summary refs log tree commit diff
path: root/sound/soc/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/Kconfig30
-rw-r--r--sound/soc/codecs/Makefile10
-rw-r--r--sound/soc/codecs/ak4613.c10
-rw-r--r--sound/soc/codecs/cs35l35.c1580
-rw-r--r--sound/soc/codecs/cs35l35.h294
-rw-r--r--sound/soc/codecs/cs4271.c2
-rw-r--r--sound/soc/codecs/cs53l30.c1
-rw-r--r--sound/soc/codecs/da7213.c13
-rw-r--r--sound/soc/codecs/dio2125.c120
-rw-r--r--sound/soc/codecs/es7134.c116
-rw-r--r--sound/soc/codecs/es8328.c51
-rw-r--r--sound/soc/codecs/hdac_hdmi.c20
-rw-r--r--sound/soc/codecs/max9867.c4
-rw-r--r--sound/soc/codecs/max98927.c841
-rw-r--r--sound/soc/codecs/max98927.h272
-rw-r--r--sound/soc/codecs/nau8540.c1224
-rw-r--r--sound/soc/codecs/nau8540.h310
-rw-r--r--sound/soc/codecs/nau8824.c1831
-rw-r--r--sound/soc/codecs/nau8824.h466
-rw-r--r--sound/soc/codecs/rt5514.c36
-rw-r--r--sound/soc/codecs/rt5645.c10
-rw-r--r--sound/soc/codecs/rt5665.c232
-rw-r--r--sound/soc/codecs/rt5665.h4
-rw-r--r--sound/soc/codecs/rt5670.c21
-rw-r--r--sound/soc/codecs/rt5677.c7
-rw-r--r--sound/soc/codecs/wm_adsp.c333
-rw-r--r--sound/soc/codecs/wm_adsp.h24
27 files changed, 6921 insertions, 941 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index e49e9da7f1f6..883ed4c8a551 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -49,6 +49,7 @@ config SND_SOC_ALL_CODECS
 	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
@@ -69,9 +70,11 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_DA7219 if I2C
 	select SND_SOC_DA732X if I2C
 	select SND_SOC_DA9055 if I2C
+	select SND_SOC_DIO2125
 	select SND_SOC_DMIC
 	select SND_SOC_ES8328_SPI if SPI_MASTER
 	select SND_SOC_ES8328_I2C if I2C
+	select SND_SOC_ES7134
 	select SND_SOC_GTM601
 	select SND_SOC_HDAC_HDMI
 	select SND_SOC_ICS43432
@@ -89,6 +92,7 @@ config SND_SOC_ALL_CODECS
 	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_MAX9850 if I2C
 	select SND_SOC_MAX9860 if I2C
 	select SND_SOC_MAX9768 if I2C
@@ -97,6 +101,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_ML26124 if I2C
 	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
@@ -303,12 +308,14 @@ config SND_SOC_ADAU1761
 	select SND_SOC_ADAU17X1
 
 config SND_SOC_ADAU1761_I2C
-	tristate
+	tristate "Analog Devices AU1761 CODEC - I2C"
+	depends on I2C
 	select SND_SOC_ADAU1761
 	select REGMAP_I2C
 
 config SND_SOC_ADAU1761_SPI
-	tristate
+	tristate "Analog Devices AU1761 CODEC - SPI"
+	depends on SPI
 	select SND_SOC_ADAU1761
 	select REGMAP_SPI
 
@@ -408,6 +415,10 @@ 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
@@ -516,6 +527,10 @@ config SND_SOC_DA732X
 config SND_SOC_DA9055
 	tristate
 
+config SND_SOC_DIO2125
+	tristate "Dioo DIO2125 Amplifier"
+	select GPIOLIB
+
 config SND_SOC_DMIC
 	tristate
 
@@ -525,6 +540,9 @@ config SND_SOC_HDMI_CODEC
 	select SND_PCM_IEC958
 	select HDMI
 
+config SND_SOC_ES7134
+       tristate "Everest Semi ES7134 CODEC"
+
 config SND_SOC_ES8328
 	tristate
 
@@ -588,6 +606,10 @@ config SND_SOC_MAX98925
 config SND_SOC_MAX98926
 	tristate
 
+config SND_SOC_MAX98927
+	tristate "Maxim Integrated MAX98927 Speaker Amplifier"
+	depends on I2C
+
 config SND_SOC_MAX9850
 	tristate
 
@@ -1116,6 +1138,10 @@ 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
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 1796cb987e71..28a63fdaf982 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -39,6 +39,7 @@ 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
@@ -63,6 +64,7 @@ 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-es8328-objs := es8328.o
 snd-soc-es8328-i2c-objs := es8328-i2c.o
 snd-soc-es8328-spi-objs := es8328-spi.o
@@ -84,6 +86,7 @@ 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-max9850-objs := max9850.o
 snd-soc-max9860-objs := max9860.o
 snd-soc-mc13783-objs := mc13783.o
@@ -92,6 +95,7 @@ snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
 snd-soc-msm8916-digital-objs := msm8916-wcd-digital.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
@@ -221,6 +225,7 @@ snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
 snd-soc-wm-hubs-objs := wm_hubs.o
 # Amp
+snd-soc-dio2125-objs := dio2125.o
 snd-soc-max9877-objs := max9877.o
 snd-soc-max98504-objs := max98504.o
 snd-soc-tpa6130a2-objs := tpa6130a2.o
@@ -269,6 +274,7 @@ obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.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
@@ -293,6 +299,7 @@ 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_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
@@ -313,6 +320,7 @@ obj-$(CONFIG_SND_SOC_MAX98357A)	+= snd-soc-max98357a.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_MAX9850)	+= snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MAX9860)	+= snd-soc-max9860.o
 obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o
@@ -321,6 +329,7 @@ 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_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
@@ -448,6 +457,7 @@ obj-$(CONFIG_SND_SOC_WM_ADSP)	+= snd-soc-wm-adsp.o
 obj-$(CONFIG_SND_SOC_WM_HUBS)	+= snd-soc-wm-hubs.o
 
 # Amp
+obj-$(CONFIG_SND_SOC_DIO2125)	+= snd-soc-dio2125.o
 obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
 obj-$(CONFIG_SND_SOC_MAX98504)	+= snd-soc-max98504.o
 obj-$(CONFIG_SND_SOC_TPA6130A2)	+= snd-soc-tpa6130a2.o
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index e819dd8c82fd..b2dfddead227 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -75,6 +75,12 @@
 #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;
@@ -365,8 +371,8 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
 	snd_soc_update_bits(codec, CTRL1, FMT_MASK, fmt_ctrl);
 	snd_soc_update_bits(codec, CTRL2, DFS_MASK, ctrl2);
 
-	snd_soc_write(codec, ICTRL, priv->ic);
-	snd_soc_write(codec, OCTRL, priv->oc);
+	snd_soc_update_bits(codec, ICTRL, ICTRL_MASK, priv->ic);
+	snd_soc_update_bits(codec, OCTRL, OCTRL_MASK, priv->oc);
 
 hw_params_end:
 	if (ret < 0)
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
new file mode 100644
index 000000000000..f8aef5869b03
--- /dev/null
+++ b/sound/soc/codecs/cs35l35.c
@@ -0,0 +1,1580 @@
+/*
+ * 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 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_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+	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(codec->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_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+	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(codec->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_codec *codec = codec_dai->codec;
+	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+
+	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_codec *codec = dai->codec;
+	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+	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(codec->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(codec->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(codec->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(codec->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(codec->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(codec->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(codec->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(codec->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_codec *codec = dai->codec;
+	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+
+	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_codec *codec = dai->codec;
+	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+
+	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_codec *codec = dai->codec;
+	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+
+	/* 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_codec_set_sysclk(struct snd_soc_codec *codec,
+				int clk_id, int source, unsigned int freq,
+				int dir)
+{
+	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+	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(codec->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(codec->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(codec->dev, "Failed to set sysclk %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int cs35l35_codec_probe(struct snd_soc_codec *codec)
+{
+	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+	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);
+
+	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_codec_controls(codec, 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 struct snd_soc_codec_driver soc_codec_dev_cs35l35 = {
+	.probe = cs35l35_codec_probe,
+	.set_sysclk = cs35l35_codec_set_sysclk,
+	.component_driver = {
+		.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),
+	},
+
+};
+
+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,
+};
+
+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;
+	}
+
+	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;
+		}
+	}
+
+	gpiod_set_value_cansleep(cs35l35->reset_gpio, 1);
+
+	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 =  snd_soc_register_codec(dev, &soc_codec_dev_cs35l35, cs35l35_dai,
+				      ARRAY_SIZE(cs35l35_dai));
+	if (ret < 0) {
+		dev_err(dev, "Failed to register codec: %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 int cs35l35_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+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,
+	.remove = cs35l35_i2c_remove,
+};
+
+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 000000000000..5a6e43a87c4d
--- /dev/null
+++ b/sound/soc/codecs/cs35l35.h
@@ -0,0 +1,294 @@
+/*
+ * 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
+
+/* 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/cs4271.c b/sound/soc/codecs/cs4271.c
index 8c0f3b89b5bc..e78b5f055f25 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -498,7 +498,7 @@ static int cs4271_reset(struct snd_soc_codec *codec)
 	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 
 	if (gpio_is_valid(cs4271->gpio_nreset)) {
-		gpio_set_value(cs4271->gpio_nreset, 0);
+		gpio_direction_output(cs4271->gpio_nreset, 0);
 		mdelay(1);
 		gpio_set_value(cs4271->gpio_nreset, 1);
 		mdelay(1);
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index cb47fb595ff4..1e0d5973b758 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -1130,6 +1130,7 @@ 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,
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 12da55882c06..6dd7578f0bb8 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -12,6 +12,7 @@
  * option) any later version.
  */
 
+#include <linux/acpi.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
@@ -1528,12 +1529,23 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
 	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_codec *codec, u32 val)
@@ -1844,6 +1856,7 @@ 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,
 	.remove		= da7213_remove,
diff --git a/sound/soc/codecs/dio2125.c b/sound/soc/codecs/dio2125.c
new file mode 100644
index 000000000000..09451cd44f9b
--- /dev/null
+++ b/sound/soc/codecs/dio2125.c
@@ -0,0 +1,120 @@
+/*
+ * 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 "dio2125"
+
+struct dio2125 {
+	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 dio2125 *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 dio2125_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 dio2125_dapm_routes[] = {
+	{ "DRV", NULL, "INL" },
+	{ "DRV", NULL, "INR" },
+	{ "OUTL", NULL, "DRV" },
+	{ "OUTR", NULL, "DRV" },
+};
+
+static const struct snd_soc_component_driver dio2125_component_driver = {
+	.dapm_widgets		= dio2125_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(dio2125_dapm_widgets),
+	.dapm_routes		= dio2125_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(dio2125_dapm_routes),
+};
+
+static int dio2125_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct dio2125 *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, &dio2125_component_driver,
+					       NULL, 0);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id dio2125_ids[] = {
+	{ .compatible = "dioo,dio2125", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, dio2125_ids);
+#endif
+
+static struct platform_driver dio2125_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = of_match_ptr(dio2125_ids),
+	},
+	.probe = dio2125_probe,
+};
+
+module_platform_driver(dio2125_driver);
+
+MODULE_DESCRIPTION("ASoC DIO2125 output driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es7134.c b/sound/soc/codecs/es7134.c
new file mode 100644
index 000000000000..25ede825d349
--- /dev/null
+++ b/sound/soc/codecs/es7134.c
@@ -0,0 +1,116 @@
+/*
+ * 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/module.h>
+#include <sound/soc.h>
+
+/*
+ * The everest 7134 is a very simple DA converter with no register
+ */
+
+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 const struct snd_soc_dai_ops es7134_dai_ops = {
+	.set_fmt	= es7134_set_fmt,
+};
+
+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_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 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),
+};
+
+static const struct snd_soc_dapm_route es7134_dapm_routes[] = {
+	{ "AOUTL", NULL, "DAC" },
+	{ "AOUTR", NULL, "DAC" },
+};
+
+static struct snd_soc_codec_driver es7134_codec_driver = {
+	.component_driver = {
+		.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),
+	},
+};
+
+static int es7134_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_codec(&pdev->dev,
+				      &es7134_codec_driver,
+				      &es7134_dai, 1);
+}
+
+static int es7134_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id es7134_ids[] = {
+	{ .compatible = "everest,es7134", },
+	{ .compatible = "everest,es7144", },
+	{ }
+};
+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,
+	.remove = es7134_remove,
+};
+
+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/es8328.c b/sound/soc/codecs/es8328.c
index 3f84fbd071e2..ed7cc42d1ee2 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -69,14 +69,10 @@ static const char * const supply_names[ES8328_SUPPLY_NUM] = {
 	"HPVDD",
 };
 
-#define ES8328_RATES (SNDRV_PCM_RATE_96000 | \
-		SNDRV_PCM_RATE_48000 | \
-		SNDRV_PCM_RATE_44100 | \
-		SNDRV_PCM_RATE_32000 | \
-		SNDRV_PCM_RATE_22050 | \
-		SNDRV_PCM_RATE_16000 | \
-		SNDRV_PCM_RATE_11025 | \
-		SNDRV_PCM_RATE_8000)
+#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 | \
@@ -91,6 +87,7 @@ struct es8328_priv {
 	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];
 };
 
@@ -469,7 +466,7 @@ static int es8328_startup(struct snd_pcm_substream *substream,
 	struct snd_soc_codec *codec = dai->codec;
 	struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
 
-	if (es8328->sysclk_constraints)
+	if (es8328->master && es8328->sysclk_constraints)
 		snd_pcm_hw_constraint_list(substream->runtime, 0,
 				SNDRV_PCM_HW_PARAM_RATE,
 				es8328->sysclk_constraints);
@@ -488,27 +485,34 @@ static int es8328_hw_params(struct snd_pcm_substream *substream,
 	int wl;
 	int ratio;
 
-	if (!es8328->sysclk_constraints) {
-		dev_err(codec->dev, "No MCLK configured\n");
-		return -EINVAL;
-	}
-
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		reg = ES8328_DACCONTROL2;
 	else
 		reg = ES8328_ADCCONTROL5;
 
-	for (i = 0; i < es8328->sysclk_constraints->count; i++)
-		if (es8328->sysclk_constraints->list[i] == params_rate(params))
-			break;
+	if (es8328->master) {
+		if (!es8328->sysclk_constraints) {
+			dev_err(codec->dev, "No MCLK configured\n");
+			return -EINVAL;
+		}
 
-	if (i == es8328->sysclk_constraints->count) {
-		dev_err(codec->dev, "LRCLK %d unsupported with current clock\n",
-			params_rate(params));
-		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(codec->dev,
+				"LRCLK %d unsupported with current clock\n",
+				params_rate(params));
+			return -EINVAL;
+		}
+		ratio = es8328->mclk_ratios[i];
+	} else {
+		ratio = 0;
+		es8328->mclkdiv2 = 0;
 	}
 
-	ratio = es8328->mclk_ratios[i];
 	snd_soc_update_bits(codec, ES8328_MASTERMODE,
 			ES8328_MASTERMODE_MCLKDIV2,
 			es8328->mclkdiv2 ? ES8328_MASTERMODE_MCLKDIV2 : 0);
@@ -586,6 +590,7 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
+	struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
 	u8 dac_mode = 0;
 	u8 adc_mode = 0;
 
@@ -595,11 +600,13 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		snd_soc_update_bits(codec, ES8328_MASTERMODE,
 				    ES8328_MASTERMODE_MSC,
 				    ES8328_MASTERMODE_MSC);
+		es8328->master = true;
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
 		/* Slave serial port mode */
 		snd_soc_update_bits(codec, ES8328_MASTERMODE,
 				    ES8328_MASTERMODE_MSC, 0);
+		es8328->master = false;
 		break;
 	default:
 		return -EINVAL;
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 78fca8acd3ec..bc2e74ff3b2d 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -469,7 +469,7 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
 
 	format = snd_hdac_calc_stream_format(params_rate(hparams),
 			params_channels(hparams), params_format(hparams),
-			24, 0);
+			dai->driver->playback.sig_bits, 0);
 
 	pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
 	if (!pcm)
@@ -1419,8 +1419,8 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdac,
 		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++;
 	}
 
@@ -1534,21 +1534,20 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
 			pin->mst_capable = false;
 			/* if not MST, default is port[0] */
 			hport = &pin->ports[0];
-			goto out;
 		} else {
 			for (i = 0; i < pin->num_ports; i++) {
 				pin->mst_capable = true;
 				if (pin->ports[i].id == pipe) {
 					hport = &pin->ports[i];
-					goto out;
+					break;
 				}
 			}
 		}
+
+		if (hport)
+			hdac_hdmi_present_sense(pin, hport);
 	}
 
-out:
-	if (pin && hport)
-		hdac_hdmi_present_sense(pin, hport);
 }
 
 static struct i915_audio_component_audio_ops aops = {
@@ -1998,7 +1997,7 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
 	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;
+	struct hdac_hdmi_port *port, *port_next;
 	int i;
 
 	snd_soc_unregister_codec(&edev->hdac.dev);
@@ -2008,8 +2007,9 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
 		if (list_empty(&pcm->port_list))
 			continue;
 
-		list_for_each_entry(port, &pcm->port_list, head)
-			port = NULL;
+		list_for_each_entry_safe(port, port_next,
+					&pcm->port_list, head)
+			list_del(&port->head);
 
 		list_del(&pcm->head);
 		kfree(pcm);
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
index 6cdf15ab46de..0247edc9c84e 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -516,13 +516,13 @@ 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(i2c, max9867_i2c_id);
+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)
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
new file mode 100644
index 000000000000..b5ee29499e16
--- /dev/null
+++ b/sound/soc/codecs/max98927.c
@@ -0,0 +1,841 @@
+/*
+ * max98927.c  --  MAX98927 ALSA Soc Audio driver
+ *
+ * Copyright (C) 2016 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,  0x00},
+	{MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH,  0x00},
+	{MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS,  0x00},
+	{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,  0x01},
+	{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,  0x00},
+	{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_codec *codec = codec_dai->codec;
+	struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+	unsigned int mode = 0;
+	unsigned int format = 0;
+	unsigned int invert = 0;
+
+	dev_dbg(codec->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(codec->dev, "DAI clock mode unsupported");
+		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(codec->dev, "DAI invert mode unsupported");
+		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:
+		max98927->iface |= SND_SOC_DAIFMT_I2S;
+		format = MAX98927_PCM_FORMAT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		max98927->iface |= SND_SOC_DAIFMT_LEFT_J;
+		format = MAX98927_PCM_FORMAT_LJ;
+		break;
+	case SND_SOC_DAIFMT_PDM:
+		max98927->iface |= SND_SOC_DAIFMT_PDM;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* pcm channel configuration */
+	if (max98927->iface & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
+		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);
+
+	} else
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R0018_PCM_RX_EN_A,
+			MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0);
+
+	/* pdm channel configuration */
+	if (max98927->iface & SND_SOC_DAIFMT_PDM) {
+		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);
+	} else
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R0035_PDM_RX_CTRL,
+			MAX98927_PDM_RX_EN_MASK, 0);
+	return 0;
+}
+
+/* codec MCLK rate in master mode */
+static const int rate_table[] = {
+	5644800, 6000000, 6144000, 6500000,
+	9600000, 11289600, 12000000, 12288000,
+	13000000, 19200000,
+};
+
+static int max98927_set_clock(struct max98927_priv *max98927,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_codec *codec = max98927->codec;
+	/* 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(codec->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);
+	}
+
+	switch (blr_clk_ratio) {
+	case 32:
+		value = 2;
+		break;
+	case 48:
+		value = 3;
+		break;
+	case 64:
+		value = 4;
+		break;
+	default:
+		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_codec *codec = dai->codec;
+	struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+	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(codec->dev, "format unsupported %d",
+			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(codec->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(codec->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;
+}
+
+#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_codec *codec = dai->codec;
+	struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+
+	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,
+};
+
+static int max98927_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R003A_AMP_EN,
+			MAX98927_AMP_EN_MASK, 1);
+		/* enable VMON and IMON */
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R003E_MEAS_EN,
+			MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN,
+			MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN);
+		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);
+		/* disable VMON and IMON */
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R003E_MEAS_EN,
+			MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN, 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_soc_dapm_widget max98927_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+	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"),
+};
+
+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:
+		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[] = {
+	{"Amp Enable", NULL, "DAI_OUT"},
+	{"DAI Sel Mux", "Left", "Amp Enable"},
+	{"DAI Sel Mux", "Right", "Amp Enable"},
+	{"DAI Sel Mux", "LeftRight", "Amp Enable"},
+	{"BE_OUT", NULL, "DAI Sel Mux"},
+};
+
+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_codec *codec)
+{
+	struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+
+	max98927->codec = codec;
+	codec->control_data = max98927->regmap;
+	codec->cache_bypass = 1;
+
+	/* 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;
+}
+
+static const struct snd_soc_codec_driver soc_codec_dev_max98927 = {
+	.probe = max98927_probe,
+	.component_driver = {
+		.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),
+	},
+};
+
+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;
+
+	if (!of_property_read_u32(i2c->dev.of_node,
+		"vmon-slot-no", &value))
+		max98927->v_l_slot = value & 0xF;
+	else
+		max98927->v_l_slot = 0;
+	if (!of_property_read_u32(i2c->dev.of_node,
+		"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 = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98927,
+		max98927_dai, ARRAY_SIZE(max98927_dai));
+	if (ret < 0)
+		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+
+	return ret;
+}
+
+static int max98927_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+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 = NULL,
+	},
+	.probe  = max98927_i2c_probe,
+	.remove = max98927_i2c_remove,
+	.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 000000000000..ece6a608cbe1
--- /dev/null
+++ b/sound/soc/codecs/max98927.h
@@ -0,0 +1,272 @@
+/*
+ * max98927.h  --  MAX98927 ALSA Soc Audio driver
+ *
+ * Copyright 2013-15 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_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_codec *codec;
+	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;
+};
+#endif
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c
index 9e8f0f4aa51a..c8bcb1db966d 100644
--- a/sound/soc/codecs/nau8540.c
+++ b/sound/soc/codecs/nau8540.c
@@ -39,147 +39,147 @@
 
 /* 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 },
+	{ 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 },
+	{ 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 },
+	{ 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 */
+	{ 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},
+	{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;
-       }
+	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;
-       }
+	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;
-       }
+	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;
+	}
 }
 
 
@@ -187,255 +187,255 @@ 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),
+	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"
+	"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);
+	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);
+	SOC_DAPM_ENUM("Digital CH4 Select", digital_ch4_enum);
 
 static SOC_ENUM_SINGLE_DECL(
-       digital_ch3_enum, NAU8540_REG_DIGITAL_MUX, 4, adc_channel);
+	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);
+	SOC_DAPM_ENUM("Digital CH3 Select", digital_ch3_enum);
 
 static SOC_ENUM_SINGLE_DECL(
-       digital_ch2_enum, NAU8540_REG_DIGITAL_MUX, 2, adc_channel);
+	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);
+	SOC_DAPM_ENUM("Digital CH2 Select", digital_ch2_enum);
 
 static SOC_ENUM_SINGLE_DECL(
-       digital_ch1_enum, NAU8540_REG_DIGITAL_MUX, 0, adc_channel);
+	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);
+	SOC_DAPM_ENUM("Digital CH1 Select", digital_ch1_enum);
 
 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("ADC1", NULL,
-               NAU8540_REG_POWER_MANAGEMENT, 0, 0),
-       SND_SOC_DAPM_ADC("ADC2", NULL,
-               NAU8540_REG_POWER_MANAGEMENT, 1, 0),
-       SND_SOC_DAPM_ADC("ADC3", NULL,
-               NAU8540_REG_POWER_MANAGEMENT, 2, 0),
-       SND_SOC_DAPM_ADC("ADC4", NULL,
-               NAU8540_REG_POWER_MANAGEMENT, 3, 0),
-
-       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("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0),
+	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("ADC1", NULL,
+		NAU8540_REG_POWER_MANAGEMENT, 0, 0),
+	SND_SOC_DAPM_ADC("ADC2", NULL,
+		NAU8540_REG_POWER_MANAGEMENT, 1, 0),
+	SND_SOC_DAPM_ADC("ADC3", NULL,
+		NAU8540_REG_POWER_MANAGEMENT, 2, 0),
+	SND_SOC_DAPM_ADC("ADC4", NULL,
+		NAU8540_REG_POWER_MANAGEMENT, 3, 0),
+
+	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("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0),
 };
 
 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"},
+	{"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)
 {
-       int osrate;
+	int osrate;
 
-       if (osr >= ARRAY_SIZE(osr_adc_sel))
-               return -EINVAL;
-       osrate = osr_adc_sel[osr].osr;
+	if (osr >= ARRAY_SIZE(osr_adc_sel))
+		return -EINVAL;
+	osrate = osr_adc_sel[osr].osr;
 
-       if (rate * osr > CLK_ADC_MAX) {
-               dev_err(nau8540->dev, "exceed the maximum frequency of CLK_ADC\n");
-               return -EINVAL;
-       }
+	if (rate * osr > CLK_ADC_MAX) {
+		dev_err(nau8540->dev, "exceed the maximum frequency of CLK_ADC\n");
+		return -EINVAL;
+	}
 
-       return 0;
+	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_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-       struct snd_soc_codec *codec = dai->codec;
-       struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
-       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;
+	struct snd_soc_codec *codec = dai->codec;
+	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	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_codec *codec = dai->codec;
-       struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
-       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;
+	struct snd_soc_codec *codec = dai->codec;
+	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	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;
 }
 
 /**
@@ -451,55 +451,55 @@ static int nau8540_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
  * 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)
+	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
-       struct snd_soc_codec *codec = dai->codec;
-       struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
-       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;
+	struct snd_soc_codec *codec = dai->codec;
+	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	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,
+	.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)
+	 | 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,
+	.name = "nau8540-hifi",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 4,
+		.rates = NAU8540_RATES,
+		.formats = NAU8540_FORMATS,
+	},
+	.ops = &nau8540_dai_ops,
 };
 
 /**
@@ -513,320 +513,320 @@ static struct snd_soc_dai_driver nau8540_dai = {
  * 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)
+	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;
+	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)
+	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, fll_param->ratio);
-       /* 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_SDM_EN);
-       } 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, 0);
-       }
+	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, fll_param->ratio);
+	/* 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_SDM_EN);
+	} 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, 0);
+	}
 }
 
 /* freq_out must be 256*Fs in order to achieve the best performance */
 static int nau8540_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
-               unsigned int freq_in, unsigned int freq_out)
+		unsigned int freq_in, unsigned int freq_out)
 {
-       struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
-       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_FLL_CLK_SRC_MCLK);
-               break;
-
-       case NAU8540_CLK_FLL_BLK:
-               regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
-                       NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_BLK);
-               break;
-
-       case NAU8540_CLK_FLL_FS:
-               regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
-                       NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_FS);
-               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;
+	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	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_FLL_CLK_SRC_MCLK);
+		break;
+
+	case NAU8540_CLK_FLL_BLK:
+		regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
+			NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_BLK);
+		break;
+
+	case NAU8540_CLK_FLL_FS:
+		regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
+			NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_FS);
+		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_codec *codec,
-       int clk_id, int source, unsigned int freq, int dir)
+	int clk_id, int source, unsigned int freq, int dir)
 {
-       struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
-
-       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;
+	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+
+	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);
+	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 */
-       regmap_update_bits(regmap, NAU8540_REG_ADC_SAMPLE_RATE,
-               NAU8540_ADC_OSR_MASK, NAU8540_ADC_OSR_64);
+	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 */
+	regmap_update_bits(regmap, NAU8540_REG_ADC_SAMPLE_RATE,
+		NAU8540_ADC_OSR_MASK, NAU8540_ADC_OSR_64);
 }
 
 static int __maybe_unused nau8540_suspend(struct snd_soc_codec *codec)
 {
-       struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
 
-       regcache_cache_only(nau8540->regmap, true);
-       regcache_mark_dirty(nau8540->regmap);
+	regcache_cache_only(nau8540->regmap, true);
+	regcache_mark_dirty(nau8540->regmap);
 
-       return 0;
+	return 0;
 }
 
 static int __maybe_unused nau8540_resume(struct snd_soc_codec *codec)
 {
-       struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
 
-       regcache_cache_only(nau8540->regmap, false);
-       regcache_sync(nau8540->regmap);
+	regcache_cache_only(nau8540->regmap, false);
+	regcache_sync(nau8540->regmap);
 
-       return 0;
+	return 0;
 }
 
 static struct snd_soc_codec_driver nau8540_codec_driver = {
-       .set_sysclk = nau8540_set_sysclk,
-       .set_pll = nau8540_set_pll,
-       .suspend = nau8540_suspend,
-       .resume = nau8540_resume,
-       .suspend_bias_off = true,
-
-       .component_driver = {
-               .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),
-       },
+	.set_sysclk = nau8540_set_sysclk,
+	.set_pll = nau8540_set_pll,
+	.suspend = nau8540_suspend,
+	.resume = nau8540_resume,
+	.suspend_bias_off = true,
+
+	.component_driver = {
+		.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),
+	},
 };
 
 static const struct regmap_config nau8540_regmap_config = {
-       .val_bits = 16,
-       .reg_bits = 16,
+	.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,
+	.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),
+	.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)
+	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 snd_soc_register_codec(dev,
-               &nau8540_codec_driver, &nau8540_dai, 1);
+	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 snd_soc_register_codec(dev,
+		&nau8540_codec_driver, &nau8540_dai, 1);
 }
 
 static int nau8540_i2c_remove(struct i2c_client *client)
 {
-       snd_soc_unregister_codec(&client->dev);
-       return 0;
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
 }
 
 
 static const struct i2c_device_id nau8540_i2c_ids[] = {
-       { "nau8540", 0 },
-       { }
+	{ "nau8540", 0 },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, nau8540_i2c_ids);
 
 #ifdef CONFIG_OF
 static const struct of_device_id nau8540_of_ids[] = {
-       { .compatible = "nuvoton,nau8540", },
-       {}
+	{ .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,
-       .remove = nau8540_i2c_remove,
-       .id_table = nau8540_i2c_ids,
+	.driver = {
+		.name = "nau8540",
+		.of_match_table = of_match_ptr(nau8540_of_ids),
+	},
+	.probe = nau8540_i2c_probe,
+	.remove = nau8540_i2c_remove,
+	.id_table = nau8540_i2c_ids,
 };
 module_i2c_driver(nau8540_i2c_driver);
 
diff --git a/sound/soc/codecs/nau8540.h b/sound/soc/codecs/nau8540.h
index d06e65188cd5..5db5b224944d 100644
--- a/sound/soc/codecs/nau8540.h
+++ b/sound/soc/codecs/nau8540.h
@@ -12,211 +12,211 @@
 #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
+#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
+#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)
+#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
+#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_FLL_RATIO_MASK 0x7f
+#define NAU8540_FLL_RATIO_MASK	0x7f
 
 /* FLL3 (0x06) */
-#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
+#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)
+#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)
+#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_DCO_EN			(0x1 << 15)
+#define NAU8540_SDM_EN			(0x1 << 14)
 
 /* 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
+#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_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
+#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_OE            (0x1 << 11)
-#define NAU8540_I2S_TSLOT_L_MASK       0x3ff
+#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
+#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_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
+#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)
+#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)
+#define NAU8540_PU_PRE			(0x1 << 8)
 
 /* REFERENCE (0x68) */
-#define NAU8540_PRECHARGE_DIS          (0x1 << 13)
-#define NAU8540_GLOBAL_BIAS_EN (0x1 << 12)
+#define NAU8540_PRECHARGE_DIS		(0x1 << 13)
+#define NAU8540_GLOBAL_BIAS_EN	(0x1 << 12)
 
 
 /* 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,
+	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 device *dev;
+	struct regmap *regmap;
 };
 
 struct nau8540_fll {
-       int mclk_src;
-       int ratio;
-       int fll_frac;
-       int fll_int;
-       int clk_ref_div;
+	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;
+	unsigned int param;
+	unsigned int val;
 };
 
 /* over sampling rate */
 struct nau8540_osr_attr {
-       unsigned int osr;
-       unsigned int clk_src;
+	unsigned int osr;
+	unsigned int clk_src;
 };
 
 
-#endif /* __NAU8540_H__ */
+#endif	/* __NAU8540_H__ */
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
new file mode 100644
index 000000000000..cca974d26136
--- /dev/null
+++ b/sound/soc/codecs/nau8824.c
@@ -0,0 +1,1831 @@
+/*
+ * 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 124000000
+#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 semaphone timeout\n");
+	} else {
+		ret = down_interruptible(&nau8824->jd_sem);
+		if (ret < 0)
+			dev_warn(nau8824->dev, "Acquire semaphone 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),
+};
+
+static int nau8824_output_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+	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_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+	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_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+	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_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		/* 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);
+		}
+	}
+	return 0;
+}
+
+static int dmic_clock_control(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *k, int  event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	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_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 */
+	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);
+
+	nau8824_sema_release(nau8824);
+}
+
+static void nau8824_setup_auto_irq(struct nau8824 *nau8824)
+{
+	struct regmap *regmap = nau8824->regmap;
+
+	/* Enable jack ejection, short key press and release 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 | NAU8824_IRQ_KEY_RELEASE_DIS |
+		NAU8824_IRQ_KEY_SHORT_PRESS_DIS, 0);
+	/* Enable internal VCO needed for interruptions */
+	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_codec *codec = dai->codec;
+	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	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_codec *codec = dai->codec;
+	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	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_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 = 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 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_codec *codec, int pll_id, int source,
+		unsigned int freq_in, unsigned int freq_out)
+{
+	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	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_codec *codec,
+	int clk_id, int source, unsigned int freq, int dir)
+{
+	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+	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_codec *codec,
+	enum snd_soc_bias_level level)
+{
+	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_codec_get_bias_level(codec) == 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_codec_probe(struct snd_soc_codec *codec)
+{
+	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+	nau8824->dapm = dapm;
+
+	return 0;
+}
+
+static int __maybe_unused nau8824_suspend(struct snd_soc_codec *codec)
+{
+	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+	if (nau8824->irq) {
+		disable_irq(nau8824->irq);
+		snd_soc_codec_force_bias_level(codec, 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_codec *codec)
+{
+	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+	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 struct snd_soc_codec_driver nau8824_codec_driver = {
+	.probe = nau8824_codec_probe,
+	.set_sysclk = nau8824_set_sysclk,
+	.set_pll = nau8824_set_pll,
+	.set_bias_level = nau8824_set_bias_level,
+	.suspend = nau8824_suspend,
+	.resume = nau8824_resume,
+	.suspend_bias_off = true,
+
+	.component_driver = {
+		.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),
+	},
+};
+
+static const struct snd_soc_dai_ops nau8824_dai_ops = {
+	.hw_params = nau8824_hw_params,
+	.set_fmt = nau8824_set_fmt,
+};
+
+#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_codec *codec,
+	struct snd_soc_jack *jack)
+{
+	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	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 snd_soc_register_codec(dev,
+		&nau8824_codec_driver, &nau8824_dai, 1);
+}
+
+
+static int nau8824_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+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,
+	.remove = nau8824_i2c_remove,
+	.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 000000000000..87ac9a382aed
--- /dev/null
+++ b/sound/soc/codecs/nau8824.h
@@ -0,0 +1,466 @@
+/*
+ * 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
+
+/* 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_codec *codec,
+	struct snd_soc_jack *jack);
+
+#endif				/* _NAU8824_H */
+
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index b281a46d769d..f91221b1ddf0 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -1084,13 +1084,28 @@ static int rt5514_parse_dt(struct rt5514_priv *rt5514, struct device *dev)
 	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;
+	unsigned int val = ~0;
 
 	rt5514 = devm_kzalloc(&i2c->dev, sizeof(struct rt5514_priv),
 				GFP_KERNEL);
@@ -1120,8 +1135,16 @@ static int rt5514_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	regmap_read(rt5514->regmap, RT5514_VENDOR_ID2, &val);
-	if (val != RT5514_DEVICE_ID) {
+	/*
+	 * 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;
@@ -1149,10 +1172,15 @@ static int rt5514_i2c_remove(struct i2c_client *i2c)
 	return 0;
 }
 
-struct i2c_driver rt5514_i2c_driver = {
+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",
 		.of_match_table = of_match_ptr(rt5514_of_match),
+		.pm = &rt5514_i2_pm_ops,
 	},
 	.probe = rt5514_i2c_probe,
 	.remove   = rt5514_i2c_remove,
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index e149f3ce5401..87844a45886a 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3542,6 +3542,15 @@ static const struct i2c_device_id rt5645_i2c_id[] = {
 };
 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 },
@@ -3912,6 +3921,7 @@ static void rt5645_i2c_shutdown(struct i2c_client *i2c)
 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,
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index 324461e985b3..8cd22307f5b6 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -1139,7 +1139,8 @@ static void rt5665_enable_push_button_irq(struct snd_soc_codec *codec,
 	bool enable)
 {
 	if (enable) {
-		snd_soc_write(codec, RT5665_4BTN_IL_CMD_1, 0x000b);
+		snd_soc_write(codec, RT5665_4BTN_IL_CMD_1, 0x0003);
+		snd_soc_update_bits(codec, RT5665_SAR_IL_CMD_9, 0x1, 0x1);
 		snd_soc_write(codec, RT5665_IL_CMD_1, 0x0048);
 		snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2,
 				RT5665_4BTN_IL_MASK | RT5665_4BTN_IL_RST_MASK,
@@ -1192,10 +1193,13 @@ static int rt5665_headset_detect(struct snd_soc_codec *codec, int jack_insert)
 		}
 
 		regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1,
-			0x180, 0x180);
+			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_read(rt5665->codec,
 			RT5665_SAR_IL_CMD_4) & 0x7ff;
 
@@ -1241,7 +1245,7 @@ static irqreturn_t rt5665_irq(int irq, void *data)
 static void rt5665_jd_check_handler(struct work_struct *work)
 {
 	struct rt5665_priv *rt5665 = container_of(work, struct rt5665_priv,
-		calibrate_work.work);
+		jd_check_work.work);
 
 	if (snd_soc_read(rt5665->codec, RT5665_AJD1_CTRL) & 0x0010) {
 		/* jack out */
@@ -1256,8 +1260,8 @@ static void rt5665_jd_check_handler(struct work_struct *work)
 	}
 }
 
-int rt5665_set_jack_detect(struct snd_soc_codec *codec,
-	struct snd_soc_jack *hs_jack)
+static int rt5665_set_jack_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *hs_jack, void *data)
 {
 	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
 
@@ -1284,7 +1288,6 @@ int rt5665_set_jack_detect(struct snd_soc_codec *codec,
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(rt5665_set_jack_detect);
 
 static void rt5665_jack_detect_handler(struct work_struct *work)
 {
@@ -2252,7 +2255,7 @@ static const char * const rt5665_if2_1_adc_in_src[] = {
 
 static const SOC_ENUM_SINGLE_DECL(
 	rt5665_if2_1_adc_in_enum, RT5665_DIG_INF2_DATA,
-	RT5665_IF3_ADC_IN_SFT, rt5665_if2_1_adc_in_src);
+	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);
@@ -2600,6 +2603,55 @@ static int rt5655_set_verf(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
+static int rt5665_i2s_pin_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	unsigned int val1, val2, mask1, 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:
+		snd_soc_update_bits(codec, RT5665_GPIO_CTRL_1, mask1, val1);
+		if (mask2)
+			snd_soc_update_bits(codec, RT5665_GPIO_CTRL_2,
+					    mask2, val2);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, RT5665_GPIO_CTRL_1, mask1, 0);
+		if (mask2)
+			snd_soc_update_bits(codec, 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,
@@ -2852,11 +2904,14 @@ static const struct snd_soc_dapm_widget rt5665_dapm_widgets[] = {
 	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, NULL, 0),
+		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, NULL, 0),
+		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, NULL, 0),
+		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),
@@ -3178,6 +3233,9 @@ static const struct snd_soc_dapm_route rt5665_dapm_routes[] = {
 	{"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"},
@@ -3912,6 +3970,7 @@ static const struct snd_soc_dapm_route rt5665_dapm_routes[] = {
 	{"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"},
@@ -3959,12 +4018,68 @@ static const struct snd_soc_dapm_route rt5665_dapm_routes[] = {
 	{"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_codec *codec = dai->codec;
+	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_update_bits(codec, 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_codec *codec = dai->codec;
 	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
-	unsigned int val_len = 0, val_clk, mask_clk, val_bits = 0x0100;
+	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);
@@ -4005,6 +4120,10 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream,
 	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_update_bits(codec, RT5665_I2S1_SDP,
@@ -4012,12 +4131,14 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream,
 		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_update_bits(codec, 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_update_bits(codec, RT5665_I2S3_SDP,
@@ -4028,7 +4149,7 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, mask_clk, val_clk);
+	snd_soc_update_bits(codec, reg_clk, mask_clk, val_clk);
 	snd_soc_update_bits(codec, RT5665_STO1_DAC_SIL_DET, 0x3700, val_bits);
 
 	switch (rt5665->lrck[dai->id]) {
@@ -4121,10 +4242,9 @@ static int rt5665_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	return 0;
 }
 
-static int rt5665_set_dai_sysclk(struct snd_soc_dai *dai,
-		int clk_id, unsigned int freq, int dir)
+static int rt5665_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
+				   int source, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
 	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
 	unsigned int reg_val = 0;
 
@@ -4150,20 +4270,20 @@ static int rt5665_set_dai_sysclk(struct snd_soc_dai *dai,
 	rt5665->sysclk = freq;
 	rt5665->sysclk_src = clk_id;
 
-	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+	dev_dbg(codec->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
 
 	return 0;
 }
 
-static int rt5665_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
-			unsigned int freq_in, unsigned int freq_out)
+static int rt5665_set_codec_pll(struct snd_soc_codec *codec, int pll_id,
+				int source, unsigned int freq_in,
+				unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = dai->codec;
 	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
 	struct rl6231_pll_code pll_code;
 	int ret;
 
-	if (Source == rt5665->pll_src && freq_in == rt5665->pll_in &&
+	if (source == rt5665->pll_src && freq_in == rt5665->pll_in &&
 	    freq_out == rt5665->pll_out)
 		return 0;
 
@@ -4177,7 +4297,7 @@ static int rt5665_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
 		return 0;
 	}
 
-	switch (Source) {
+	switch (source) {
 	case RT5665_PLL1_S_MCLK:
 		snd_soc_update_bits(codec, RT5665_GLB_CLK,
 			RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_MCLK);
@@ -4195,7 +4315,7 @@ static int rt5665_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
 				RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK3);
 		break;
 	default:
-		dev_err(codec->dev, "Unknown PLL Source %d\n", Source);
+		dev_err(codec->dev, "Unknown PLL Source %d\n", source);
 		return -EINVAL;
 	}
 
@@ -4217,62 +4337,7 @@ static int rt5665_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
 
 	rt5665->pll_in = freq_in;
 	rt5665->pll_out = freq_out;
-	rt5665->pll_src = Source;
-
-	return 0;
-}
-
-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_codec *codec = dai->codec;
-	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_update_bits(codec, 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);
+	rt5665->pll_src = source;
 
 	return 0;
 }
@@ -4389,9 +4454,7 @@ static int rt5665_resume(struct snd_soc_codec *codec)
 static const struct snd_soc_dai_ops rt5665_aif_dai_ops = {
 	.hw_params = rt5665_hw_params,
 	.set_fmt = rt5665_set_dai_fmt,
-	.set_sysclk = rt5665_set_dai_sysclk,
 	.set_tdm_slot = rt5665_set_tdm_slot,
-	.set_pll = rt5665_set_dai_pll,
 	.set_bclk_ratio = rt5665_set_bclk_ratio,
 };
 
@@ -4500,7 +4563,10 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5665 = {
 		.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_codec_sysclk,
+	.set_pll = rt5665_set_codec_pll,
+	.set_jack = rt5665_set_jack_detect,
 };
 
 
@@ -4779,7 +4845,7 @@ static int rt5665_i2c_probe(struct i2c_client *i2c,
 
 	regmap_write(rt5665->regmap, RT5665_HP_LOGIC_CTRL_2, 0x0002);
 	regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1,
-		0xf000 | RT5665_VREF_POW_MASK, 0xd000 | RT5665_VREF_POW_REG);
+		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);
@@ -4798,7 +4864,7 @@ static int rt5665_i2c_probe(struct i2c_client *i2c,
 	/* 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_09);
+		RT5665_HP_DRIVER_5X | RT5665_LDO1_DVO_12);
 
 	INIT_DELAYED_WORK(&rt5665->jack_detect_work,
 				rt5665_jack_detect_handler);
diff --git a/sound/soc/codecs/rt5665.h b/sound/soc/codecs/rt5665.h
index 12f7080a0d3c..1db5c6a62a8e 100644
--- a/sound/soc/codecs/rt5665.h
+++ b/sound/soc/codecs/rt5665.h
@@ -1106,7 +1106,7 @@
 #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			(0x2 << 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)
@@ -1984,7 +1984,5 @@ enum {
 
 int rt5665_sel_asrc_clk_src(struct snd_soc_codec *codec,
 		unsigned int filter_mask, unsigned int clk_src);
-int rt5665_set_jack_detect(struct snd_soc_codec *codec,
-	struct snd_soc_jack *hs_jack);
 
 #endif /* __RT5665_H__ */
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index 17d20b99f041..e27c5a4a0a15 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -2835,6 +2835,27 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "Wyse 3040"),
 		},
 	},
+	{
+		.ident = "Lenovo Thinkpad Tablet 10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 10"),
+		},
+	},
+	{
+		.ident = "Lenovo Thinkpad Tablet 10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Tablet B"),
+		},
+	},
+	{
+		.ident = "Lenovo Thinkpad Tablet 10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Miix 2 10"),
+		},
+	},
 	{}
 };
 
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index abc802a5a479..65ac4518ad06 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -5035,6 +5035,12 @@ static const struct i2c_device_id rt5677_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
 
+static const struct of_device_id rt5677_of_match[] = {
+	{ .compatible = "realtek,rt5677", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, rt5677_of_match);
+
 static const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false };
 static const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false };
 static const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false };
@@ -5294,6 +5300,7 @@ static int rt5677_i2c_remove(struct i2c_client *i2c)
 static struct i2c_driver rt5677_i2c_driver = {
 	.driver = {
 		.name = "rt5677",
+		.of_match_table = rt5677_of_match,
 	},
 	.probe = rt5677_i2c_probe,
 	.remove   = rt5677_i2c_remove,
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index d151224ffcca..20695b691aff 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -112,17 +112,22 @@
 #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 ADSP2_STATUS1        0x4
-#define ADSP2_WDMA_CONFIG_1 0x30
-#define ADSP2_WDMA_CONFIG_2 0x31
-#define ADSP2_RDMA_CONFIG_1 0x34
-
-#define ADSP2_SCRATCH0        0x40
-#define ADSP2_SCRATCH1        0x41
-#define ADSP2_SCRATCH2        0x42
-#define ADSP2_SCRATCH3        0x43
+#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
@@ -153,6 +158,17 @@
 #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
@@ -160,6 +176,37 @@
 #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
@@ -683,6 +730,9 @@ static const struct soc_enum wm_adsp_fw_enum[] = {
 	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),
 };
 
 const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
@@ -694,6 +744,12 @@ const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
 		     wm_adsp_fw_get, wm_adsp_fw_put),
 	SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
 		     wm_adsp_fw_get, wm_adsp_fw_put),
+	SOC_ENUM_EXT("DSP5 Firmware", wm_adsp_fw_enum[4],
+		     wm_adsp_fw_get, wm_adsp_fw_put),
+	SOC_ENUM_EXT("DSP6 Firmware", wm_adsp_fw_enum[5],
+		     wm_adsp_fw_get, wm_adsp_fw_put),
+	SOC_ENUM_EXT("DSP7 Firmware", wm_adsp_fw_enum[6],
+		     wm_adsp_fw_get, wm_adsp_fw_put),
 };
 EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
 
@@ -750,6 +806,29 @@ static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
 		 be16_to_cpu(scratch[3]));
 }
 
+static void wm_adsp2v2_show_fw_status(struct wm_adsp *dsp)
+{
+	u32 scratch[2];
+	int ret;
+
+	ret = regmap_raw_read(dsp->regmap, dsp->base + ADSP2V2_SCRATCH0_1,
+			      scratch, sizeof(scratch));
+
+	if (ret) {
+		adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret);
+		return;
+	}
+
+	scratch[0] = be32_to_cpu(scratch[0]);
+	scratch[1] = be32_to_cpu(scratch[1]);
+
+	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);
@@ -899,7 +978,10 @@ static int wm_coeff_put(struct snd_kcontrol *kctl,
 
 	mutex_lock(&ctl->dsp->pwr_lock);
 
-	memcpy(ctl->cache, p, ctl->len);
+	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)
@@ -926,6 +1008,8 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
 		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);
@@ -947,7 +1031,7 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
 
 	mutex_lock(&ctl->dsp->pwr_lock);
 
-	if (ctl->enabled)
+	if (ctl->enabled && ctl->dsp->running)
 		ret = wm_coeff_write_acked_control(ctl, val);
 	else
 		ret = -EPERM;
@@ -2430,10 +2514,17 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)
 	unsigned int val;
 	int ret, count;
 
-	ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
-				       ADSP2_SYS_ENA, ADSP2_SYS_ENA);
-	if (ret != 0)
-		return ret;
+	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) {
@@ -2492,11 +2583,17 @@ static void wm_adsp2_boot_work(struct work_struct *work)
 	if (ret != 0)
 		goto err_ena;
 
-	/* 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;
+	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;
 
@@ -2518,12 +2615,21 @@ static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq)
 {
 	int ret;
 
-	ret = regmap_update_bits_async(dsp->regmap,
-				       dsp->base + ADSP2_CLOCKING,
-				       ADSP2_CLK_SEL_MASK,
-				       freq << ADSP2_CLK_SEL_SHIFT);
-	if (ret != 0)
-		adsp_err(dsp, "Failed to set clock rate: %d\n", 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,
@@ -2563,6 +2669,18 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
 }
 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)
@@ -2635,6 +2753,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
 		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,
@@ -2658,23 +2778,49 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
 		/* 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 */
-		wm_adsp2_show_fw_status(dsp);
+		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,
+		regmap_update_bits(dsp->regmap,
+				   dsp->base + ADSP2_CONTROL,
 				   ADSP2_CORE_ENA | ADSP2_START, 0);
 
 		/* Make sure DMAs are quiesced */
-		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);
+		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);
@@ -2727,15 +2873,22 @@ int wm_adsp2_init(struct wm_adsp *dsp)
 {
 	int ret;
 
-	/*
-	 * 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 != 0) {
-		adsp_err(dsp, "Failed to clear memory retention: %d\n", 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);
@@ -3518,4 +3671,94 @@ int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf,
 }
 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
index 3706b11053a3..41cc11c19b83 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -23,6 +23,23 @@
 #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;
@@ -40,6 +57,7 @@ struct wm_adsp_compr_buf;
 
 struct wm_adsp {
 	const char *part;
+	int rev;
 	int num;
 	int type;
 	struct device *dev;
@@ -75,6 +93,8 @@ struct wm_adsp {
 
 	struct mutex pwr_lock;
 
+	unsigned int lock_regions;
+
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_root;
 	char *wmfw_file_name;
@@ -113,6 +133,10 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
 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);