zte's code,first commit

Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/os/linux/linux-3.4.x/sound/soc/codecs/es8312.c b/ap/os/linux/linux-3.4.x/sound/soc/codecs/es8312.c
new file mode 100755
index 0000000..2361b02
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/sound/soc/codecs/es8312.c
@@ -0,0 +1,1575 @@
+/*
+ * es8312.c  --  ES8312/ES8312 ALSA SoC Audio Codec
+ *
+ * Copyright (C) 2018 Everest Semiconductor Co., Ltd
+ *
+ * Authors:  David Yang(yangxiaohua@everest-semi.com)
+ *
+ * Based on es8374.c by David Yang(yangxiaohua@everest-semi.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/stddef.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include <mach/gpio.h>
+#include <mach/pcu.h>
+#include <linux/gpio.h>
+#include <sound/jack.h>
+#include <linux/irq.h>
+
+#include "es8312.h"
+//#include <linux/soc/zte/pm/drv_idle.h>
+#include "linux/soc/zte/pm/drv_idle.h"
+#include "linux/wakelock.h"
+
+/*
+ * es8312 register cache
+ */
+static struct reg_default  es8312_reg_defaults[] = {
+	{ 0x00, 0x1f },
+	{ 0x01, 0x00 },
+	{ 0x02, 0x00 },
+	{ 0x03, 0x10 },
+	{ 0x04, 0x10 },
+	{ 0x05, 0x00 },
+	{ 0x06, 0x03 },
+	{ 0x07, 0x00 },
+	{ 0x08, 0xff },
+	{ 0x09, 0x00 },
+	{ 0x0a, 0x00 },
+	{ 0x0b, 0x00 },
+	{ 0x0c, 0x20 },
+	{ 0x0d, 0xfc },
+	{ 0x0e, 0x6a },
+	{ 0x0f, 0x00 },
+
+	{ 0x10, 0x13 },
+	{ 0x11, 0x7c },
+	{ 0x12, 0x02 },
+	{ 0x13, 0x40 },
+	{ 0x14, 0x10 },
+	{ 0x15, 0x00 },
+	{ 0x16, 0x04 },
+	{ 0x17, 0x00 },
+	{ 0x18, 0x00 },
+	{ 0x19, 0x00 },
+	{ 0x1a, 0x00 },
+	{ 0x1b, 0x0c },
+	{ 0x1c, 0x4c },
+	{ 0x1d, 0x00 },
+	{ 0x1e, 0x00 },
+	{ 0x1f, 0x00 },
+
+	{ 0x20, 0x00 },
+	{ 0x21, 0x00 },
+	{ 0x22, 0x00 },
+	{ 0x23, 0x00 },
+	{ 0x24, 0x00 },
+	{ 0x25, 0x00 },
+	{ 0x26, 0x00 },
+	{ 0x27, 0x00 },
+	{ 0x28, 0x00 },
+	{ 0x29, 0x00 },
+	{ 0x2a, 0x00 },
+	{ 0x2b, 0x00 },
+	{ 0x2c, 0x00 },
+	{ 0x2d, 0x00 },
+	{ 0x2e, 0x00 },
+	{ 0x2f, 0x00 },
+
+	{ 0x30, 0x00 },
+	{ 0x31, 0x00 },
+	{ 0x32, 0x00 },
+	{ 0x33, 0x00 },
+	{ 0x34, 0x00 },
+	{ 0x35, 0x00 },
+	{ 0x36, 0x00 },
+	{ 0x37, 0x08 },
+	{ 0x38, 0x00 },
+	{ 0x39, 0x00 },
+	{ 0x3a, 0x00 },
+	{ 0x3b, 0x00 },
+	{ 0x3c, 0x00 },
+	{ 0x3d, 0x00 },
+	{ 0x3e, 0x00 },
+	{ 0x3f, 0x00 },
+
+	{ 0x40, 0x00 },
+	{ 0x41, 0x00 },
+	{ 0x42, 0x00 },
+	{ 0x43, 0x00 },
+	{ 0x44, 0x00 },
+	{ 0x45, 0x00 },
+	
+};
+struct sp_config {
+	u8 spc, mmcc, spfs;
+	u32 srate;
+	u8 lrcdiv;
+	u8 sclkdiv;
+};
+
+/* codec private data */
+struct	es8312_private {
+	struct snd_soc_codec *codec;
+	struct regmap *regmap;
+	u32 mclk;
+	bool sclkinv;
+	bool mclkinv;
+	bool dmic_enable;
+	struct mutex codec_mutex;
+	struct wake_lock pm_lock;
+	volatile int codec_active_count;
+};
+
+struct es8312_private *es8312_data;
+struct snd_soc_codec *es8312_codec;
+
+static bool es8312_volatile_register(struct device *dev,
+			unsigned int reg)
+{
+	if ((reg  <= 0xff)) {
+		return true;
+	}
+	 else {
+		return false;
+	}
+}
+
+static bool es8312_readable_register(struct device *dev,
+			unsigned int reg)
+{
+	if ((reg  <= 0xff)) {
+		return true;
+	} 
+	else {
+		return false;
+	}
+}
+static bool es8312_writable_register(struct device *dev,
+			unsigned int reg)
+{
+	if ((reg  <= 0xff)) {
+		return true;
+	} 
+	else {
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(vdac_tlv, 
+				-9550, 50, true);
+static const DECLARE_TLV_DB_SCALE(vadc_tlv, 
+				-9550, 50, true);
+static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, 
+				0, 300, true);
+static const DECLARE_TLV_DB_SCALE(fm_pga_tlv, 
+				0, 600, true);	
+static const DECLARE_TLV_DB_SCALE(mono_pga_tlv, 
+				0, 600, true);				
+static const DECLARE_TLV_DB_SCALE(adc_scale_tlv, 
+				0, 600, false);
+static const DECLARE_TLV_DB_SCALE(alc_winsize_tlv, 
+				0, 25, false);
+static const DECLARE_TLV_DB_SCALE(alc_maxlevel_tlv, 
+				-3600, 200, false);
+static const DECLARE_TLV_DB_SCALE(alc_minlevel_tlv, 
+				-3600, 200, false);
+static const DECLARE_TLV_DB_SCALE(alc_noisegate_tlv, 
+				-9600, 600, false);
+static const DECLARE_TLV_DB_SCALE(alc_noisegate_winsize_tlv, 
+				4200, 4200, false);
+static const DECLARE_TLV_DB_SCALE(alc_automute_gain_tlv, 
+				4200, 4200, false);
+static const DECLARE_TLV_DB_SCALE(adc_ramprate_tlv, 
+				0, 25, false);
+
+static const char * const dmic_type_txt[] = {
+	"dmic at high level",
+	"dmic at low level"
+};
+static const struct soc_enum dmic_type =
+SOC_ENUM_SINGLE(ES8312_ADC_REG15, 0, 1, dmic_type_txt);
+
+static const char * const automute_type_txt[] = {
+	"automute disabled",
+	"automute enable"
+};
+static const struct soc_enum alc_automute_type =
+SOC_ENUM_SINGLE(ES8312_ADC_REG18, 6, 1, automute_type_txt);
+
+static const char * const dacdsm_mute_type_txt[] = {
+	"mute to 8",
+	"mute to 7/9"
+};
+static const struct soc_enum dacdsm_mute_type =
+SOC_ENUM_SINGLE(ES8312_DAC_REG31, 7, 1, dacdsm_mute_type_txt);
+
+static const char * const aec_type_txt[] = {
+	"adc left, adc right",
+	"adc left, null right",
+	"null left, adc right",
+	"null left, null right",
+	"dac left, adc right",
+	"adc left, dac right",
+	"dac left, dac right",
+	"N/A"
+};
+static const struct soc_enum aec_type =
+SOC_ENUM_SINGLE(ES8312_GPIO_REG44, 4, 7, aec_type_txt);
+
+static const char * const adc2dac_sel_txt[] = {
+	"disable",
+	"adc data to dac",
+};
+static const struct soc_enum adc2dac_sel =
+SOC_ENUM_SINGLE(ES8312_GPIO_REG44, 7, 1, adc2dac_sel_txt);
+
+static const char * const mclk_sel_txt[] = {
+	"from mclk pin",
+	"from bclk",
+};
+static const struct soc_enum mclk_src =
+SOC_ENUM_SINGLE(ES8312_CLK_MANAGER_REG01, 7, 1, mclk_sel_txt);
+
+/*
+ * es8312 Controls
+ */
+static const struct snd_kcontrol_new es8312_snd_controls[] = {
+	SOC_SINGLE_TLV("MIC PGA GAIN", ES8312_SYSTEM_REG14, 
+			0, 10, 0, mic_pga_tlv),
+	SOC_SINGLE_TLV("FM GAIN", ES8312_SYSTEM_REG13, 
+			6, 2, 0, fm_pga_tlv),
+	SOC_SINGLE("FM Switch", ES8312_SYSTEM_REG13, 5, 1, 0),
+	SOC_SINGLE_TLV("ADC SCALE", ES8312_ADC_REG16, 
+			0, 7, 0, adc_scale_tlv),
+	SOC_ENUM("DMIC TYPE", dmic_type),
+	SOC_SINGLE_TLV("ADC RAMP RATE", ES8312_ADC_REG15, 
+			4, 15, 0, adc_ramprate_tlv),
+	SOC_SINGLE("ADC SDP MUTE", ES8312_SDPOUT_REG0A, 6, 1, 0),
+	SOC_SINGLE("ADC INVERTED", ES8312_ADC_REG16, 4, 1, 0),
+	SOC_SINGLE("ADC SYNC", ES8312_ADC_REG16, 5, 1, 1),
+	SOC_SINGLE("ADC RAM CLR", ES8312_ADC_REG16, 3, 1, 0),
+	SOC_SINGLE_TLV("ADC VOLUME", ES8312_ADC_REG17, 
+			0, 255, 0, vadc_tlv),
+	SOC_SINGLE("ALC ENABLE", ES8312_ADC_REG18, 7, 1, 0),
+	SOC_ENUM("ALC AUTOMUTE TYPE", alc_automute_type),
+	SOC_SINGLE_TLV("ALC WIN SIZE", ES8312_ADC_REG18, 
+			0, 15, 0, alc_winsize_tlv),
+	SOC_SINGLE_TLV("ALC MAX LEVEL", ES8312_ADC_REG19, 
+			4, 15, 0, alc_maxlevel_tlv),
+	SOC_SINGLE_TLV("ALC MIN LEVEL", ES8312_ADC_REG19, 
+			0, 15, 0, alc_minlevel_tlv),
+	SOC_SINGLE_TLV("ALC AUTOMUTE WINSIZE", ES8312_ADC_REG1A, 
+			4, 15, 0, alc_noisegate_winsize_tlv),
+	SOC_SINGLE_TLV("ALC AUTOMUTE GATE THRESHOLD", ES8312_ADC_REG1A, 
+			0, 15, 0, alc_noisegate_tlv),
+	SOC_SINGLE_TLV("ALC AUTOMUTE VOLUME", ES8312_ADC_REG1B, 
+			5, 7, 0, alc_automute_gain_tlv),
+	SOC_SINGLE("ADC FS MODE", ES8312_CLK_MANAGER_REG03, 6, 1, 0),
+	SOC_SINGLE("ADC OSR", ES8312_CLK_MANAGER_REG03, 0, 63, 0),
+	SOC_SINGLE("DAC SDP MUTE", ES8312_SDPIN_REG09, 6, 1, 0),
+	SOC_SINGLE("DAC DEM  MUTE", ES8312_DAC_REG31, 5, 1, 0),
+	SOC_SINGLE("DAC INVERT", ES8312_DAC_REG31, 4, 1, 0),
+	SOC_SINGLE("DAC RAM CLR", ES8312_DAC_REG31, 3, 1, 0),
+	SOC_ENUM("DAC DSM MUTE", dacdsm_mute_type),
+	SOC_SINGLE("DAC OFFSET", ES8312_DAC_REG33, 0, 255, 0),
+	SOC_SINGLE_TLV("DAC VOLUME", ES8312_DAC_REG32, 
+			0, 255, 0, vdac_tlv),
+	SOC_SINGLE("DRC ENABLE", ES8312_DAC_REG34, 7, 1, 0),
+	SOC_SINGLE_TLV("DRC WIN SIZE",	ES8312_DAC_REG34, 
+			0, 15, 0, alc_winsize_tlv),
+	SOC_SINGLE_TLV("DRC MAX LEVEL",	ES8312_DAC_REG35, 
+			4, 15, 0, alc_maxlevel_tlv),
+	SOC_SINGLE_TLV("DRC MIN LEVEL",	ES8312_DAC_REG35, 
+			0, 15, 0, alc_minlevel_tlv),
+	SOC_SINGLE_TLV("DAC RAMP RATE",	ES8312_DAC_REG37, 
+			4, 15, 0, adc_ramprate_tlv),
+	SOC_SINGLE("DAC OSR", ES8312_CLK_MANAGER_REG04, 0, 127, 0),
+	SOC_ENUM("AEC MODE", aec_type),
+	SOC_ENUM("ADC DATA TO DAC TEST MODE", adc2dac_sel),
+	SOC_SINGLE("MCLK INVERT", ES8312_CLK_MANAGER_REG01, 6, 1, 0),
+	SOC_SINGLE("BCLK INVERT", ES8312_CLK_MANAGER_REG06, 5, 1, 0),
+//	SOC_ENUM("MCLK SOURCE", mclk_src),
+};
+
+/*
+* adc line in selection
+*/
+static const char * const es8312_adc_input_src_txt[] = {
+	"NO-IN",
+	"MIC1P-MIC1N",
+	"MIC2P-MIC2N",
+	"MIC1-MIC2",
+};
+static const unsigned int es8312_adc_input_src_values[] = {
+	0, 1, 2, 3};
+static const struct soc_enum es8312_adc_input_src_enum = 
+SOC_VALUE_ENUM_SINGLE(ES8312_SYSTEM_REG14, 4, 3,
+			ARRAY_SIZE(es8312_adc_input_src_txt),
+			es8312_adc_input_src_txt,
+			es8312_adc_input_src_values);
+static const struct snd_kcontrol_new es8312_adc_input_src_controls = 
+	SOC_DAPM_ENUM("Route", es8312_adc_input_src_enum);
+	
+/*
+ * DAPM Controls
+ */
+static const char * const es8312_dmic_mux_txt[] = {
+	"DMIC DISABLE",
+	"DMIC ENABLE"
+};
+static const unsigned int es8312_dmic_mux_values[] = {
+	0, 1
+};
+static const struct soc_enum es8312_dmic_mux_enum =
+	SOC_VALUE_ENUM_SINGLE(ES8312_SYSTEM_REG14, 6, 1,
+		ARRAY_SIZE(es8312_dmic_mux_txt),
+		es8312_dmic_mux_txt,
+		es8312_dmic_mux_values);
+static const struct snd_kcontrol_new es8312_dmic_mux_controls =
+	SOC_DAPM_ENUM("DMIC ROUTE", es8312_dmic_mux_enum);
+
+static const char * const es8312_adc_sdp_mux_txt[] = {
+	"FROM EQUALIZER",
+	"FROM ADC OUT",
+};
+static const unsigned int es8312_adc_sdp_mux_values[] = {
+	0, 1
+};
+static const struct soc_enum es8312_adc_sdp_mux_enum =
+	SOC_VALUE_ENUM_SINGLE(ES8312_ADC_REG1C, 6, 1,
+		ARRAY_SIZE(es8312_adc_sdp_mux_txt),
+		es8312_adc_sdp_mux_txt,
+		es8312_adc_sdp_mux_values);
+static const struct snd_kcontrol_new es8312_adc_sdp_mux_controls =
+	SOC_DAPM_ENUM("ADC SDP ROUTE", es8312_adc_sdp_mux_enum);
+
+/*
+* alc on/off
+*/
+static const char * const es8312_alc_enable_txt[] = {
+	"ALC OFF",
+	"ALC ON",
+};
+static const unsigned int es8312_alc_enable_values[] = {
+	0, 1};
+static const struct soc_enum es8312_alc_enable_enum = 
+SOC_VALUE_ENUM_SINGLE(ES8312_ADC_REG18, 7, 1,
+			ARRAY_SIZE(es8312_alc_enable_txt),
+			es8312_alc_enable_txt,
+			es8312_alc_enable_values);
+static const struct snd_kcontrol_new es8312_alc_enable_controls = 
+	SOC_DAPM_ENUM("Route", es8312_alc_enable_enum);
+	
+/*
+* DAC data  soure
+*/
+static const char * const es8312_dac_data_mux_txt[] = {
+	"SELECT SDP LEFT DATA",
+	"SELECT SDP RIGHT DATA",
+};
+static const unsigned int  es8312_dac_data_mux_values[] = {
+	0, 1
+};
+static const struct soc_enum  es8312_dac_data_mux_enum =
+	SOC_VALUE_ENUM_SINGLE(ES8312_SDPIN_REG09, 7, 1,
+		ARRAY_SIZE(es8312_dac_data_mux_txt),
+		es8312_dac_data_mux_txt,
+		es8312_dac_data_mux_values);
+static const struct snd_kcontrol_new  es8312_dac_data_mux_controls =
+	SOC_DAPM_ENUM("DAC SDP ROUTE", es8312_dac_data_mux_enum);
+
+
+/*
+* DRC
+*/
+static const char * const es8312_drc_mux_txt[] = {
+	"DRC DISABLE",
+	"DRC ENABLE",
+};
+static const unsigned int es8312_drc_mux_values[] = {
+	0, 1
+};
+static const struct soc_enum es8312_drc_mux_enum = 
+	SOC_VALUE_ENUM_SINGLE(ES8312_DAC_REG34, 7, 1,
+	ARRAY_SIZE(es8312_drc_mux_txt),
+	es8312_drc_mux_txt,
+	es8312_drc_mux_values);
+static const struct snd_kcontrol_new es8312_drc_mux_controls =
+	SOC_DAPM_ENUM("DRC MUX ROUTE", es8312_drc_mux_enum);
+	
+/*
+* Dac eq
+*/
+static const char * const es8312_dac_eq_mux_txt[] = {
+	"DAC EQ ENABLE",
+	"DAC EQ BYPASS",
+};
+static const unsigned int es8312_dac_eq_mux_values[] = {
+	0,1
+};
+static const struct soc_enum es8312_dac_eq_mux_enum = 
+	SOC_VALUE_ENUM_SINGLE(ES8312_DAC_REG37, 3, 1,
+	ARRAY_SIZE(es8312_dac_eq_mux_txt),
+	es8312_dac_eq_mux_txt,
+	es8312_dac_eq_mux_values);
+static const struct snd_kcontrol_new es8312_dac_eq_mux_controls =
+	SOC_DAPM_ENUM("DAC EQ MUX ROUTE", es8312_dac_eq_mux_enum);
+	
+	
+	
+static const struct snd_soc_dapm_widget es8312_dapm_widgets[] = {
+	/* Input*/
+	SND_SOC_DAPM_INPUT("DMIC"),
+	SND_SOC_DAPM_INPUT("AMIC"),
+
+	/* Input MUX */
+	SND_SOC_DAPM_MUX("DIFFERENTIAL MUX", SND_SOC_NOPM, 0, 0,
+			&es8312_adc_input_src_controls),
+			
+	SND_SOC_DAPM_PGA("INPUT PGA", SND_SOC_NOPM,
+			0, 0, NULL, 0),
+	/* ADCs */
+	SND_SOC_DAPM_ADC("MONO ADC", NULL, SND_SOC_NOPM, 0, 0),
+	/* Dmic MUX */	
+	SND_SOC_DAPM_MUX("DMIC MUX", SND_SOC_NOPM, 0, 0,
+			&es8312_dmic_mux_controls),
+			/* Dmic MUX */
+	SND_SOC_DAPM_MUX("ALC MUX", SND_SOC_NOPM, 0, 0,
+			&es8312_alc_enable_controls),
+			
+	/* sdp MUX */
+	SND_SOC_DAPM_MUX("SDP OUT MUX", SND_SOC_NOPM, 0, 0,
+		&es8312_adc_sdp_mux_controls),
+	/* Digital Interface */
+	SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture",  1,
+			SND_SOC_NOPM, 0, 0),
+	/* Render path	*/
+	SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0,
+			SND_SOC_NOPM, 0, 0),
+	/*DACs SDP DATA SRC MUX */
+	SND_SOC_DAPM_MUX("DAC SDP SRC MUX", SND_SOC_NOPM, 0, 0,
+			&es8312_dac_data_mux_controls),
+			
+	SND_SOC_DAPM_MUX("DRC MUX", SND_SOC_NOPM, 0, 0,
+			&es8312_drc_mux_controls),
+	SND_SOC_DAPM_MUX("DAC EQ MUX", SND_SOC_NOPM, 0, 0,
+			&es8312_dac_eq_mux_controls),
+			
+	SND_SOC_DAPM_DAC("MONO DAC", NULL, SND_SOC_NOPM, 0, 0),	
+	
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("DIFFERENTIAL OUT"),
+
+};
+
+
+static const struct snd_soc_dapm_route es8312_dapm_routes[] = {
+	/* record route map */
+	
+	{"DIFFERENTIAL MUX", "MIC1P-MIC1N", "AMIC"},
+	{"DIFFERENTIAL MUX", "MIC2P-MIC2N", "AMIC"},
+	{"DIFFERENTIAL MUX", "MIC1-MIC2", "AMIC"},
+	
+	{"INPUT PGA", NULL, "DIFFERENTIAL MUX"},
+	{"MONO ADC", NULL, "INPUT PGA"},
+	{"DMIC MUX", "DMIC DISABLE", "MONO ADC"},
+	{"DMIC MUX", "DMIC ENABLE", "DMIC"},
+	
+	/* Alc Mux */
+	{"ALC MUX", "ALC OFF", "DMIC MUX"},
+	{"ALC MUX", "ALC ON", "DMIC MUX"},
+	
+	/* 
+	* Equalizer path
+	*/
+	{"SDP OUT MUX", "FROM EQUALIZER", "ALC MUX"},
+	{"SDP OUT MUX", "FROM ADC OUT", "ALC MUX"},
+	
+	{"I2S OUT", NULL, "SDP OUT MUX"},
+	
+	/* playback route map */
+	{"DAC SDP SRC MUX", "SELECT SDP LEFT DATA", "I2S IN"},
+	{"DAC SDP SRC MUX", "SELECT SDP RIGHT DATA", "I2S IN"},
+	
+	{"DRC MUX", "DRC DISABLE", "DAC SDP SRC MUX"},
+	{"DRC MUX", "DRC ENABLE", "DAC SDP SRC MUX"},
+	
+	{"DAC EQ MUX", "DAC EQ BYPASS", "DRC MUX"},
+	{"DAC EQ MUX", "DAC EQ ENABLE", "DRC MUX"},
+	
+	{"MONO DAC", NULL, "DAC EQ MUX"},
+	{"DIFFERENTIAL OUT", NULL, "MONO DAC"},
+};
+
+struct _coeff_div {
+	u32 mclk;       /* mclk frequency */
+	u32 rate;       /* sample rate */
+	u8 prediv;      /* the pre divider with range from 1 to 8 */
+	u8 premulti;    /* the pre multiplier with x1, x2, x4 and x8 selection */
+	u8 adcdiv;      /* adcclk divider */
+	u8 dacdiv;      /* dacclk divider */
+	u8 fsmode;      /* double speed or single speed, =0, ss, =1, ds */
+	u8 lrck_h;      /* adclrck divider and daclrck divider */
+	u8 lrck_l;
+	u8 bclkdiv;     /* sclk divider */
+	u8 adcosr;      /* adc osr */
+	u8 dacosr;      /* dac osr */
+};
+
+
+/* codec hifi mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	//mclk     rate   prediv  mult  adcdiv dacdiv fsmode lrch  lrcl  bckdiv osr
+	/* 8k */
+	//{26000000, 8000 , 0x05, 0x08, 0x0d, 0x0d, 0x00, 0x01, 0xff, 0x04, 0x19, 0x19},
+	{26000000, 8000 , 0x06, 0x01, 0x02, 0x02, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10},
+	//{26000000, 8000 , 0x05, 0x08, 0x0d, 0x0d, 0x00, 0x01, 0x8f, 0x04, 0x14, 0x14},
+	{24576000, 8000 , 0x06, 0x01, 0x02, 0x02, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10},
+	{12288000, 8000 , 0x06, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10},
+	{18432000, 8000 , 0x03, 0x02, 0x03, 0x03, 0x00, 0x01, 0xff, 0x18, 0x10, 0x10},
+	{16384000, 8000 , 0x08, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10},
+	{8192000 , 8000 , 0x04, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10},
+	{6144000 , 8000 , 0x03, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10},
+	{4096000 , 8000 , 0x02, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10},
+	{3072000 , 8000 , 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10},
+	{2048000 , 8000 , 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10},
+	{1536000 , 8000 , 0x03, 0x04, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10},
+	{1024000 , 8000 , 0x01, 0x02, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10},
+
+	/* 11.025k */
+	{26000000, 11025, 0x04, 0x01, 0x02, 0x02, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{24576000, 11025, 0x04, 0x01, 0x02, 0x02, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{11289600, 11025, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{5644800 , 11025, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{2822400 , 11025, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{1411200 , 11025, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+
+	/* 12k */
+	{26000000, 12000, 0x08, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x19, 0x19},
+	{24576000, 12000, 0x08, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{12288000, 12000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{6144000 , 12000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{3072000 , 12000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{1536000 , 12000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+
+	/* 16k */
+	{26000000, 16000, 0x06, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{24576000, 16000, 0x06, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{12288000, 16000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{18432000, 16000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x10},
+	{16384000, 16000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{8192000 , 16000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{6144000 , 16000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{4096000 , 16000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{3072000 , 16000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{2048000 , 16000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{1536000 , 16000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{1024000 , 16000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	
+	/* 22.05k */
+	{26000000, 22050, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{24576000, 22050, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{11289600, 22050, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{5644800 , 22050, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{2822400 , 22050, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{1411200 , 22050, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+
+	/* 24k */
+	{26000000, 24000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{24576000, 24000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{12288000, 24000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{18432000, 24000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{6144000 , 24000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{3072000 , 24000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{1536000 , 24000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	
+	/* 32k */
+	{26000000, 32000, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{24576000, 32000, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{12288000, 32000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{18432000, 32000, 0x03, 0x04, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x10},
+	{16384000, 32000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{8192000 , 32000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{6144000 , 32000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{4096000 , 32000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{3072000 , 32000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{2048000 , 32000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{1536000 , 32000, 0x03, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10},
+	{1024000 , 32000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+
+	/* 44.1k */
+	{26000000, 44100, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{24576000, 44100, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{11289600, 44100, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{5644800 , 44100, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{2822400 , 44100, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{1411200 , 44100, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+
+	/* 48k */
+	{26000000, 48000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{24576000, 48000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{12288000, 48000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{18432000, 48000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{6144000 , 48000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+ 	{3072000 , 48000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{1536000 , 48000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+
+	/* 64k */
+	{26000000, 64000, 0x06, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{24576000, 64000, 0x06, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{12288000, 64000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{18432000, 64000, 0x03, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10},
+	{16384000, 64000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{8192000 , 64000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{6144000 , 64000, 0x01, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10},
+	{4096000 , 64000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{3072000 , 64000, 0x01, 0x08, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10},
+	{2048000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{1536000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0xbf, 0x03, 0x18, 0x18},
+	{1024000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10},
+
+	/* 88.2k */
+	{26000000, 88200, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{24576000, 88200, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{11289600, 88200, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{5644800 , 88200, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{2822400 , 88200, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{1411200 , 88200, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10},
+
+	/* 96k */
+	{26000000, 96000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{24576000, 96000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{12288000, 96000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{18432000, 96000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{6144000 , 96000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{3072000 , 96000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
+	{1536000 , 96000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10},
+};
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * if PLL not be used, use internal clk1 for mclk,otherwise, use internal clk2 for PLL source.
+ */
+static int es8312_set_dai_sysclk(struct snd_soc_dai *dai,
+			int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct es8312_private *es8312 = snd_soc_codec_get_drvdata(codec);
+	printk("Enter into %s() freq =%d\n", __func__, freq);
+	
+	if (clk_id == ES8312_CLKID_BCLK)
+		snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01, 0x80, 0x80);
+	else if (clk_id == ES8312_CLKID_MCLK)
+		snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01, 0x80, 0x00);
+	
+	es8312->mclk = freq;
+#if 0	
+	switch (freq) {
+	case 11289600:
+	case 22579200:
+		es8312->mclk = freq;
+		return 0;
+
+	case 12288000:
+	case 16384000:
+	case 18432000:
+	case 24576000:
+	case 26000000:
+		es8312->mclk = freq;
+		return 0;
+	}
+#endif
+	return 0;
+}
+
+static int es8312_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 iface = 0;
+	u8 adciface = 0;
+	u8 daciface = 0;
+	printk("Enter into %s()\n", __func__);
+	iface    = snd_soc_read(codec, ES8312_RESET_REG00);
+	adciface = snd_soc_read(codec, ES8312_SDPOUT_REG0A);
+	daciface = snd_soc_read(codec, ES8312_SDPIN_REG09);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:    /* MASTER MODE */
+		printk("ES8312 in Master mode\n");
+		iface |= 0x40;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:    /* SLAVE MODE */
+		printk("ES8312 in Slave mode\n");
+		iface &= 0xBF;
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_write(codec, ES8312_RESET_REG00, iface);
+
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		printk("ES8312 in I2S Format\n");
+		adciface &= 0xFC;
+		daciface &= 0xFC;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		return -EINVAL;
+	case SND_SOC_DAIFMT_LEFT_J:
+		printk("ES8312 in LJ Format\n");
+		adciface &= 0xFC;
+		daciface &= 0xFC;
+		adciface |= 0x01;
+		daciface |= 0x01;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		printk("ES8312 in DSP-A Format\n");
+		adciface &= 0xDC;
+		daciface &= 0xDC;
+		adciface |= 0x03;
+		daciface |= 0x03;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		printk("ES8312 in DSP-B Format\n");
+		adciface &= 0xDC;
+		daciface &= 0xDC;
+		adciface |= 0x23;
+		daciface |= 0x23;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	iface    = snd_soc_read(codec, ES8312_CLK_MANAGER_REG06);
+	/* clock inversion */
+	if(((fmt & SND_SOC_DAIFMT_FORMAT_MASK)==SND_SOC_DAIFMT_I2S) ||
+		((fmt & SND_SOC_DAIFMT_FORMAT_MASK)==SND_SOC_DAIFMT_LEFT_J))
+		{
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+
+			iface    &= 0xDF;
+			adciface &= 0xDF;
+			daciface &= 0xDF;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			iface    |= 0x20;
+			adciface |= 0x20;
+			daciface |= 0x20;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			iface    |= 0x20;
+			adciface &= 0xDF;
+			daciface &= 0xDF;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			iface    &= 0xDF;
+			adciface |= 0x20;
+			daciface |= 0x20;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG06, iface);
+	snd_soc_write(codec, ES8312_SDPOUT_REG0A, adciface);
+	snd_soc_write(codec, ES8312_SDPIN_REG09, daciface);
+	return 0;
+}
+
+static int es8312_pcm_startup(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	return 0;
+}
+
+static int es8312_pcm_shutdown(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct es8312_private *es8312 = snd_soc_codec_get_drvdata(codec);
+	printk("Enter into %s()\n", __func__);
+	snd_soc_write(codec, ES8312_DAC_REG32, 0x00);
+	snd_soc_write(codec, ES8312_ADC_REG17, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0E, 0xFF);
+	snd_soc_write(codec, ES8312_SYSTEM_REG12, 0x02);
+	snd_soc_write(codec, ES8312_SYSTEM_REG14, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0xFA);
+	snd_soc_write(codec, ES8312_ADC_REG15, 0x00);
+	snd_soc_write(codec, ES8312_DAC_REG37, 0x08);	
+	snd_soc_write(codec, ES8312_RESET_REG00, 0x00);
+	snd_soc_write(codec, ES8312_RESET_REG00, 0x1F);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x30);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x00);
+	snd_soc_write(codec, ES8312_GP_REG45, 0x01);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0xFC);
+	return 0;
+}
+
+static int es8312_pcm_hw_params(struct snd_pcm_substream *substream,
+			struct snd_pcm_hw_params *params,
+			struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct es8312_private *es8312 = snd_soc_codec_get_drvdata(codec);
+	u16 iface;
+	int coeff;
+	u8 regv, datmp;
+	printk("Enter into %s()\n", __func__);
+
+	coeff = get_coeff(es8312->mclk, params_rate(params));
+	if (coeff < 0) {
+		printk("Unable to configure sample rate %dHz with %dHz MCLK\n",
+			params_rate(params), es8312->mclk);
+		return coeff;
+	}
+	
+	/*
+	* set clock parammeters
+	*/
+	if(coeff >= 0) {
+		snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x30);
+		snd_soc_write(codec, ES8312_RESET_REG00, 0x83);
+		regv = snd_soc_read(codec, ES8312_CLK_MANAGER_REG02) & 0x07;
+		regv |= (coeff_div[coeff].prediv - 1) << 5;
+		datmp = 0;
+		switch(coeff_div[coeff].premulti) 
+		{
+		case 1:
+			datmp = 0;
+			break;
+		case 2:
+			datmp = 1;
+			break;
+		case 4:
+			datmp = 2;
+			break;
+		case 8:
+			datmp = 3;
+			break;
+		defalut:
+			break;
+		}
+		regv |= (datmp) << 3;
+		snd_soc_write(codec, ES8312_CLK_MANAGER_REG02, regv);
+
+		regv = snd_soc_read(codec, ES8312_CLK_MANAGER_REG05) & 0x00;
+		regv |= (coeff_div[coeff].adcdiv-1) << 4;
+		regv |= (coeff_div[coeff].dacdiv-1) << 0;
+		snd_soc_write(codec, ES8312_CLK_MANAGER_REG05, regv);
+
+		regv = snd_soc_read(codec, ES8312_CLK_MANAGER_REG03) & 0x80;
+		regv |= coeff_div[coeff].fsmode << 6;
+		regv |= coeff_div[coeff].adcosr << 0;
+		snd_soc_write(codec, ES8312_CLK_MANAGER_REG03, regv);
+
+		regv = snd_soc_read(codec, ES8312_CLK_MANAGER_REG04) & 0x80;
+		regv |= coeff_div[coeff].dacosr << 0;
+		snd_soc_write(codec, ES8312_CLK_MANAGER_REG04, regv);
+	
+		regv = snd_soc_read(codec, ES8312_CLK_MANAGER_REG07) & 0xf0;
+		regv |= coeff_div[coeff].lrck_h << 0;
+		snd_soc_write(codec, ES8312_CLK_MANAGER_REG07, regv);
+
+		regv = snd_soc_read(codec, ES8312_CLK_MANAGER_REG08) & 0x00;
+		regv |= coeff_div[coeff].lrck_l << 0;
+		snd_soc_write(codec, ES8312_CLK_MANAGER_REG08, regv);
+
+		regv = snd_soc_read(codec, ES8312_CLK_MANAGER_REG06) & 0xE0;
+		regv |= coeff_div[coeff].bclkdiv << 0;
+		snd_soc_write(codec, ES8312_CLK_MANAGER_REG06, regv);
+		
+		snd_soc_write(codec, ES8312_RESET_REG00, 0x80);
+		snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x3F);		
+	}
+	
+	if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		iface = snd_soc_read(codec, ES8312_SDPIN_REG09) & 0xE3;
+		/* bit size */
+		switch (params_format(params)) {
+		case SNDRV_PCM_FORMAT_S16_LE:
+			iface |= 0x0c;
+			break;
+		case SNDRV_PCM_FORMAT_S20_3LE:
+			iface |= 0x04;
+			break;
+		case SNDRV_PCM_FORMAT_S24_LE:
+			break;
+		case SNDRV_PCM_FORMAT_S32_LE:
+			iface |= 0x10;
+			break;
+		}
+		/* set iface */
+		snd_soc_write(codec, ES8312_SDPIN_REG09, iface);
+	} else {
+		iface = snd_soc_read(codec, ES8312_SDPOUT_REG0A) & 0xE3;
+		/* bit size */
+		
+		/* set iface */
+		snd_soc_write(codec, ES8312_SDPOUT_REG0A, iface);
+	}
+	switch (params_format(params)) {
+		case SNDRV_PCM_FORMAT_S16_LE:
+			iface |= 0x0c;
+			break;
+		case SNDRV_PCM_FORMAT_S20_3LE:
+			iface |= 0x04;
+			break;
+		case SNDRV_PCM_FORMAT_S24_LE:
+			break;
+		case SNDRV_PCM_FORMAT_S32_LE:
+			iface |= 0x10;
+			break;
+		}
+		switch(params_rate(params)) 
+			{
+			case 8000:
+			case 11025:				
+			break;
+			case 16000:			
+			case 24000:
+			case 48000:
+			case 22050:
+			case 44100:
+				break;
+			default:
+				break;
+			}
+	return 0;
+}
+extern void zx29_i2s_close_clk(void);
+#ifdef CONFIG_PM
+static void es8312_set_cpu_active(struct es8312_private *es8312)
+{
+	mutex_lock(&es8312->codec_mutex);
+	if(es8312->codec_active_count == 0)
+	{
+		zx_cpuidle_set_busy(IDLE_FLAG_CODEC);
+		wake_lock(&es8312->pm_lock);
+		es8312->codec_active_count++;
+	}
+	mutex_unlock(&es8312->codec_mutex);
+}
+
+static void es8312_set_cpu_idle(struct es8312_private *es8312)
+{
+	mutex_lock(&es8312->codec_mutex);
+	if(es8312->codec_active_count != 0)
+	{
+		es8312->codec_active_count--;
+		zx_cpuidle_set_free(IDLE_FLAG_CODEC);
+		wake_unlock(&es8312->pm_lock);		
+	}
+	mutex_unlock(&es8312->codec_mutex);
+}
+
+#endif
+static int es8312_set_bias_level(struct snd_soc_codec *codec,
+			enum snd_soc_bias_level level)
+{
+	int regv;
+	struct es8312_private *es8312 = snd_soc_codec_get_drvdata(codec);
+	printk("Enter into %s(), level = %d\n", __func__, level);
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_write(codec, ES8312_GP_REG45, 0x00);
+		snd_soc_write(codec, ES8312_ADC_REG16, 0x24);		
+		snd_soc_write(codec, ES8312_SYSTEM_REG0B, 0x00);
+		snd_soc_write(codec, ES8312_SYSTEM_REG0C, 0x00);
+		snd_soc_write(codec, ES8312_SYSTEM_REG10, 0x1F);
+		snd_soc_write(codec, ES8312_SYSTEM_REG11, 0x7F);
+		snd_soc_write(codec, ES8312_RESET_REG00, 0x80);
+		snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0x01);
+		snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01, 0x3F, 0x3F);
+		if(es8312->mclkinv == true) {
+			snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01,
+					0x40, 0x40);
+		}
+		else {
+			snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01,
+					0x40, 0x00);
+		}
+		if(es8312->sclkinv == true) {
+			snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG06,
+					0x20, 0x20);
+		}
+		else {
+			snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG06,
+					0x20, 0x00);
+		}
+		regv = snd_soc_read(codec, ES8312_SYSTEM_REG14) & 0xCF;
+		regv |= 0x1A;
+		snd_soc_write(codec, ES8312_SYSTEM_REG14, regv);
+		if(es8312->dmic_enable == true) {
+			snd_soc_update_bits(codec, ES8312_SYSTEM_REG14,
+					0x40, 0x40);
+		}
+		else {
+			snd_soc_update_bits(codec, ES8312_SYSTEM_REG14,
+					0x40, 0x00);
+		}
+		snd_soc_write(codec, ES8312_SYSTEM_REG13, 0x10);
+		snd_soc_write(codec, ES8312_SYSTEM_REG0E, 0x02);
+		snd_soc_write(codec, ES8312_ADC_REG15, 0x40);
+		snd_soc_write(codec, ES8312_ADC_REG1B, 0x0A);
+		snd_soc_write(codec, ES8312_ADC_REG1C, 0x6A);
+		snd_soc_write(codec, ES8312_DAC_REG37, 0x48);
+		snd_soc_write(codec, ES8312_GPIO_REG44, 0x08);
+		snd_soc_write(codec, ES8312_ADC_REG17, 0xBF);
+		snd_soc_write(codec, ES8312_DAC_REG32, 0xBF);
+		snd_soc_write(codec, ES8312_SYSTEM_REG12, 0xc0);
+	#ifdef CONFIG_PM
+		es8312_set_cpu_active(es8312);
+	#endif
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+	snd_soc_write(codec, ES8312_DAC_REG32, 0x00);
+	snd_soc_write(codec, ES8312_ADC_REG17, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0E, 0xFF);
+	snd_soc_write(codec, ES8312_SYSTEM_REG12, 0x02);
+	snd_soc_write(codec, ES8312_SYSTEM_REG14, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0xFA);
+	snd_soc_write(codec, ES8312_ADC_REG15, 0x00);
+	snd_soc_write(codec, ES8312_DAC_REG37, 0x08);	
+	snd_soc_write(codec, ES8312_RESET_REG00, 0x00);
+	snd_soc_write(codec, ES8312_RESET_REG00, 0x1F);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x30);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x00);
+	snd_soc_write(codec, ES8312_GP_REG45, 0x01);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0xFC);
+	zx29_i2s_close_clk();
+#ifdef CONFIG_PM
+	es8312_set_cpu_idle(es8312);
+#endif
+		break;
+	case SND_SOC_BIAS_OFF:
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+static int es8312_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	printk("Enter into %s(), tristate = %d\n", __func__, tristate);
+	if(tristate) {
+		snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG07,
+			0x30, 0x30);
+	} 
+	else {
+		snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG07,
+			0x30, 0x00);
+	}
+	return 0;
+}
+
+static DEFINE_RAW_SPINLOCK(codec_pa_lock);
+static int es8312_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned long  flags;
+	
+	printk("Enter into %s(), mute = %d\n", __func__, mute);
+	if (mute) {
+	//	snd_soc_write(codec, ES8312_SYSTEM_REG12, 0x02);
+		mdelay(4);
+		gpio_set_value(ZX29_GPIO_125, GPIO_LOW);
+		mdelay(1);
+		snd_soc_update_bits(codec, ES8312_DAC_REG31, 0x68, 0x68);
+	//	snd_soc_write(codec, ES8312_DAC_REG32, 0x00);
+	//	snd_soc_write(codec, ES8312_DAC_REG37, 0x08);
+	} 	else if (dai->playback_active) {
+		gpio_set_value(ZX29_GPIO_125, GPIO_LOW);
+		mdelay(1);
+		raw_spin_lock_irqsave(&codec_pa_lock, flags);
+		gpio_set_value(ZX29_GPIO_125, GPIO_HIGH);
+		udelay(2);	
+		gpio_set_value(ZX29_GPIO_125, GPIO_LOW);
+		udelay(2);
+		gpio_set_value(ZX29_GPIO_125, GPIO_HIGH);
+		udelay(2);	
+		gpio_set_value(ZX29_GPIO_125, GPIO_LOW);
+		udelay(2);
+		gpio_set_value(ZX29_GPIO_125, GPIO_HIGH);
+		raw_spin_unlock_irqrestore(&codec_pa_lock, flags); 
+		snd_soc_update_bits(codec, ES8312_DAC_REG31, 0x68, 0x00);
+	//	snd_soc_write(codec, ES8312_SYSTEM_REG12, 0x00);
+	}
+	return 0;
+}
+
+#define es8312_RATES SNDRV_PCM_RATE_8000_96000
+
+#define es8312_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+		SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops es8312_ops = {
+	.startup = es8312_pcm_startup,
+	.hw_params = es8312_pcm_hw_params,
+	.set_fmt = es8312_set_dai_fmt,
+	.set_sysclk = es8312_set_dai_sysclk,
+	.digital_mute = es8312_mute,
+	.set_tristate = es8312_set_tristate,
+};
+
+static struct snd_soc_dai_driver es8312_dai[] = {
+	{
+	.name = "ES8312 HiFi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = es8312_RATES,
+		.formats = es8312_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = es8312_RATES,
+		.formats = es8312_FORMATS,
+	},
+	.ops = &es8312_ops,
+	.symmetric_rates = 1,
+	},
+};
+
+static int es8312_suspend(struct snd_soc_codec *codec)
+{
+	printk("Enter into %s()\n", __func__);
+	snd_soc_write(codec, ES8312_DAC_REG32, 0x00);
+	snd_soc_write(codec, ES8312_ADC_REG17, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0E, 0xFF);
+	snd_soc_write(codec, ES8312_SYSTEM_REG12, 0x02);
+	snd_soc_write(codec, ES8312_SYSTEM_REG14, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0xFA);
+	snd_soc_write(codec, ES8312_ADC_REG15, 0x00);
+	snd_soc_write(codec, ES8312_DAC_REG37, 0x08);
+	snd_soc_write(codec, ES8312_RESET_REG00, 0x00);
+	snd_soc_write(codec, ES8312_RESET_REG00, 0x1F);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x30);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x00);
+	snd_soc_write(codec, ES8312_GP_REG45, 0x01);
+	return 0;
+}
+
+static int es8312_resume(struct snd_soc_codec *codec)
+{
+	struct es8312_private *es8312 = snd_soc_codec_get_drvdata(codec);
+	printk("Enter into %s()\n", __func__);
+	snd_soc_write(codec, ES8312_GP_REG45, 0x00);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x30);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG02, 0x00);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG03, 0x10);
+	snd_soc_write(codec, ES8312_ADC_REG16, 0x24);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG04, 0x10);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG05, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0B, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0C, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG10, 0x1F);
+	snd_soc_write(codec, ES8312_SYSTEM_REG11, 0x7F);
+	snd_soc_write(codec, ES8312_RESET_REG00, 0x80);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0x01);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x3F);
+	if(es8312->mclkinv == true) {
+		snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01,
+				0x40, 0x40);
+	}
+	else {
+		snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01,
+				0x40, 0x00);
+	}
+	if(es8312->sclkinv == true) {
+		snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG06,
+				0x20, 0x20);
+	}
+	else {
+		snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG06,
+				0x20, 0x00);
+	}
+	snd_soc_write(codec, ES8312_SYSTEM_REG14, 0x1A);
+	if(es8312->dmic_enable == true) {
+		snd_soc_update_bits(codec, ES8312_SYSTEM_REG14,
+				0x40, 0x40);
+	}
+	else {
+		snd_soc_update_bits(codec, ES8312_SYSTEM_REG14,
+				0x40, 0x00);
+	}
+	snd_soc_write(codec, ES8312_SYSTEM_REG12, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG13, 0x10);
+	snd_soc_write(codec, ES8312_SDPIN_REG09, 0x00);
+	snd_soc_write(codec, ES8312_SDPOUT_REG0A, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0E, 0x02);
+	snd_soc_write(codec, ES8312_ADC_REG15, 0x40);
+	snd_soc_write(codec, ES8312_ADC_REG1B, 0x0A);
+	snd_soc_write(codec, ES8312_ADC_REG1C, 0x6A);
+	snd_soc_write(codec, ES8312_DAC_REG37, 0x48);
+	snd_soc_write(codec, ES8312_GPIO_REG44, 0x08);
+	snd_soc_write(codec, ES8312_ADC_REG17, 0xBF);
+	snd_soc_write(codec, ES8312_DAC_REG32, 0xBF);
+
+	return 0;
+}
+
+static int es8312_probe(struct snd_soc_codec *codec)
+{
+	int ret = 0;
+	struct es8312_private *es8312 = snd_soc_codec_get_drvdata(codec);
+	printk("Enter into %s()\n", __func__);
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+	if (ret < 0)
+		return ret;
+	es8312_codec = codec;
+	es8312->codec = codec;
+	codec->cache_bypass = 1;
+	
+	snd_soc_update_bits(codec, ES8312_RESET_REG00, 
+			0x10, 0x10);
+	snd_soc_update_bits(codec, ES8312_RESET_REG00, 
+			0x10, 0x00);
+	snd_soc_write(codec, ES8312_GP_REG45, 0x00);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x30);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG02, 0x00);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG03, 0x10);
+	snd_soc_write(codec, ES8312_ADC_REG16, 0x24);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG04, 0x10);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG05, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0B, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0C, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG10, 0x1F);
+	snd_soc_write(codec, ES8312_SYSTEM_REG11, 0x7F);
+	snd_soc_write(codec, ES8312_RESET_REG00, 0x80);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0x01);
+	snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x3F);
+	if(es8312->mclkinv == true) {
+		snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01, 
+				0x40, 0x40);
+	}
+	else {
+		snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01, 
+				0x40, 0x00);
+	}
+	if(es8312->sclkinv == true) {
+		snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG06,
+				0x20, 0x20); 
+	}
+	else {
+		snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG06,
+				0x20, 0x00); 
+	}
+	snd_soc_write(codec, ES8312_SYSTEM_REG14, 0x1A);
+	if(es8312->dmic_enable == true) {
+		snd_soc_update_bits(codec, ES8312_SYSTEM_REG14,
+				0x40, 0x40);
+	}
+	else {
+		snd_soc_update_bits(codec, ES8312_SYSTEM_REG14,
+				0x40, 0x00);
+	} 
+	snd_soc_write(codec, ES8312_SYSTEM_REG12, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG13, 0x10);
+	snd_soc_write(codec, ES8312_SDPIN_REG09, 0x00);
+	snd_soc_write(codec, ES8312_SDPOUT_REG0A, 0x00);
+	snd_soc_write(codec, ES8312_SYSTEM_REG0E, 0x02);
+	snd_soc_write(codec, ES8312_ADC_REG15, 0x40);
+	snd_soc_write(codec, ES8312_ADC_REG1B, 0x0A);
+	snd_soc_write(codec, ES8312_ADC_REG1C, 0x6A);
+	snd_soc_write(codec, ES8312_DAC_REG37, 0x48);
+	snd_soc_write(codec, ES8312_GPIO_REG44, 0x08);
+	snd_soc_write(codec, ES8312_ADC_REG17, 0xBF);
+	snd_soc_write(codec, ES8312_DAC_REG32, 0xBF);
+	
+	msleep(100);
+	es8312_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	return ret;
+}
+
+static int es8312_remove(struct snd_soc_codec *codec)
+{
+	es8312_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_es8312 = {
+	.probe = es8312_probe,
+	.remove = es8312_remove,
+	.suspend = es8312_suspend,
+	.resume = es8312_resume,
+	.set_bias_level = es8312_set_bias_level,
+
+	.reg_cache_size = ARRAY_SIZE(es8312_reg_defaults),
+	.reg_word_size = sizeof(u8),
+	.reg_cache_default = es8312_reg_defaults,
+	.controls = es8312_snd_controls,
+	.num_controls = ARRAY_SIZE(es8312_snd_controls),
+	.dapm_widgets = es8312_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(es8312_dapm_widgets),
+	.dapm_routes = es8312_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(es8312_dapm_routes),
+};
+
+static struct regmap_config es8312_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = ES8312_MAX_REGISTER,
+	.reg_defaults = es8312_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(es8312_reg_defaults),
+	.volatile_reg = es8312_volatile_register,
+	.writeable_reg = es8312_writable_register,
+	.readable_reg  = es8312_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+#ifdef CONFIG_OF
+static struct of_device_id es8312_if_dt_ids[] = {
+	{ .compatible = "ambarella,es8312", },
+	{ }
+};
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static void es8312_i2c_shutdown(struct i2c_client *i2c)
+{
+	struct snd_soc_codec *codec;
+	struct es8312_private *es8312;
+	es8312 = i2c_get_clientdata(i2c);
+	if(es8312 == NULL){
+		printk("%s(): NULL pointer es8312\n", __FUNCTION__);
+		return;
+	}
+	codec = es8312->codec;
+	return;
+}
+static u32 cur_reg=0;
+
+static ssize_t es8312_show(struct device *dev, 
+			struct device_attribute *attr, char *_buf)
+{
+	int ret;
+	ret = sprintf(_buf, "%s(): get 0x%04x=0x%04x\n",
+			__FUNCTION__, cur_reg,
+			snd_soc_read(es8312_codec, cur_reg));
+	return ret;
+}
+
+static u32 strtol(const char *nptr, int base)
+{
+	u32 ret; 
+	if(!nptr || (base!=16 && base!=10 && base!=8))
+	{
+		printk("%s(): NULL pointer input\n", __FUNCTION__);
+		return -1;
+	}
+	for(ret=0; *nptr; nptr++)
+	{
+		if((base==16 && *nptr>='A' && *nptr<='F') ||
+			(base==16 && *nptr>='a' && *nptr<='f') ||
+			(base>=10 && *nptr>='0' && *nptr<='9') ||
+			(base>=8 && *nptr>='0' && *nptr<='7') )
+		{
+			ret *= base;
+			if(base==16 && *nptr>='A' && *nptr<='F')
+				ret += *nptr-'A'+10;
+			else if(base==16 && *nptr>='a' && *nptr<='f')
+				ret += *nptr-'a'+10;
+			else if(base>=10 && *nptr>='0' && *nptr<='9')
+				ret += *nptr-'0';
+			else if(base>=8 && *nptr>='0' && *nptr<='7')
+				ret += *nptr-'0';
+		}
+		else
+			return ret;
+	}
+	return ret;
+}
+
+static ssize_t es8312_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	int val=0, flag=0;
+	u8 i=0, reg, num, value_w, value_r;
+
+	val = simple_strtol(buf, NULL, 16);
+	flag = (val >> 16) & 0xFF;
+
+	if (flag) {
+		reg = (val >> 8) & 0xFF;
+		value_w = val & 0xFF;
+		printk("\nWrite: start REG:0x%02x,val:0x%02x,count:0x%02x\n", 
+				reg, value_w, flag);
+		while(flag--) {
+			snd_soc_write(es8312_codec, reg, value_w);
+			printk("Write 0x%02x to REG:0x%02x\n", 
+				value_w, 
+				reg);
+			reg++;
+		}
+	} 
+	else {
+		reg = (val >> 8) & 0xFF;
+		num = val & 0xff;
+		printk("\nRead: start REG:0x%02x,count:0x%02x\n", 
+			reg, num);
+		do {
+			value_r = 0;
+			value_r = snd_soc_read(es8312_codec, reg);
+			printk("REG[0x%02x]: 0x%02x;  \n", 
+			reg, value_r);
+			reg++;
+			i++;
+		} while (i<num);
+	}
+	
+	return count;
+}
+
+static struct device *es8312_dev = NULL;
+static struct class *es8312_class = NULL;
+static DEVICE_ATTR(es8312, 0664, es8312_show, es8312_store);
+
+static struct attribute *es8312_debug_attrs[] = {
+	&dev_attr_es8312.attr,
+	NULL,
+};
+
+static struct attribute_group es8312_debug_attr_group = {
+	.name   = "es8312_debug",
+	.attrs  = es8312_debug_attrs,
+};
+
+static int es8312_i2c_probe(struct i2c_client *i2c_client,
+					const struct i2c_device_id *id)
+{
+	struct es8312_private *es8312;
+	int ret = -1;
+	printk("Enter into %s\n", __func__);
+	es8312 = devm_kzalloc(&i2c_client->dev, 
+			sizeof(*es8312), GFP_KERNEL);
+	if (es8312 == NULL)
+		return -ENOMEM;
+
+	printk("Enter into %s---1\n", __func__);
+	es8312->dmic_enable = false;     // dmic interface disabled
+	/* the edge of lrck is always at the falling edge of mclk */
+	es8312->mclkinv = false; 
+        /* the edge of lrck is always at the falling edge of sclk */         
+	es8312->sclkinv = false; 
+
+	printk("Enter into %s----2\n", __func__);
+	dev_set_drvdata(&i2c_client->dev,  es8312);
+	es8312_data = es8312;
+	printk("Enter into %s---3\n", __func__);
+	ret =  snd_soc_register_codec(&i2c_client->dev, 
+			&soc_codec_dev_es8312,
+			&es8312_dai[0], 
+			ARRAY_SIZE(es8312_dai));
+	if (ret < 0) {
+		kfree(es8312);
+		return ret;
+	}
+	
+	printk("Enter into %s-----4\n", __func__);
+	ret = sysfs_create_group(&i2c_client->dev.kobj, 
+				&es8312_debug_attr_group);
+	if (ret) {
+		pr_err("failed to create attr group\n");
+	}
+	ret = gpio_request_one(ZX29_GPIO_125, GPIOF_OUT_INIT_LOW, "codec_pa");
+	if (ret < 0) {
+		printk(KERN_ERR "Alsa es8374: codec_pa in use\n");
+		return ret;
+	}
+	#ifdef CONFIG_PM
+	es8312->codec_active_count = 0;
+	mutex_init(&es8312->codec_mutex);
+	wake_lock_init(&es8312->pm_lock,WAKE_LOCK_SUSPEND,"es8312-code");
+	#endif
+	printk("Exit %s\n", __func__);
+	return ret;
+}
+
+static  int es8312_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static const struct i2c_device_id es8312_i2c_id[] = {
+	{"es8312", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, es8312_i2c_id);
+
+static struct i2c_driver es8312_i2c_driver = {
+	.driver = {
+		.name	= "es8312",
+		.owner	= THIS_MODULE,
+#ifdef CONFIG_OF
+		.of_match_table = of_match_ptr(es8312_if_dt_ids),
+#endif
+	},
+	.shutdown = es8312_i2c_shutdown,
+	.probe = es8312_i2c_probe,
+	.remove	= es8312_i2c_remove,
+	.id_table	= es8312_i2c_id,
+};
+#endif
+static int __init es8312_init(void)
+{
+	return i2c_add_driver(&es8312_i2c_driver);
+}
+
+static void __exit es8312_exit(void)
+{
+	return i2c_del_driver(&es8312_i2c_driver);
+}
+
+module_init(es8312_init);
+module_exit(es8312_exit);
+
+MODULE_DESCRIPTION("ASoC es8312 driver");
+MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
+MODULE_LICENSE("GPL");
+