summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorldq <david.li@rock-chips.com>2017-10-17 18:03:33 +0800
committerHuang, Tao <huangtao@rock-chips.com>2017-10-20 15:30:18 +0800
commit71d4a8ffec5bb1b5501c10eedd8058207ed09e7e (patch)
treebfd6cb40ce1e5d93469de10635c934e83740a728
parentf08254d1242ff4935b685547639c91c930234bbd (diff)
ASoC: Add driver for codec es8396
Change-Id: I45b01dfa336e88b9eb74e65739fa0ed863c2da90 Signed-off-by: Li Dongqiang <david.li@rock-chips.com>
-rw-r--r--sound/soc/codecs/Kconfig4
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/es8396.c3370
-rw-r--r--sound/soc/codecs/es8396.h359
4 files changed, 3735 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 3792cf494451..6b50b998f1d3 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -68,6 +68,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ES8323 if I2C
select SND_SOC_ES8328_SPI if SPI_MASTER
select SND_SOC_ES8328_I2C if I2C
+ select SND_SOC_ES8396 if I2C
select SND_SOC_GTM601
select SND_SOC_ICS43432
select SND_SOC_ISABELLE if I2C
@@ -494,6 +495,9 @@ config SND_SOC_ES8328_SPI
tristate
select SND_SOC_ES8328
+config SND_SOC_ES8396
+ tristate "Everest Semi ES8396 CODEC"
+
config SND_SOC_GTM601
tristate 'GTM601 UMTS modem audio codec'
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index aff1c31eab05..62e51942a7b0 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -62,6 +62,7 @@ snd-soc-es8323-objs := es8323.o
snd-soc-es8328-objs := es8328.o
snd-soc-es8328-i2c-objs := es8328-i2c.o
snd-soc-es8328-spi-objs := es8328-spi.o
+snd-soc-es8396-objs := es8396.o
snd-soc-gtm601-objs := gtm601.o
snd-soc-ics43432-objs := ics43432.o
snd-soc-isabelle-objs := isabelle.o
@@ -266,6 +267,7 @@ obj-$(CONFIG_SND_SOC_ES8323) += snd-soc-es8323.o
obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o
obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
+obj-$(CONFIG_SND_SOC_ES8396) += snd-soc-es8396.o
obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o
obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o
obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
diff --git a/sound/soc/codecs/es8396.c b/sound/soc/codecs/es8396.c
new file mode 100644
index 000000000000..afb48d7c2516
--- /dev/null
+++ b/sound/soc/codecs/es8396.c
@@ -0,0 +1,3370 @@
+/*
+ * es8396.c -- ES8396 ALSA SoC Audio Codec
+ *
+ * Copyright (C) 2014 Everest Semiconductor Co., Ltd
+ *
+ * Authors: David Yang(yangxiaohua@everest-semi.com)
+ *
+ *
+ * Based on alc5632.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 <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include "es8396.h"
+
+#define INVALID_GPIO -1
+
+static struct snd_soc_codec *tron_codec;
+static int es8396_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level);
+
+/*
+ * ES8396 register cache
+ */
+static struct reg_default es8396_reg_defaults[] = {
+ {0x00, 0x00},
+ {0x01, 0x00},
+ {0x02, 0x80},
+ {0x03, 0x00},
+ {0x04, 0x00},
+ {0x05, 0x00},
+ {0x06, 0x00},
+ {0x07, 0x00},
+ {0x08, 0x50},
+ {0x09, 0x04},
+ {0x0a, 0x00},
+ {0x0b, 0x20},
+ {0x0c, 0x20},
+ {0x0d, 0x00},
+ {0x0e, 0x00},
+ {0x0f, 0x00},
+
+ {0x10, 0x00},
+ {0x11, 0x00},
+ {0x12, 0x00},
+ {0x13, 0x00},
+ {0x14, 0x00},
+ {0x15, 0x00},
+ {0x16, 0x00},
+ {0x17, 0x00},
+ {0x18, 0x00},
+ {0x19, 0x00},
+ {0x1a, 0x00},
+ {0x1b, 0x00},
+ {0x1c, 0x00},
+ {0x1d, 0x00},
+ {0x1e, 0x00},
+ {0x1f, 0x00},
+
+ {0x20, 0x00},
+ {0x21, 0x00},
+ {0x22, 0x00},
+ {0x23, 0x00},
+ {0x24, 0x00},
+ {0x25, 0x00},
+ {0x26, 0x11},
+ {0x27, 0x00},
+ {0x28, 0x00},
+ {0x29, 0x04},
+ {0x2a, 0x00},
+ {0x2b, 0x33},
+ {0x2c, 0x00},
+ {0x2d, 0x04},
+ {0x2e, 0x00},
+ {0x2f, 0x11},
+
+ {0x30, 0x00},
+ {0x31, 0x04},
+ {0x32, 0x00},
+ {0x33, 0x11},
+ {0x34, 0x00},
+ {0x35, 0x04},
+ {0x36, 0x00},
+ {0x37, 0x11},
+ {0x38, 0x00},
+ {0x39, 0x04},
+ {0x3a, 0x44},
+ {0x3b, 0x00},
+ {0x3c, 0x20},
+ {0x3d, 0x00},
+ {0x3e, 0x00},
+ {0x3f, 0x00},
+
+ {0x40, 0x08},
+ {0x41, 0x88},
+ {0x42, 0x20},
+ {0x43, 0x82},
+ {0x44, 0x03},
+ {0x45, 0xa0},
+ {0x46, 0x00},
+ {0x47, 0x00},
+ {0x48, 0x01},
+ {0x49, 0x01},
+ {0x4a, 0x80},
+ {0x4b, 0x80},
+ {0x4c, 0x80},
+ {0x4d, 0x80},
+ {0x4e, 0x84},
+ {0x4f, 0x84},
+
+ {0x50, 0x84},
+ {0x51, 0x84},
+ {0x52, 0xc0},
+ {0x53, 0x80},
+ {0x54, 0x00},
+ {0x55, 0x00},
+ {0x56, 0xc0},
+ {0x57, 0xc0},
+ {0x58, 0x0b},
+ {0x59, 0x32},
+ {0x5a, 0x00},
+ {0x5b, 0x1f},
+ {0x5c, 0xc0},
+ {0x5d, 0x00},
+ {0x5e, 0xfc},
+ {0x5f, 0x02},
+
+ {0x60, 0x00},
+ {0x61, 0x00},
+ {0x62, 0x00},
+ {0x63, 0x00},
+ {0x64, 0x00},
+ {0x65, 0x00},
+ {0x66, 0x80},
+ {0x67, 0x00},
+ {0x68, 0x00},
+ {0x69, 0x00},
+ {0x6a, 0xc0},
+ {0x6b, 0xc0},
+ {0x6c, 0x00},
+ {0x6d, 0x00},
+ {0x6e, 0xc8},
+ {0x6f, 0x00},
+
+ {0x70, 0xd3},
+ {0x71, 0x90},
+ {0x72, 0x00},
+ {0x73, 0x00},
+ {0x74, 0x88},
+ {0x75, 0xc1},
+ {0x76, 0x00},
+ {0x77, 0x00},
+ {0x7a, 0x00},
+ {0x7b, 0x00},
+};
+
+static u8 es8396_equalizer_lpf_bt_incall[] = {
+ 0x6D, 0x27, 0x64, 0x09, 0x4C, 0xA3, 0x53, 0x07, 0x6D, 0x27, 0x64, 0x09,
+ 0x8D, 0xE5, 0x23, 0x00, 0x2A, 0xA3, 0x4A, 0x22,
+ 0x6D, 0x27, 0x64, 0x09, 0x4C, 0xA3, 0x53, 0x07, 0x6D, 0x27, 0x64, 0x09,
+ 0x8D, 0xE5, 0x23, 0x00, 0x2A, 0xA3, 0x4A, 0x22,
+ 0x6D, 0x27, 0x64, 0x09, 0x4C, 0xA3, 0x53, 0x07, 0x6D, 0x27, 0x64, 0x09,
+ 0x8D, 0xE5, 0x23, 0x00, 0x2A, 0xA3, 0x4A, 0x22,
+};
+
+struct sp_config {
+ u8 spc, mmcc, spfs;
+ u32 srate;
+ u8 lrcdiv;
+ u8 sclkdiv;
+};
+
+/* codec private data */
+struct es8396_private {
+ struct sp_config config[3];
+ struct regmap *regmap;
+ u8 sysclk[3];
+ u32 mclk[3];
+ struct clk *mclk_clock;
+
+ /* platform dependant DVDD voltage configuration */
+ u8 dvdd_pwr_vol;
+
+ /* platform dependant CLASS D Mono mode configuration */
+ bool spkmono;
+ /* platform dependant earpiece mode configuration */
+ bool earpiece;
+ /* platform dependant monon/p differential mode configuration */
+ bool monoin_differential;
+ /* platform dependant lout/rout differential mode configuration */
+ bool lno_differential;
+
+ /* platform dependant analog ldo level configuration */
+ u8 ana_ldo_lvl;
+ /* platform dependant speaker ldo level configuration */
+ u8 spk_ldo_lvl;
+ /* platform dependant mic bias voltage configuration */
+ u8 mic_bias_lvl;
+ u8 dmic_amic;
+
+ bool jackdet_enable;
+
+ u8 gpio_int_pol;
+
+ int shutdwn_delay;
+ int pon_delay;
+ int spk_ctl_gpio;
+ bool spk_gpio_level;
+ int lineout_ctl_gpio;
+ bool lineout_gpio_level;
+
+ bool calibrate;
+ u8 output_device_selected;
+ u8 aif1_select;
+ u8 aif2_select;
+ /*
+ * Add a delay work-quenue, to debug DC calibration
+ */
+ struct mutex adc_depop_mlock;
+ struct delayed_work adc_depop_work;
+
+ /* for playback pop noise */
+ struct mutex pcm_depop_mlock;
+ struct delayed_work pcm_pop_work;
+ /* for playback pop noise */
+ struct mutex pcm_shutdown_depop_mlock;
+ struct delayed_work pcm_shutdown_depop_work;
+
+ /* for voice pop noise */
+ struct mutex voice_depop_mlock;
+ struct delayed_work voice_pop_work;
+ /* for voice pop noise */
+ struct mutex voice_shutdown_depop_mlock;
+ struct delayed_work voice_shutdown_depop_work;
+
+ /* for hp calibration */
+ struct mutex init_cali_mlock;
+ struct delayed_work init_cali_work;
+ int pcm_pop_work_retry;
+};
+
+static bool es8396_valid_micbias(u8 micbias)
+{
+ switch (micbias) {
+ case MICBIAS_3V:
+ case MICBIAS_2_8V:
+ case MICBIAS_2_5V:
+ case MICBIAS_2_3V:
+ case MICBIAS_2V:
+ case MICBIAS_1_5V:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static bool es8396_valid_analdo(u8 ldolvl)
+{
+ switch (ldolvl) {
+ case ANA_LDO_3V:
+ case ANA_LDO_2_9V:
+ case ANA_LDO_2_8V:
+ case ANA_LDO_2_7V:
+ case ANA_LDO_2_4V:
+ case ANA_LDO_2_3V:
+ case ANA_LDO_2_2V:
+ case ANA_LDO_2_1V:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static bool es8396_valid_spkldo(u8 ldolvl)
+{
+ switch (ldolvl) {
+ case SPK_LDO_3_3V:
+ case SPK_LDO_3_2V:
+ case SPK_LDO_3V:
+ case SPK_LDO_2_9V:
+ case SPK_LDO_2_8V:
+ case SPK_LDO_2_6V:
+ case SPK_LDO_2_5V:
+ case SPK_LDO_2_4V:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/*
+static int es8396_volatile_register(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ switch (reg) {
+ case ES8396_SHARED_ADDR_REG1D:
+ case ES8396_SHARED_DATA_REG1E:
+ case ES8396_GPIO_STA_REG17:
+ case ES8396_CPHP_HPL_ICAL_REG3E:
+ case ES8396_CPHP_HPR_ICAL_REG3F:
+ case ES8396_RESET_REG00:
+ case ES8396_PLL_CTRL_1_REG02:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int es8396_readable_register(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ if (reg < 0x80)
+ return true;
+
+ return false;
+}
+*/
+
+static void pcm_shutdown_depop_events(struct work_struct *work)
+{
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(tron_codec);
+
+ mutex_lock(&es8396->pcm_shutdown_depop_mlock);
+ snd_soc_update_bits(tron_codec, ES8396_SDP1_IN_FMT_REG1F, 0x40,
+ 0x40);
+ es8396->aif1_select &= 0xfe;
+ mutex_unlock(&es8396->pcm_shutdown_depop_mlock);
+}
+
+static void voice_shutdown_depop_events(struct work_struct *work)
+{
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(tron_codec);
+
+ mutex_lock(&es8396->voice_shutdown_depop_mlock);
+ snd_soc_update_bits(tron_codec, ES8396_SDP2_IN_FMT_REG22,
+ 0x7F, 0x53);
+ es8396->aif2_select &= 0xfe;
+ if ((es8396->aif1_select) != 0) {
+ snd_soc_write(tron_codec, 0x1A, 0x00);
+ snd_soc_write(tron_codec, 0x67, 0x00);
+ snd_soc_write(tron_codec, 0x69, 0x00);
+ snd_soc_write(tron_codec, 0x66, 0x00);
+ }
+ mutex_unlock(&es8396->voice_shutdown_depop_mlock);
+}
+
+static void init_cali_work_events(struct work_struct *work)
+{
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(tron_codec);
+
+ mutex_lock(&es8396->init_cali_mlock);
+ pr_debug("init_cali_work_events\n");
+ if ((es8396->pcm_pop_work_retry) > 0) {
+ es8396->pcm_pop_work_retry--;
+ pr_debug("Enter into %s %d\n", __func__, __LINE__);
+ snd_soc_write(tron_codec, ES8396_DAC_OFFSET_CALI_REG6F, 0x83);
+ if (es8396->pcm_pop_work_retry) {
+ schedule_delayed_work(&es8396->init_cali_work,
+ msecs_to_jiffies(100));
+ }
+ }
+ snd_soc_write(tron_codec, ES8396_ADC_ANALOG_CTRL_REG5E, 0x3C);
+
+ /* use line out */
+ msleep(100);
+ snd_soc_write(tron_codec, 0x4E, 0x80);
+ snd_soc_write(tron_codec, 0x4F, 0x81);
+ snd_soc_write(tron_codec, 0x4A, 0x60);
+ snd_soc_write(tron_codec, 0x4B, 0x60);
+
+ mutex_unlock(&es8396->init_cali_mlock);
+}
+
+static void voice_pop_work_events(struct work_struct *work)
+{
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(tron_codec);
+ int i;
+
+ mutex_lock(&es8396->voice_depop_mlock);
+ pr_debug("voice_pop_work_events\n");
+ /*
+ * set the clock source to pll out
+ * set divider for voice playback
+ * set Equalizer
+ * set DAC source from equalizer
+ */
+ snd_soc_update_bits(tron_codec, ES8396_SDP2_IN_FMT_REG22,
+ 0x3F, 0x13);
+ snd_soc_update_bits(tron_codec, ES8396_SDP2_OUT_FMT_REG23,
+ 0x7F, 0x33);
+ /* use line out */
+ snd_soc_write(tron_codec, 0x4E, 0x80);
+ snd_soc_write(tron_codec, 0x4F, 0x81);
+ snd_soc_write(tron_codec, 0x4A, 0x60);
+ snd_soc_write(tron_codec, 0x4B, 0x60);
+ snd_soc_write(tron_codec, 0x1A, 0x40); /* Enable HPOUT */
+
+ /* unmute dac */
+ snd_soc_write(tron_codec, 0x66, 0x00);
+
+ for (i = 0; i < 120; i = i + 2) {
+ snd_soc_write(tron_codec, 0x6A, 120 - i);
+ snd_soc_write(tron_codec, 0x6B, 120 - i);
+ usleep_range(100, 200);
+ }
+
+ mutex_unlock(&es8396->voice_depop_mlock);
+}
+
+static void pcm_pop_work_events(struct work_struct *work)
+{
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(tron_codec);
+ int i;
+ mutex_lock(&es8396->pcm_depop_mlock);
+ pr_debug("pcm_pop_work_events\n");
+
+ snd_soc_write(tron_codec, ES8396_SYS_VMID_REF_REG71,
+ 0xFC);
+
+ /* use line out */
+ snd_soc_write(tron_codec, 0x4E, 0x80);
+ snd_soc_write(tron_codec, 0x4F, 0x81);
+ snd_soc_write(tron_codec, 0x4A, 0x60);
+ snd_soc_write(tron_codec, 0x4B, 0x60);
+ snd_soc_update_bits(tron_codec, ES8396_DAC_CSM_REG66,
+ 0x03, 0x00);
+ snd_soc_update_bits(tron_codec, ES8396_SDP1_IN_FMT_REG1F, 0x40,
+ 0x00);
+ for (i = 0; i < 120; i = i + 2) {
+ snd_soc_write(tron_codec, 0x6A, 120 - i);
+ snd_soc_write(tron_codec, 0x6B, 120 - i);
+ usleep_range(100, 200);
+ }
+ mutex_unlock(&es8396->pcm_depop_mlock);
+}
+
+/*********************************************************************
+ * to power on/off class d with min pop noise
+ *********************************************************************/
+static int classd_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ unsigned int regv1, regv2, lvl;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct es8396_private *priv = snd_soc_codec_get_drvdata(codec);
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(tron_codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU: /* prepare power up */
+ /* power up class d */
+ pr_debug("SND_SOC_DAPM_PRE_PMU = 0x%x\n", event);
+ /* read the clock configure */
+ regv1 = snd_soc_read(codec, ES8396_CLK_CTRL_REG08);
+ regv1 &= 0xcf;
+ /* enable class d clock */
+ snd_soc_write(codec, ES8396_CLK_CTRL_REG08, regv1);
+ /* dac csm startup, dac digital still on */
+ snd_soc_update_bits(codec, ES8396_DAC_CSM_REG66, 0xFE, 0x00);
+ /* dac analog power on */
+ snd_soc_update_bits(codec, ES8396_DAC_REF_PWR_CTRL_REG6E,
+ 0xff, 0x34);
+
+ regv2 = snd_soc_read(codec, ES8396_SPK_CTRL_1_REG3C);
+ /* set speaker ldo level */
+ if (es8396_valid_spkldo(priv->spk_ldo_lvl) == false) {
+ pr_err("speaker LDO Level error.\n");
+ return -EINVAL;
+ } else {
+ regv1 = regv2 & 0xD8;
+ lvl = priv->spk_ldo_lvl;
+ lvl &= 0x07;
+ regv1 |= lvl;
+ regv1 |= 0x10;
+ }
+ if (priv->spkmono == 1) { /* speaker in mono mode */
+ regv1 = regv1 | 0x40;
+ } else {
+ regv1 = regv1 & 0xbf;
+ }
+ snd_soc_write(codec, ES8396_SPK_CTRL_1_REG3C, regv1);
+
+ snd_soc_write(codec, ES8396_SPK_CTRL_2_REG3D, 0x10);
+
+ regv1 = snd_soc_read(codec, ES8396_SPK_MIXER_REG26);
+ /* clear pdnspkl_biasgen, clear pdnspkr_biasgen */
+ regv1 &= 0xee;
+ snd_soc_write(codec, ES8396_SPK_MIXER_REG26, regv1);
+ snd_soc_write(codec, ES8396_SPK_MIXER_VOL_REG28, 0x33);
+
+ snd_soc_write(codec, ES8396_SPK_CTRL_SRC_REG3A, 0xA9);
+ /* L&R DAC Vol=-6db */
+ snd_soc_write(codec, ES8396_DAC_LDAC_VOL_REG6A, 0x00);
+ snd_soc_write(codec, ES8396_DAC_RDAC_VOL_REG6B, 0x00);
+
+ regv1 = snd_soc_read(codec, ES8396_HP_MIXER_BOOST_REG2B);
+ regv1 &= 0xcc;
+ snd_soc_write(codec, ES8396_HP_MIXER_BOOST_REG2B, regv1);
+
+ regv1 = snd_soc_read(codec, ES8396_CPHP_CTRL_3_REG44);
+ regv1 &= 0xcc;
+ snd_soc_write(codec, ES8396_CPHP_CTRL_3_REG44, regv1);
+
+ regv1 = snd_soc_read(codec, ES8396_CPHP_CTRL_1_REG42);
+ regv1 &= 0xdf;
+ snd_soc_write(codec, ES8396_CPHP_CTRL_1_REG42, regv1);
+
+ regv1 = snd_soc_read(codec, ES8396_CPHP_CTRL_2_REG43);
+ regv1 &= 0x7f;
+ snd_soc_write(codec, ES8396_CPHP_CTRL_2_REG43, regv1);
+ es8396->output_device_selected = 0;
+ break;
+ case SND_SOC_DAPM_POST_PMU: /* after power up */
+ pr_debug("SND_SOC_DAPM_POST_PMU = 0x%x\n", event);
+ schedule_delayed_work(&es8396->pcm_pop_work,
+ msecs_to_jiffies(50));
+ break;
+ case SND_SOC_DAPM_PRE_PMD: /* prepare power down */
+ pr_debug("SND_SOC_DAPM_PRE_PMD = 0x%x\n", event);
+ /* read the clock configure */
+ regv1 = snd_soc_read(codec, ES8396_CLK_CTRL_REG08);
+ regv1 |= 0x10;
+ /* stop class d clock */
+ snd_soc_write(codec, ES8396_CLK_CTRL_REG08, regv1);
+ /* dac csm startup, dac digital still on */
+ /* snd_soc_update_bits(w->codec, ES8396_DAC_CSM_REG66,
+ 0x01, 0x01); */
+ regv1 = snd_soc_read(codec, ES8396_SPK_EN_VOL_REG3B);
+ regv1 &= 0x77;
+ /* clear enspk_l,enspk_r */
+ snd_soc_write(codec, ES8396_SPK_EN_VOL_REG3B, regv1);
+
+ regv1 = snd_soc_read(codec, ES8396_SPK_CTRL_SRC_REG3A);
+ regv1 |= 0x44; /* set pdnspkl_biasgen, set pdnspkr_biasgen */
+ snd_soc_write(codec, ES8396_SPK_CTRL_SRC_REG3A, regv1);
+ regv1 = snd_soc_read(codec, ES8396_SPK_MIXER_REG26);
+ /* clear pdnspkl_biasgen, clear pdnspkr_biasgen */
+ regv1 |= 0x11;
+ snd_soc_write(codec, ES8396_SPK_MIXER_REG26, regv1);
+ snd_soc_update_bits(codec, ES8396_SPK_CTRL_1_REG3C, 0x20,
+ 0x20);
+ break;
+ case SND_SOC_DAPM_POST_PMD: /* after power down */
+ pr_debug("SND_SOC_DAPM_POST_PMD = 0x%x\n", event);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int micbias_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 es8396_private *es8396 = snd_soc_codec_get_drvdata(codec);
+ unsigned int regv;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (es8396_valid_micbias(es8396->mic_bias_lvl) == false) {
+ pr_err("MIC BIAS Level error.\n");
+ return -EINVAL;
+ } else {
+ regv = es8396->mic_bias_lvl;
+ regv &= 0x07;
+ regv = (regv << 4) | 0x08;
+ /* enable micbias1 */
+ snd_soc_write(codec, ES8396_SYS_MICBIAS_CTRL_REG74,
+ regv);
+ }
+ regv = snd_soc_read(codec, ES8396_ALRCK_GPIO_SEL_REG15);
+ if (es8396->dmic_amic == MIC_DMIC) {
+ regv &= 0xf0; /* enable DMIC CLK */
+ regv |= 0x0A;
+ } else {
+ regv &= 0xf0; /* disable DMIC CLK */
+ }
+ snd_soc_write(codec, ES8396_ALRCK_GPIO_SEL_REG15, regv);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regv = snd_soc_read(codec, ES8396_ALRCK_GPIO_SEL_REG15);
+ regv &= 0xf0; /* disable DMIC CLK */
+ snd_soc_write(codec, ES8396_ALRCK_GPIO_SEL_REG15, regv);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void adc_depop_work_events(struct work_struct *work)
+{
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(tron_codec);
+
+ pr_debug("adc_depop_work_events\n");
+ mutex_lock(&es8396->adc_depop_mlock);
+ snd_soc_update_bits(tron_codec, ES8396_SDP1_OUT_FMT_REG20, 0x40, 0x00);
+ mutex_unlock(&es8396->adc_depop_mlock);
+}
+
+static int adc_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ unsigned int regv;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("Enter into %s %d\n", __func__, __LINE__);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ pr_debug("Enter into SND_SOC_DAPM_PRE_PMU %s %d\n", __func__,
+ __LINE__);
+ snd_soc_update_bits(codec, ES8396_SDP1_OUT_FMT_REG20, 0x40,
+ 0x40);
+ /* set adc alc */
+ snd_soc_write(codec, ES8396_ADC_ALC_CTRL_1_REG58, 0xC6);
+ snd_soc_write(codec, ES8396_ADC_ALC_CTRL_2_REG59, 0x12);
+ snd_soc_write(codec, ES8396_ADC_ALC_CTRL_4_REG5B, 0x04);
+ snd_soc_write(codec, ES8396_ADC_ALC_CTRL_5_REG5C, 0xC8);
+ snd_soc_write(codec, ES8396_ADC_ALC_CTRL_6_REG5D, 0x11);
+ snd_soc_write(codec, ES8396_ADC_ANALOG_CTRL_REG5E, 0x0);
+ /* Enable MIC BOOST */
+ snd_soc_write(codec, ES8396_SYS_MIC_IBIAS_EN_REG75, 0x02);
+
+ /* axMixer Gain boost */
+ regv = snd_soc_read(codec, ES8396_AX_MIXER_BOOST_REG2F);
+ regv |= 0x88;
+ snd_soc_write(codec, ES8396_AX_MIXER_BOOST_REG2F, regv);
+ /* axmixer vol = +12db */
+ snd_soc_write(codec, ES8396_AX_MIXER_VOL_REG30, 0xaa);
+ /* axmixer high driver capacility */
+ snd_soc_write(codec, ES8396_AX_MIXER_REF_LP_REG31, 0x02);
+
+ /* MNMixer Gain boost */
+ regv = snd_soc_read(codec, ES8396_MN_MIXER_BOOST_REG37);
+ regv |= 0x88;
+ snd_soc_write(codec, ES8396_MN_MIXER_BOOST_REG37, regv);
+ /* mnmixer vol = +12db */
+ snd_soc_write(codec, ES8396_MN_MIXER_VOL_REG38, 0x44);
+ /* mnmixer high driver capacility */
+ snd_soc_write(codec, ES8396_MN_MIXER_REF_LP_REG39, 0x02);
+
+ msleep(200);
+ /* ADC STM and Digital Startup, ADC DS Mode */
+ snd_soc_write(codec, ES8396_ADC_CSM_REG53, 0x00);
+ /* force adc stm to normal */
+ snd_soc_write(codec, ES8396_ADC_FORCE_REG77, 0x40);
+ snd_soc_write(codec, ES8396_ADC_FORCE_REG77, 0x0);
+ /* ADC Volume =0db */
+ snd_soc_write(codec, ES8396_ADC_LADC_VOL_REG56, 0x0);
+ snd_soc_write(codec, ES8396_ADC_RADC_VOL_REG57, 0x0);
+ snd_soc_write(codec, ES8396_ADC_CLK_DIV_REG09, 0x04);
+
+ schedule_delayed_work(&es8396->adc_depop_work,
+ msecs_to_jiffies(150));
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ pr_debug("Enter into SND_SOC_DAPM_PRE_PMD %s %d\n", __func__,
+ __LINE__);
+ snd_soc_write(codec, ES8396_ADC_CSM_REG53, 0x20);
+ snd_soc_write(codec, ES8396_ADC_CLK_DIV_REG09, 0x04);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*********************************************************************
+ * to power on/off headphone with min pop noise
+ ********************************************************************/
+static int hpamp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ unsigned int regv;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("Enter into %s %d\n", __func__, __LINE__);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ pr_debug("Enter into %s %d, event = SND_SOC_DAPM_PRE_PMU\n",
+ __func__, __LINE__);
+ es8396->output_device_selected = 1;
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ pr_debug("Enter into %s %d, event = SND_SOC_DAPM_POST_PMU\n",
+ __func__, __LINE__);
+ schedule_delayed_work(&es8396->pcm_pop_work,
+ msecs_to_jiffies(50));
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ pr_debug("Enter into %s %d, event = SND_SOC_DAPM_PRE_PMD\n",
+ __func__, __LINE__);
+ /* dac analog power down */
+ snd_soc_update_bits(codec, ES8396_DAC_CSM_REG66, 0x42, 0x00);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ pr_debug("Enter into %s %d, event = SND_SOC_DAPM_POST_PMD\n",
+ __func__, __LINE__);
+ /* dac analog power down */
+ snd_soc_update_bits(codec, ES8396_DAC_CSM_REG66, 0x40, 0x40);
+ /* dac analog power down */
+ snd_soc_update_bits(codec, ES8396_DAC_REF_PWR_CTRL_REG6E,
+ 0xC0, 0xC0);
+ /* read the clock configure */
+ regv = snd_soc_read(codec, ES8396_CLK_CTRL_REG08);
+ regv |= 0x20;
+ /* stop charge pump clock */
+ snd_soc_write(codec, ES8396_CLK_CTRL_REG08, regv);
+
+ regv = snd_soc_read(codec, ES8396_HP_MIXER_BOOST_REG2B);
+ regv |= 0x11;
+ snd_soc_write(codec, ES8396_HP_MIXER_BOOST_REG2B, regv);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+/*
+ * ES8396 Controls
+ */
+static const DECLARE_TLV_DB_RANGE(mixvol_tlv,
+ 0, 4, TLV_DB_SCALE_ITEM(-1200, 150, 0),
+ 8, 11, TLV_DB_SCALE_ITEM(-600, 150, 0));
+static const DECLARE_TLV_DB_RANGE(boost_tlv,
+ 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+ 1, 3, TLV_DB_SCALE_ITEM(2000, 0, 0));
+
+/* -34.5db min scale, 1.5db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(vol_tlv, -600, 150, 0);
+/* -34.5db min scale, 1.5db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(spk_vol_tlv, 0, 150, 0);
+/* -46.5db min scale, 1.5db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(hp_tlv, -4800, 1200, 0);
+/* -16.5db min scale, 1.5db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -9600, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(lineout_tlv, -1200, 1200, 0);
+
+/* 0db min scale, 6 db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0);
+/* 0db min scalem 0.75db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(vdac_tlv, -9600, 50, 0);
+
+static const char *const alc_func_txt[] = { "Off", "LOn", "ROn", "StereoOn" };
+
+static const struct soc_enum alc_func =
+SOC_ENUM_SINGLE(ES8396_ADC_ALC_CTRL_1_REG58, 6, 4, alc_func_txt);
+
+/*
+ *define the line in,mic in, phone in ,and aif1-2 in volume/switch
+ */
+static const struct snd_kcontrol_new es8396_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("DAC Playback Volume",
+ ES8396_DAC_LDAC_VOL_REG6A, ES8396_DAC_RDAC_VOL_REG6B,
+ 0, 127, 1, vdac_tlv),
+ SOC_DOUBLE_TLV("MNIN MIXER Volume",
+ ES8396_MN_MIXER_VOL_REG38, 4, 0, 3, 1, mixvol_tlv),
+
+ SOC_DOUBLE_TLV("LIN MIXER Volume",
+ ES8396_LN_MIXER_VOL_REG34, 4, 0, 4, 0, mixvol_tlv),
+
+ SOC_DOUBLE_TLV("AXIN MIXER Volume",
+ ES8396_AX_MIXER_VOL_REG30, 4, 0, 4, 0, mixvol_tlv),
+ SOC_DOUBLE_TLV("Mic Boost Volume",
+ ES8396_ADC_MICBOOST_REG60, 4, 0, 3, 0, boost_tlv),
+
+ SOC_DOUBLE_R_TLV("ADC Capture Volume",
+ ES8396_ADC_LADC_VOL_REG56, ES8396_ADC_RADC_VOL_REG57,
+ 0, 127, 1, adc_rec_tlv),
+
+ SOC_SINGLE_TLV("Speakerl Playback Volume",
+ ES8396_SPK_EN_VOL_REG3B, 4, 7, 0, spk_vol_tlv),
+ SOC_SINGLE_TLV("Speakerr Playback Volume",
+ ES8396_SPK_EN_VOL_REG3B, 0, 7, 0, spk_vol_tlv),
+
+ SOC_SINGLE_TLV("Headphonel Playback Volume",
+ ES8396_CPHP_ICAL_VOL_REG41, 4, 3, 1, hp_tlv),
+ SOC_SINGLE_TLV("Headphoner Playback Volume",
+ ES8396_CPHP_ICAL_VOL_REG41, 0, 3, 1, hp_tlv),
+ /*
+ * lineout playback volume
+ */
+ SOC_SINGLE_TLV("Lineoutp Playback Volume",
+ ES8396_LNOUT_LO1_GAIN_CTRL_REG4E, 5, 1, 1, lineout_tlv),
+ SOC_SINGLE_TLV("Lineoutn Playback Volume",
+ ES8396_LNOUT_RO1_GAIN_CTRL_REG4F, 5, 1, 1, lineout_tlv),
+ /*
+ * monoout playback volume
+ */
+ SOC_SINGLE_TLV("Monooutp Playback Volume",
+ ES8396_MONOHP_P_BOOST_MUTE_REG48, 3, 1, 1, lineout_tlv),
+ SOC_SINGLE_TLV("Monooutn Playback Volume",
+ ES8396_MONOHP_N_BOOST_MUTE_REG49, 3, 1, 1, lineout_tlv),
+ SOC_ENUM("ALC Capture Function", alc_func),
+};
+
+/*
+ * DAPM Controls
+ */
+static const struct snd_kcontrol_new es8396_dac_controls =
+SOC_DAPM_SINGLE("Switch", ES8396_DAC_CSM_REG66, 3, 1, 1);
+
+static const struct snd_kcontrol_new hp_amp_ctl =
+SOC_DAPM_SINGLE("Switch", ES8396_CP_CLK_DIV_REG0B, 1, 1, 1);
+
+static const struct snd_kcontrol_new es8396_hpl_mixer_controls[] = {
+ SOC_DAPM_SINGLE("LNMUX2HPMIX_L Switch", ES8396_HP_MIXER_REG2A, 6, 1, 0),
+ SOC_DAPM_SINGLE("AXMUX2HPMIX_L Switch", ES8396_HP_MIXER_REG2A, 5, 1, 0),
+ SOC_DAPM_SINGLE("DACL2HPMIX Switch", ES8396_HP_MIXER_REF_LP_REG2D,
+ 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new es8396_hpr_mixer_controls[] = {
+ SOC_DAPM_SINGLE("LNMUX2HPMIX_R Switch", ES8396_HP_MIXER_REG2A, 2, 1, 0),
+ SOC_DAPM_SINGLE("AXMUX2HPMIX_R Switch", ES8396_HP_MIXER_REG2A, 1, 1, 0),
+ SOC_DAPM_SINGLE("DACR2HPMIX Switch", ES8396_HP_MIXER_REF_LP_REG2D,
+ 4, 1, 0),
+};
+
+/*
+ * Only used mono out p mixer for differential output
+ */
+static const struct snd_kcontrol_new es8396_monoP_mixer_controls[] = {
+ SOC_DAPM_SINGLE("LHPMIX2MNMIXP Switch", ES8396_MONOHP_P_MIXER_REG47, 7,
+ 1, 0),
+ SOC_DAPM_SINGLE("RHPMIX2MNOMIXP Switch", ES8396_MONOHP_P_MIXER_REG47, 6,
+ 1, 0),
+ SOC_DAPM_SINGLE("RMNMIX2MNOMIXP Switch", ES8396_MONOHP_P_MIXER_REG47, 5,
+ 1, 0),
+ SOC_DAPM_SINGLE("RAXMIX2MNOMIXP Switch",
+ ES8396_MONOHP_P_MIXER_REG47, 4, 1, 0),
+ SOC_DAPM_SINGLE("LLNMIX2MNOMIXP Switch",
+ ES8396_MONOHP_P_MIXER_REG47, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new es8396_monoN_mixer_controls[] = {
+ SOC_DAPM_SINGLE("LMNMIX2MNMIXN Switch", ES8396_MONOHP_N_MIXER_REG46, 7,
+ 1, 0),
+ SOC_DAPM_SINGLE("RHPMIX2MNOMIXN Switch", ES8396_MONOHP_N_MIXER_REG46, 6,
+ 1, 0),
+ SOC_DAPM_SINGLE("MOPINV2MNOMIXN Switch", ES8396_MONOHP_N_MIXER_REG46, 5,
+ 1, 0),
+ SOC_DAPM_SINGLE("LLNMIX2MNOMIXN Switch",
+ ES8396_MONOHP_N_MIXER_REG46, 4, 1, 0),
+ SOC_DAPM_SINGLE("LAXMIX2MNOMIXN Switch",
+ ES8396_MONOHP_N_MIXER_REG46, 3, 1, 0),
+};
+
+/*
+ * define the stereo class d speaker mixer
+ */
+static const struct snd_kcontrol_new es8396_speaker_lmixer_controls[] = {
+ SOC_DAPM_SINGLE("LLNMUX2SPKMIX Switch", ES8396_SPK_MIXER_REG26, 6, 1,
+ 0),
+ SOC_DAPM_SINGLE("LAXMUX2SPKMIX Switch", ES8396_SPK_MIXER_REG26, 5, 1,
+ 0),
+ SOC_DAPM_SINGLE("LDAC2SPKMIX Switch", ES8396_SPK_MIXER_REG26, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new es8396_speaker_rmixer_controls[] = {
+ SOC_DAPM_SINGLE("RLNMUX2SPKMIX Switch", ES8396_SPK_MIXER_REG26, 2, 1,
+ 0),
+ SOC_DAPM_SINGLE("RAXMUX2SPKMIX Switch", ES8396_SPK_MIXER_REG26, 1, 1,
+ 0),
+ SOC_DAPM_SINGLE("RDAC2SPKMIX Switch", ES8396_SPK_MIXER_REG26, 3, 1, 0),
+};
+
+/*
+ * Only used line out1 p mixer for differential output
+ */
+static const struct snd_kcontrol_new es8396_lout1_mixer_controls[] = {
+ SOC_DAPM_SINGLE("LDAC2LO1MIXP Switch", SND_SOC_NOPM,
+ 5, 1, 0),
+ SOC_DAPM_SINGLE("LAXMIX2LO1MIXP Switch",
+ ES8396_LNOUT_LO1EN_LO1MIX_REG4A, 4, 1, 0),
+ SOC_DAPM_SINGLE("LLNMIX2LO1MIXP Switch",
+ ES8396_LNOUT_LO1EN_LO1MIX_REG4A, 3, 1, 0),
+ SOC_DAPM_SINGLE("LMNMIX2LO1MIXP Switch",
+ ES8396_LNOUT_LO1EN_LO1MIX_REG4A, 2, 1, 0),
+ SOC_DAPM_SINGLE("RO1INV2LO1MIXP Switch",
+ ES8396_LNOUT_LO1EN_LO1MIX_REG4A, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new es8396_rout1_mixer_controls[] = {
+ SOC_DAPM_SINGLE("RDAC2RO1MIXN Switch", SND_SOC_NOPM,
+ 5, 1, 0),
+ SOC_DAPM_SINGLE("RAXMIX2RO1MIXN Switch",
+ ES8396_LNOUT_RO1EN_RO1MIX_REG4B, 4, 1, 0),
+ SOC_DAPM_SINGLE("RLNMIX2RO1MIXN Switch",
+ ES8396_LNOUT_RO1EN_RO1MIX_REG4B, 3, 1, 0),
+ SOC_DAPM_SINGLE("RMNMIX2RO1MIXN Switch",
+ ES8396_LNOUT_RO1EN_RO1MIX_REG4B, 2, 1, 0),
+ SOC_DAPM_SINGLE("LO1INV2RO1MIXN Switch",
+ ES8396_LNOUT_RO1EN_RO1MIX_REG4B, 1, 1, 0),
+};
+
+/*
+ *left LNMIX mixer
+ */
+static const struct snd_kcontrol_new es8396_lnmixL_mixer_controls[] = {
+ SOC_DAPM_SINGLE("AINL2LLNMIX Switch", ES8396_LN_MIXER_REG32, 7, 1, 0),
+ SOC_DAPM_SINGLE("LLNMUX2LLNMIX Switch", ES8396_LN_MIXER_REG32, 6, 1, 0),
+ SOC_DAPM_SINGLE("MIC1P2LLNMIX Switch", ES8396_LN_MIXER_REG32, 5, 1, 0),
+ SOC_DAPM_SINGLE("PMICDSE2LLNMIX Switch", ES8396_LN_MIXER_REG32, 4, 1,
+ 0),
+};
+
+/*
+ *right LNMIX mixer
+ */
+static const struct snd_kcontrol_new es8396_lnmixR_mixer_controls[] = {
+ SOC_DAPM_SINGLE("AINR2RLNMIX Switch", ES8396_LN_MIXER_REG32, 3, 1, 0),
+ SOC_DAPM_SINGLE("RLNMUX2RLNMIX Switch", ES8396_LN_MIXER_REG32, 2, 1, 0),
+ SOC_DAPM_SINGLE("MIC1N2LLNMIX Switch", ES8396_LN_MIXER_REG32, 1, 1, 0),
+ SOC_DAPM_SINGLE("NMICDSE2RLNMIX Switch", ES8396_LN_MIXER_REG32, 0, 1,
+ 0),
+};
+
+/*
+ *left AXMIX mixer
+ */
+static const struct snd_kcontrol_new es8396_axmixL_mixer_controls[] = {
+ SOC_DAPM_SINGLE("LAXMUX2LAXMIX Switch", ES8396_AX_MIXER_REG2E, 7, 1, 0),
+ SOC_DAPM_SINGLE("MONOP2LAXMIX Switch", ES8396_AX_MIXER_REG2E, 6, 1, 0),
+ SOC_DAPM_SINGLE("MIC2P2LAXMIX Switch", ES8396_AX_MIXER_REG2E, 5, 1, 0),
+ SOC_DAPM_SINGLE("PMICDSE2LAXMIX Switch", ES8396_AX_MIXER_REG2E, 4, 1,
+ 0),
+};
+
+/*
+ *right AXMIX mixer
+ */
+static const struct snd_kcontrol_new es8396_axmixR_mixer_controls[] = {
+ SOC_DAPM_SINGLE("RAXMUX2RAXMIX Switch", ES8396_AX_MIXER_REG2E, 3, 1, 0),
+ SOC_DAPM_SINGLE("MONON2RAXMIX Switch", ES8396_AX_MIXER_REG2E, 2, 1, 0),
+ SOC_DAPM_SINGLE("MIC2N2RAXMIX Switch", ES8396_AX_MIXER_REG2E, 1, 1, 0),
+ SOC_DAPM_SINGLE("NMICDSE2RAXMIX Switch", ES8396_AX_MIXER_REG2E, 0, 1,
+ 0),
+};
+
+/*
+ *left MNMIX mixer
+ */
+static const struct snd_kcontrol_new es8396_mnmixL_mixer_controls[] = {
+ SOC_DAPM_SINGLE("LDAC2LMNMIX Switch", ES8396_MN_MIXER_REG36, 7, 1, 0),
+ SOC_DAPM_SINGLE("MONOP2LMNMIX Switch", ES8396_MN_MIXER_REG36, 6, 1, 0),
+ SOC_DAPM_SINGLE("AINL2LMNMIX Switch", ES8396_MN_MIXER_REG36, 5, 1, 0),
+};
+
+/*
+ *right MNMIX mixer
+ */
+static const struct snd_kcontrol_new es8396_mnmixR_mixer_controls[] = {
+ SOC_DAPM_SINGLE("RDAC2RMNMIX Switch", ES8396_MN_MIXER_REG36, 3, 1, 0),
+ SOC_DAPM_SINGLE("MONON2RMNMIX Switch", ES8396_MN_MIXER_REG36, 2, 1, 0),
+ SOC_DAPM_SINGLE("AINR2RMNMIX Switch", ES8396_MN_MIXER_REG36, 1, 1, 0),
+};
+
+/*
+ * Left Record Mixer
+ */
+static const struct snd_kcontrol_new es8396_captureL_mixer_controls[] = {
+ SOC_DAPM_SINGLE("RLNMIX2LPGA Switch", ES8396_ADC_LPGA_MIXER_REG62, 7, 1,
+ 0),
+ SOC_DAPM_SINGLE("RAXMIX2LPGA Switch", ES8396_ADC_LPGA_MIXER_REG62, 6, 1,
+ 0),
+ SOC_DAPM_SINGLE("RMNMIX2LPGA Switch", ES8396_ADC_LPGA_MIXER_REG62, 5, 1,
+ 0),
+ SOC_DAPM_SINGLE("LMNMIX2LPGA Switch", ES8396_ADC_LPGA_MIXER_REG62, 4, 1,
+ 0),
+ SOC_DAPM_SINGLE("LLNMIX2LPGA Switch", ES8396_ADC_LPGA_MIXER_REG62, 3, 1,
+ 0),
+
+};
+
+/*
+ * Right Record Mixer
+ */
+static const struct snd_kcontrol_new es8396_captureR_mixer_controls[] = {
+ SOC_DAPM_SINGLE("RLNMIX2RPGA Switch", ES8396_ADC_RPGA_MIXER_REG63, 7, 1,
+ 0),
+ SOC_DAPM_SINGLE("RAXMIX2RPGA Switch", ES8396_ADC_RPGA_MIXER_REG63, 6, 1,
+ 0),
+ SOC_DAPM_SINGLE("RMNMIX2RPGA Switch", ES8396_ADC_RPGA_MIXER_REG63, 5, 1,
+ 0),
+ SOC_DAPM_SINGLE("LMNMIX2RPGA Switch", ES8396_ADC_RPGA_MIXER_REG63, 4, 1,
+ 0),
+ SOC_DAPM_SINGLE("LAXMIX2RPGA Switch", ES8396_ADC_RPGA_MIXER_REG63, 3, 1,
+ 0),
+};
+
+static const struct snd_kcontrol_new es8396_adc_controls =
+SOC_DAPM_SINGLE("Switch", ES8396_ADC_CSM_REG53, 6, 1, 1);
+
+/*
+ * MIC INPUT MUX
+ */
+static const struct snd_kcontrol_new es8396_micin_mux_controls =
+SOC_DAPM_SINGLE("Switch", ES8396_SYS_MIC_IBIAS_EN_REG75, 1, 1, 0);
+
+/*
+ * left LN MUX
+ */
+static const char *const es8396_left_lnmux_txt[] = {
+ "NO IN",
+ "RPGAP",
+ "LPGAP",
+ "MONOP",
+ "AINL"
+};
+
+static const unsigned int es8396_left_lnmux_values[] = {
+ 0, 1, 2, 4, 8
+};
+
+static const struct soc_enum es8396_left_lnmux_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_ADC_LN_MUX_REG64, 0, 15,
+ ARRAY_SIZE(es8396_left_lnmux_txt),
+ es8396_left_lnmux_txt,
+ es8396_left_lnmux_values);
+static const struct snd_kcontrol_new es8396_left_lnmux_controls =
+SOC_DAPM_ENUM("Route", es8396_left_lnmux_enum);
+
+/*
+ * Right LN MUX
+ */
+static const char *const es8396_right_lnmux_txt[] = {
+ "NO IN",
+ "RPGAP",
+ "LPGAP",
+ "MONON",
+ "AINR"
+};
+
+static const struct soc_enum es8396_right_lnmux_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_ADC_LN_MUX_REG64, 4, 15,
+ ARRAY_SIZE(es8396_right_lnmux_txt),
+ es8396_right_lnmux_txt,
+ es8396_left_lnmux_values);
+static const struct snd_kcontrol_new es8396_right_lnmux_controls =
+SOC_DAPM_ENUM("Route", es8396_right_lnmux_enum);
+
+/*
+ * left AX MUX
+ */
+static const struct soc_enum es8396_left_axmux_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_ADC_AX_MUX_REG65, 0, 15,
+ ARRAY_SIZE(es8396_left_lnmux_txt),
+ es8396_left_lnmux_txt,
+ es8396_left_lnmux_values);
+static const struct snd_kcontrol_new es8396_left_axmux_controls =
+SOC_DAPM_ENUM("Route", es8396_left_axmux_enum);
+
+/*
+ * Right AX MUX
+ */
+static const struct soc_enum es8396_right_axmux_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_ADC_AX_MUX_REG65, 4, 15,
+ ARRAY_SIZE(es8396_right_lnmux_txt),
+ es8396_right_lnmux_txt,
+ es8396_left_lnmux_values);
+static const struct snd_kcontrol_new es8396_right_axmux_controls =
+SOC_DAPM_ENUM("Route", es8396_right_axmux_enum);
+
+/*
+ * Left SPKOUT MUX
+ */
+static const char *const es8396_left_spkout_mux_txt[] = {
+ "NO Out",
+ "SPKR Route",
+ "SPKL Route"
+};
+
+static const unsigned int es8396_left_spkout_mux_values[] = {
+ 0, 1, 2
+};
+
+static const struct soc_enum es8396_left_spkout_mux_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_SPK_CTRL_SRC_REG3A, 4, 3,
+ ARRAY_SIZE(es8396_left_spkout_mux_txt),
+ es8396_left_spkout_mux_txt,
+ es8396_left_spkout_mux_values);
+static const struct snd_kcontrol_new es8396_left_spkout_mux_controls =
+SOC_DAPM_ENUM("Route", es8396_left_spkout_mux_enum);
+
+/*
+ * Right SPKOUT MUX
+ */
+static const struct soc_enum es8396_right_spkout_mux_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_SPK_CTRL_SRC_REG3A, 0, 3,
+ ARRAY_SIZE(es8396_left_spkout_mux_txt),
+ es8396_left_spkout_mux_txt,
+ es8396_left_spkout_mux_values);
+static const struct snd_kcontrol_new es8396_right_spkout_mux_controls =
+SOC_DAPM_ENUM("Route", es8396_right_spkout_mux_enum);
+
+/*
+ * SPKLDO POWER SWITCH
+ */
+static const struct snd_kcontrol_new es8396_spkldo_pwrswitch_controls =
+SOC_DAPM_SINGLE("Switch", ES8396_DAMP_CLK_DIV_REG0C, 1, 1, 1);
+
+/*
+ * Dmic MUX
+ */
+static const char *const es8396_dmic_mux_txt[] = {
+ /* 0 can be used for stereo amic */
+ "dmic disable,use adc",
+ "ldata use ladc,rdata use ldmic at low clk",
+ "ldata use ladc,rdata use rdmic at low clk",
+ "ldata use ladc,rdata use rdmic at high clk",
+ "ldata use ldmic at high clk,rdata use radc",
+ "ldata use ldmic at high clk,rdata use ldmic at low clk",
+ /* can be used for stereo dmic */
+ "ldata use ldmic at high clk,rdata use rdmic at low clk",
+ "ldata use ldmic at high clk,rdata use rdmic at high clk",
+ "ldata use rdmic at high clk,rdata use radc",
+ /* can be used for stereo dmic */
+ "ldata use rdmic at high clk,rdata use ldmic at low clk",
+ "ldata use rdmic at high clk,rdata use rdmic at low clk",
+ "ldata use rdmic at high clk,rdata use rdmic at high clk",
+ "ldata use ldmic at low clk,rdata use radc",
+ "ldata use ldmic at low clk,rdata use ldmic at low clk",
+ "ldata use ldmic at low clk,rdata use rdmic at low clk",
+ /* can be used for stereo dmic */
+ "ldata use ldmic at low clk,rdata use rdmic at high clk",
+};
+
+static const unsigned int es8396_dmic_mux_values[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+static const struct soc_enum es8396_dmic_mux_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_ADC_DMIC_RAMPRATE_REG54, 4, 15,
+ ARRAY_SIZE(es8396_dmic_mux_txt),
+ es8396_dmic_mux_txt,
+ es8396_dmic_mux_values);
+static const struct snd_kcontrol_new es8396_dmic_mux_controls =
+SOC_DAPM_ENUM("Route", es8396_dmic_mux_enum);
+
+/*
+ * Digital mixer1 left
+ */
+static const char *const es8396_left_digital_mixer_txt[] = {
+ "left SDP1 in",
+ "left SDP2 in",
+ "left SDP3 in",
+ "left ADC out",
+ "right SDP1 in",
+ "right SDP2 in",
+ "right SDP3 in",
+ "right ADC out"
+};
+
+static const unsigned int es8396_left_digital_mixer_values[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7
+};
+
+static const struct soc_enum es8396_left_digital_mixer_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_DMIX_SRC_1_REG18, 4, 15,
+ ARRAY_SIZE(es8396_left_digital_mixer_txt),
+ es8396_left_digital_mixer_txt,
+ es8396_left_digital_mixer_values);
+static const struct snd_kcontrol_new es8396_left_digital_mixer_controls =
+SOC_DAPM_ENUM("Route", es8396_left_digital_mixer_enum);
+
+/*
+ * Digital mixer1 right
+ */
+static const char *const es8396_right_digital_mixer_txt[] = {
+ "right SDP1 in",
+ "right SDP2 in",
+ "right SDP3 in",
+ "right ADC out",
+ "left SDP1 in",
+ "left SDP2 in",
+ "left SDP3 in",
+ "left ADC out"
+};
+
+static const struct soc_enum es8396_right_digital_mixer_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_DMIX_SRC_1_REG18, 0, 15,
+ ARRAY_SIZE(es8396_right_digital_mixer_txt),
+ es8396_right_digital_mixer_txt,
+ es8396_left_digital_mixer_values);
+static const struct snd_kcontrol_new es8396_right_digital_mixer_controls =
+SOC_DAPM_ENUM("Route", es8396_right_digital_mixer_enum);
+
+/*
+ * Digital mixer2 left
+ */
+static const struct soc_enum es8396_left_digital2_mixer_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_DMIX_SRC_2_REG19, 4, 15,
+ ARRAY_SIZE(es8396_left_digital_mixer_txt),
+ es8396_left_digital_mixer_txt,
+ es8396_left_digital_mixer_values);
+static const struct snd_kcontrol_new es8396_left_digital2_mixer_controls =
+SOC_DAPM_ENUM("Route", es8396_left_digital2_mixer_enum);
+
+/*
+ * Digital mixer2 right
+ */
+static const struct soc_enum es8396_right_digital2_mixer_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_DMIX_SRC_2_REG19, 0, 15,
+ ARRAY_SIZE(es8396_right_digital_mixer_txt),
+ es8396_right_digital_mixer_txt,
+ es8396_left_digital_mixer_values);
+static const struct snd_kcontrol_new es8396_right_digital2_mixer_controls =
+SOC_DAPM_ENUM("Route", es8396_right_digital2_mixer_enum);
+
+/*
+ * equalizer clk mux
+ */
+static const char *const es8396_eq_clk_mux_txt[] = {
+ "from dac mclk",
+ "from adc mclk",
+ "from clk1",
+ "from clk2"
+};
+
+static const unsigned int es8396_eq_clk_mux_values[] = {
+ 0, 1, 2, 3
+};
+
+static const struct soc_enum es8396_eq_clk_mux_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_EQ_CLK_OSR_SEL_REG1C, 4, 3,
+ ARRAY_SIZE(es8396_eq_clk_mux_txt),
+ es8396_eq_clk_mux_txt,
+ es8396_eq_clk_mux_values);
+static const struct snd_kcontrol_new es8396_eq_clk_mux_controls =
+SOC_DAPM_ENUM("Route", es8396_eq_clk_mux_enum);
+
+/*
+ * equalizer osr mux
+ */
+static const char *const es8396_eq_osr_mux_txt[] = {
+ "1FS OSR",
+ "2FS OSR",
+ "3FS OSR",
+ "4FS OSR",
+ "5FS OSR",
+ "6FS OSR"
+};
+
+static const unsigned int es8396_eq_osr_mux_values[] = {
+ 0, 1, 2, 3, 4, 5
+};
+
+static const struct soc_enum es8396_eq_osr_mux_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_EQ_CLK_OSR_SEL_REG1C, 0, 7,
+ ARRAY_SIZE(es8396_eq_osr_mux_txt),
+ es8396_eq_osr_mux_txt,
+ es8396_eq_osr_mux_values);
+static const struct snd_kcontrol_new es8396_eq_osr_mux_controls =
+SOC_DAPM_ENUM("Route", es8396_eq_osr_mux_enum);
+
+/*
+ * DAC source mux
+ */
+static const char *const es8396_dac_src_mux_txt[] = {
+ "SDP1 in",
+ "SDP2 in",
+ "SDP3 in",
+ "ADC out",
+ "EQ stereo",
+ "EQ left",
+ "EQ right",
+};
+
+static const unsigned int es8396_dac_src_mux_values[] = {
+ 0, 1, 2, 3, 4, 5, 6
+};
+
+static const struct soc_enum es8396_dac_src_mux_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_DAC_SRC_SDP1O_SRC_REG1A, 4, 7,
+ ARRAY_SIZE(es8396_dac_src_mux_txt),
+ es8396_dac_src_mux_txt,
+ es8396_dac_src_mux_values);
+static const struct snd_kcontrol_new es8396_dac_src_mux_controls =
+SOC_DAPM_ENUM("Route", es8396_dac_src_mux_enum);
+
+/*
+ * I2S1 out mux
+ */
+static const char *const es8396_i2s1_out_mux_txt[] = {
+ "ADC out",
+ "SDP1 in",
+ "SDP2 in",
+ "SDP3 in",
+ "EQ stereo",
+ "EQ left",
+ "EQ right",
+};
+
+static const unsigned int es8396_i2s1_out_mux_values[] = {
+ 0, 1, 2, 3, 4, 5, 6
+};
+
+static const struct soc_enum es8396_i2s1_out_mux_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_DAC_SRC_SDP1O_SRC_REG1A, 0, 7,
+ ARRAY_SIZE(es8396_i2s1_out_mux_txt),
+ es8396_i2s1_out_mux_txt,
+ es8396_i2s1_out_mux_values);
+static const struct snd_kcontrol_new es8396_i2s1_out_mux_controls =
+SOC_DAPM_ENUM("Route", es8396_i2s1_out_mux_enum);
+
+/*
+ * I2S2 out mux
+ */
+static const struct soc_enum es8396_i2s2_out_mux_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_SDP2O_SDP3O_SRC_REG1B, 4, 7,
+ ARRAY_SIZE(es8396_i2s1_out_mux_txt),
+ es8396_i2s1_out_mux_txt,
+ es8396_i2s1_out_mux_values);
+static const struct snd_kcontrol_new es8396_i2s2_out_mux_controls =
+SOC_DAPM_ENUM("Route", es8396_i2s2_out_mux_enum);
+
+/*
+ * I2S3 out mux
+ */
+static const struct soc_enum es8396_i2s3_out_mux_enum =
+SOC_VALUE_ENUM_SINGLE(ES8396_SDP2O_SDP3O_SRC_REG1B, 0, 7,
+ ARRAY_SIZE(es8396_i2s1_out_mux_txt),
+ es8396_i2s1_out_mux_txt,
+ es8396_i2s1_out_mux_values);
+static const struct snd_kcontrol_new es8396_i2s3_out_mux_controls =
+SOC_DAPM_ENUM("Route", es8396_i2s3_out_mux_enum);
+
+static const struct snd_soc_dapm_widget es8396_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("DMIC"),
+ SND_SOC_DAPM_INPUT("LINP"),
+ SND_SOC_DAPM_INPUT("RINN"),
+ SND_SOC_DAPM_INPUT("MONOINP"),
+ SND_SOC_DAPM_INPUT("MONOINN"),
+ SND_SOC_DAPM_INPUT("AINL"),
+ SND_SOC_DAPM_INPUT("AINR"),
+ SND_SOC_DAPM_INPUT("MIC"),
+ SND_SOC_DAPM_SUPPLY("MIC Bias", SND_SOC_NOPM, 0, 0,
+ micbias_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ /*
+ * AIF OUT AND MUX
+ */
+ SND_SOC_DAPM_AIF_OUT("VOICESDPOL", "SDP1 Capture", 0,
+ ES8396_SDP1_OUT_FMT_REG20, 6, 1),
+ SND_SOC_DAPM_AIF_OUT("VOICESDPOR", "SDP1 Capture", 0,
+ ES8396_SDP1_OUT_FMT_REG20, 6, 1),
+ SND_SOC_DAPM_MUX("VOICESDPO Mux", SND_SOC_NOPM, 0, 0, &es8396_i2s1_out_mux_controls),
+ SND_SOC_DAPM_AIF_OUT("MASTERSDPOL", "SDP2 Capture", 0,
+ ES8396_SDP2_OUT_FMT_REG23, 6, 1),
+ SND_SOC_DAPM_AIF_OUT("MASTERSDPOR", "SDP2 Capture", 0,
+ ES8396_SDP2_OUT_FMT_REG23, 6, 1),
+ SND_SOC_DAPM_MUX("MASTERSDPO Mux", SND_SOC_NOPM, 0, 0,
+ &es8396_i2s2_out_mux_controls),
+
+ SND_SOC_DAPM_AIF_OUT("AUXSDPOL", "SDP3 Capture", 0,
+ ES8396_SDP3_OUT_FMT_REG25, 6, 1),
+ SND_SOC_DAPM_AIF_OUT("AUXSDPOR", "SDP3 Capture", 0,
+ ES8396_SDP3_OUT_FMT_REG25, 6, 1),
+ SND_SOC_DAPM_MUX("AUXSDPO Mux", SND_SOC_NOPM, 0, 0,
+ &es8396_i2s3_out_mux_controls),
+
+ SND_SOC_DAPM_MIXER("VOICEOUT AIF Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("MASTEROUT AIF Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("AUXOUT AIF Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* capature */
+
+ /*
+ *left and right mixer
+ */
+ SND_SOC_DAPM_MIXER_NAMED_CTL("PGA Left Mix", SND_SOC_NOPM, 0, 0,
+ &es8396_captureL_mixer_controls[0],
+ ARRAY_SIZE
+ (es8396_captureL_mixer_controls)),
+ SND_SOC_DAPM_MIXER_NAMED_CTL("PGA Right Mix", SND_SOC_NOPM, 0, 0,
+ &es8396_captureR_mixer_controls[0],
+ ARRAY_SIZE
+ (es8396_captureR_mixer_controls)),
+
+ SND_SOC_DAPM_PGA("LPGA P", ES8396_ADC_ANALOG_CTRL_REG5E, 4, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("RPGA P", ES8396_ADC_ANALOG_CTRL_REG5E, 5, 1, NULL, 0),
+
+ SND_SOC_DAPM_ADC("ADC Left", NULL, ES8396_ADC_ANALOG_CTRL_REG5E, 2, 1),
+ SND_SOC_DAPM_ADC("ADC Right", NULL, ES8396_ADC_ANALOG_CTRL_REG5E, 3, 1),
+ SND_SOC_DAPM_SWITCH_E("ADC_1", SND_SOC_NOPM, 0, 0,
+ &es8396_adc_controls, adc_event,
+ SND_SOC_DAPM_PRE_PMD),
+
+ /*
+ * Analog MIC Muxes
+ */
+ SND_SOC_DAPM_SWITCH("AMIC Mux", ES8396_SYS_MIC_IBIAS_EN_REG75, 0, 1,
+ &es8396_micin_mux_controls),
+ SND_SOC_DAPM_PGA("MIC BOOST", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* LN,AX Muxes */
+ /*
+ * LN MUX
+ */
+ SND_SOC_DAPM_MUX("LLN Mux", SND_SOC_NOPM, 0, 0,
+ &es8396_left_lnmux_controls),
+ SND_SOC_DAPM_MUX("RLN Mux", SND_SOC_NOPM, 0, 0,
+ &es8396_right_lnmux_controls),
+ /*
+ * AX MUX
+ */
+ SND_SOC_DAPM_MUX("LAX Mux", SND_SOC_NOPM, 0, 0,
+ &es8396_left_axmux_controls),
+ SND_SOC_DAPM_MUX("RAX Mux", SND_SOC_NOPM, 0, 0,
+ &es8396_right_axmux_controls),
+ /*
+ * AIF IN
+ */
+ SND_SOC_DAPM_AIF_IN("VOICESDPIL", "SDP1 Playback", 0,
+ ES8396_SDP1_IN_FMT_REG1F, 6, 1),
+ SND_SOC_DAPM_AIF_IN("VOICESDPIR", "SDP1 Playback", 0,
+ ES8396_SDP1_IN_FMT_REG1F, 6, 1),
+ SND_SOC_DAPM_AIF_IN("MASTERSDPIL", "SDP2 Playback", 0,
+ SND_SOC_NOPM, 6, 1),
+ SND_SOC_DAPM_AIF_IN("MASTERSDPIR", "SDP2 Playback", 0,
+ SND_SOC_NOPM, 6, 1),
+ SND_SOC_DAPM_AIF_IN("AUXSDPIL", "SDP3 Playback", 0,
+ ES8396_SDP3_IN_FMT_REG24, 6, 1),
+ SND_SOC_DAPM_AIF_IN("AUXSDPIR", "SDP3 Playback", 0,
+ ES8396_SDP3_IN_FMT_REG24, 6, 1),
+ SND_SOC_DAPM_MIXER("VOICEIN AIF Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("MASTERIN AIF Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("AUXIN AIF Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+ /*
+ * Digital mixer1,2
+ */
+ SND_SOC_DAPM_MUX("LDMIX1 Mux", SND_SOC_NOPM, 0, 0,
+ &es8396_left_digital_mixer_controls),
+ SND_SOC_DAPM_MUX("RDMIX1 Mux", SND_SOC_NOPM, 0, 0,
+ &es8396_right_digital_mixer_controls),
+ SND_SOC_DAPM_MUX("LDMIX2 Mux", SND_SOC_NOPM, 0, 0,
+ &es8396_left_digital2_mixer_controls),
+ SND_SOC_DAPM_MUX("RDMIX2 Mux", SND_SOC_NOPM, 0, 0,
+ &es8396_right_digital2_mixer_controls),
+
+ SND_SOC_DAPM_MIXER("Digital Left Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Digital Right Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Equalizer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("DACSRC Mux", SND_SOC_NOPM, 0, 0,
+ &es8396_dac_src_mux_controls),
+ /*
+ * DAC
+ */
+ SND_SOC_DAPM_SWITCH("DAC_1", SND_SOC_NOPM, 0, 0,
+ &es8396_dac_controls),
+
+ SND_SOC_DAPM_DAC("Left DAC", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("Right DAC", NULL, SND_SOC_NOPM, 0, 0),
+
+ /*
+ * mixerMono
+ */
+ SND_SOC_DAPM_MIXER("LMONIN Mix", ES8396_MN_MIXER_BOOST_REG37, 4, 1,
+ &es8396_mnmixL_mixer_controls[0],
+ ARRAY_SIZE(es8396_mnmixL_mixer_controls)),
+ SND_SOC_DAPM_PGA("LMONINMIX PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RMONIN Mix", ES8396_MN_MIXER_BOOST_REG37, 0, 1,
+ &es8396_mnmixR_mixer_controls[0],
+ ARRAY_SIZE(es8396_mnmixR_mixer_controls)),
+ SND_SOC_DAPM_PGA("RMONINMIX PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ /*
+ * mixerLN
+ */
+ SND_SOC_DAPM_MIXER("LLNIN Mix", ES8396_LN_MIXER_BOOST_REG33, 4, 1,
+ &es8396_lnmixL_mixer_controls[0],
+ ARRAY_SIZE(es8396_lnmixL_mixer_controls)),
+ SND_SOC_DAPM_PGA("LLNINMIX PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RLNIN Mix", ES8396_LN_MIXER_BOOST_REG33, 0, 1,
+ &es8396_lnmixR_mixer_controls[0],
+ ARRAY_SIZE(es8396_lnmixR_mixer_controls)),
+ SND_SOC_DAPM_PGA("RLNINMIX PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ /*
+ * mixerAX
+ */
+ SND_SOC_DAPM_MIXER("LAXIN Mix", ES8396_AX_MIXER_BOOST_REG2F, 4, 1,
+ &es8396_axmixL_mixer_controls[0],
+ ARRAY_SIZE(es8396_axmixL_mixer_controls)),
+ SND_SOC_DAPM_PGA("LAXINMIX PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RAXIN Mix", ES8396_AX_MIXER_BOOST_REG2F, 0, 1,
+ &es8396_axmixR_mixer_controls[0],
+ ARRAY_SIZE(es8396_axmixR_mixer_controls)),
+ SND_SOC_DAPM_PGA("RAXINMIX PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ /*
+ * mixerLNOUT
+ */
+ SND_SOC_DAPM_MIXER("LOUT1 Mix", SND_SOC_NOPM, 0, 0,
+ &es8396_lout1_mixer_controls[0],
+ ARRAY_SIZE(es8396_lout1_mixer_controls)),
+ SND_SOC_DAPM_PGA("LNOUTMIX1 PGA", SND_SOC_NOPM, 6, 0,
+ NULL, 0),
+ SND_SOC_DAPM_MIXER("ROUT1 Mix", SND_SOC_NOPM, 0, 0,
+ &es8396_rout1_mixer_controls[0],
+ ARRAY_SIZE(es8396_rout1_mixer_controls)),
+ SND_SOC_DAPM_PGA("RNOUTMIX1 PGA", SND_SOC_NOPM, 6, 0,
+ NULL, 0),
+
+ /*
+ * mixerMNOUT
+ */
+ SND_SOC_DAPM_MIXER("MNOUTP Mix", SND_SOC_NOPM, 0, 0,
+ &es8396_monoP_mixer_controls[0],
+ ARRAY_SIZE(es8396_monoP_mixer_controls)),
+ SND_SOC_DAPM_PGA("MNOUTP PGA", ES8396_MONOHP_P_BOOST_MUTE_REG48, 7, 0,
+ NULL, 0),
+ SND_SOC_DAPM_MIXER("MNOUTN Mix", SND_SOC_NOPM, 0, 0,
+ &es8396_monoN_mixer_controls[0],
+ ARRAY_SIZE(es8396_monoN_mixer_controls)),
+ SND_SOC_DAPM_PGA("MNOUTN PGA", ES8396_MONOHP_N_BOOST_MUTE_REG49, 7, 0,
+ NULL, 0),
+
+ /*
+ * mixerHP
+ */
+ /*
+ * SND_SOC_DAPM_MIXER("HPL Mix", ES8396_HP_MIXER_BOOST_REG2B, 4, 1,
+ */
+ SND_SOC_DAPM_MIXER("HPL Mix", SND_SOC_NOPM, 6, 0,
+ &es8396_hpl_mixer_controls[0],
+ ARRAY_SIZE(es8396_hpl_mixer_controls)),
+ /*
+ * SND_SOC_DAPM_MIXER("HPR Mix", ES8396_HP_MIXER_BOOST_REG2B, 0, 1,
+ */
+ SND_SOC_DAPM_MIXER("HPR Mix", SND_SOC_NOPM, 2, 0,
+ &es8396_hpr_mixer_controls[0],
+ ARRAY_SIZE(es8396_hpr_mixer_controls)),
+ SND_SOC_DAPM_SWITCH_E("HP Amp", SND_SOC_NOPM, 0, 0,
+ &hp_amp_ctl, hpamp_event,
+ SND_SOC_DAPM_PRE_PMU),
+ /*
+ * mixerSPK
+ */
+ SND_SOC_DAPM_MIXER("SPKL Mix", SND_SOC_NOPM, 0, 0,
+ &es8396_speaker_lmixer_controls[0],
+ ARRAY_SIZE(es8396_speaker_lmixer_controls)),
+ SND_SOC_DAPM_MIXER("SPKR Mix", SND_SOC_NOPM, 0, 0,
+ &es8396_speaker_rmixer_controls[0],
+ ARRAY_SIZE(es8396_speaker_rmixer_controls)),
+ SND_SOC_DAPM_SWITCH_E("SPK Amp", SND_SOC_NOPM, 0, 0,
+ &es8396_spkldo_pwrswitch_controls, classd_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_OUTPUT("MONOOUTP"),
+ SND_SOC_DAPM_OUTPUT("MONOOUTN"),
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+ SND_SOC_DAPM_OUTPUT("SPKOUTL"),
+ SND_SOC_DAPM_OUTPUT("SPKOUTR"),
+ SND_SOC_DAPM_OUTPUT("LOUTP"),
+ SND_SOC_DAPM_OUTPUT("ROUTN"),
+};
+
+static const struct snd_soc_dapm_route es8396_dapm_routes[] = {
+ /* lln mux */
+ {"LLN Mux", "RPGAP", "RPGA P"},
+ {"LLN Mux", "LPGAP", "LPGA P"},
+ {"LLN Mux", "MONOP", "MONOINP"},
+ {"LLN Mux", "AINL", "AINL"},
+
+ /* rln mux */
+ {"RLN Mux", "RPGAP", "RPGA P"},
+ {"RLN Mux", "LPGAP", "LPGA P"},
+ {"RLN Mux", "MONON", "MONOINN"},
+ {"RLN Mux", "AINR", "AINR"},
+
+ /* lax mux */
+ {"LAX Mux", "RPGAP", "RPGA P"},
+ {"LAX Mux", "LPGAP", "LPGA P"},
+ {"LAX Mux", "MONOP", "MONOINP"},
+ {"LAX Mux", "AINL", "AINL"},
+
+ /* rax mux */
+ {"RAX Mux", "RPGAP", "RPGA P"},
+ {"RAX Mux", "LPGAP", "LPGA P"},
+ {"RAX Mux", "MONON", "MONOINN"},
+ {"RAX Mux", "AINR", "AINR"},
+
+ /* Left, right PGA */
+ {"LPGA P", NULL, "PGA Left Mix"},
+ {"RPGA P", NULL, "PGA Right Mix"},
+
+ {"PGA Left Mix", "RLNMIX2LPGA Switch", "RLNINMIX PGA"},
+ {"PGA Left Mix", "RAXMIX2LPGA Switch", "RAXINMIX PGA"},
+ {"PGA Left Mix", "RMNMIX2LPGA Switch", "RMONINMIX PGA"},
+ {"PGA Left Mix", "LMNMIX2LPGA Switch", "LMONINMIX PGA"},
+ {"PGA Left Mix", "LLNMIX2LPGA Switch", "LLNINMIX PGA"},
+
+ {"PGA Right Mix", "RLNMIX2RPGA Switch", "RLNINMIX PGA"},
+ {"PGA Right Mix", "RAXMIX2RPGA Switch", "RAXINMIX PGA"},
+ {"PGA Right Mix", "RMNMIX2RPGA Switch", "RMONINMIX PGA"},
+ {"PGA Right Mix", "LMNMIX2RPGA Switch", "LMONINMIX PGA"},
+ {"PGA Right Mix", "LAXMIX2RPGA Switch", "LAXINMIX PGA"},
+
+ /* lnmix */
+ {"RLNINMIX PGA", NULL, "RLNIN Mix"},
+ {"LLNINMIX PGA", NULL, "LLNIN Mix"},
+
+ {"LLNIN Mix", "AINL2LLNMIX Switch", "AINL"},
+ {"LLNIN Mix", "LLNMUX2LLNMIX Switch", "LLN Mux"},
+ {"LLNIN Mix", "MIC1P2LLNMIX Switch", "MIC"},
+ {"LLNIN Mix", "PMICDSE2LLNMIX Switch", "MIC BOOST"},
+
+ {"RLNIN Mix", "AINR2RLNMIX Switch", "AINR"},
+ {"RLNIN Mix", "RLNMUX2RLNMIX Switch", "RLN Mux"},
+ {"RLNIN Mix", "MIC1N2LLNMIX Switch", "MIC"},
+ {"RLNIN Mix", "NMICDSE2RLNMIX Switch", "MIC BOOST"},
+
+ /* AXmix */
+ {"RAXINMIX PGA", NULL, "RAXIN Mix"},
+ {"LAXINMIX PGA", NULL, "LAXIN Mix"},
+
+ {"LAXIN Mix", "LAXMUX2LAXMIX Switch", "LAX Mux"},
+ {"LAXIN Mix", "MONOP2LAXMIX Switch", "MONOINP"},
+ {"LAXIN Mix", "MIC2P2LAXMIX Switch", "MIC"},
+ {"LAXIN Mix", "PMICDSE2LAXMIX Switch", "MIC BOOST"},
+
+ {"RAXIN Mix", "RAXMUX2RAXMIX Switch", "RAX Mux"},
+ {"RAXIN Mix", "MONON2RAXMIX Switch", "MONOINN"},
+ {"RAXIN Mix", "MIC2N2RAXMIX Switch", "MIC"},
+ {"RAXIN Mix", "NMICDSE2RAXMIX Switch", "MIC BOOST"},
+
+ /* MNmix */
+ {"RMONINMIX PGA", NULL, "RMONIN Mix"},
+ {"LMONINMIX PGA", NULL, "LMONIN Mix"},
+
+ {"LMONIN Mix", "LDAC2LMNMIX Switch", "Left DAC"},
+ {"LMONIN Mix", "MONOP2LMNMIX Switch", "MONOINP"},
+ {"LMONIN Mix", "AINL2LMNMIX Switch", "AINL"},
+
+ {"RMONIN Mix", "RDAC2RMNMIX Switch", "Right DAC"},
+ {"RMONIN Mix", "MONON2RMNMIX Switch", "MONOINN"},
+ {"RMONIN Mix", "AINR2RMNMIX Switch", "AINR"},
+
+ /* Analog mic mux */
+ {"MIC BOOST", NULL, "AMIC Mux"},
+
+ {"AMIC Mux", "Switch", "MIC"},
+ {"MIC", NULL, "MIC Bias"},
+ /* capature */
+ {"ADC Left", NULL, "LPGA P"},
+ {"ADC Right", NULL, "RPGA P"},
+
+ {"ADC_1", "Switch", "ADC Left"},
+ {"ADC_1", "Switch", "ADC Right"},
+
+ /* digital mixer */
+ {"Equalizer", NULL, "Digital Left Mixer"},
+ {"Equalizer", NULL, "Digital Right Mixer"},
+
+ {"Digital Left Mixer", NULL, "LDMIX1 Mux"},
+ {"Digital Left Mixer", NULL, "LDMIX2 Mux"},
+
+ {"Digital Right Mixer", NULL, "RDMIX1 Mux"},
+ {"Digital Right Mixer", NULL, "RDMIX2 Mux"},
+
+ {"LDMIX1 Mux", "left SDP1 in", "VOICESDPIL"},
+ {"LDMIX1 Mux", "left SDP2 in", "MASTERSDPIL"},
+ {"LDMIX1 Mux", "left SDP3 in", "AUXSDPIL"},
+ {"LDMIX1 Mux", "left ADC out", "ADC_1"},
+ {"LDMIX1 Mux", "right SDP1 in", "VOICESDPIR"},
+ {"LDMIX1 Mux", "right SDP2 in", "MASTERSDPIR"},
+ {"LDMIX1 Mux", "right SDP3 in", "AUXSDPIR"},
+ {"LDMIX1 Mux", "right ADC out", "ADC_1"},
+
+ {"RDMIX1 Mux", "left SDP1 in", "VOICESDPIL"},
+ {"RDMIX1 Mux", "left SDP2 in", "MASTERSDPIL"},
+ {"RDMIX1 Mux", "left SDP3 in", "AUXSDPIL"},
+ {"RDMIX1 Mux", "left ADC out", "ADC_1"},
+ {"RDMIX1 Mux", "right SDP1 in", "VOICESDPIR"},
+ {"RDMIX1 Mux", "right SDP2 in", "MASTERSDPIR"},
+ {"RDMIX1 Mux", "right SDP3 in", "AUXSDPIR"},
+ {"RDMIX1 Mux", "right ADC out", "ADC_1"},
+
+ {"LDMIX2 Mux", "left SDP1 in", "VOICESDPIL"},
+ {"LDMIX2 Mux", "left SDP2 in", "MASTERSDPIL"},
+ {"LDMIX2 Mux", "left SDP3 in", "AUXSDPIL"},
+ {"LDMIX2 Mux", "left ADC out", "ADC_1"},
+ {"LDMIX2 Mux", "right SDP1 in", "VOICESDPIR"},
+ {"LDMIX2 Mux", "right SDP2 in", "MASTERSDPIR"},
+ {"LDMIX2 Mux", "right SDP3 in", "AUXSDPIR"},
+ {"LDMIX2 Mux", "right ADC out", "ADC_1"},
+
+ {"RDMIX2 Mux", "left SDP1 in", "VOICESDPIL"},
+ {"RDMIX2 Mux", "left SDP2 in", "MASTERSDPIL"},
+ {"RDMIX2 Mux", "left SDP3 in", "AUXSDPIL"},
+ {"RDMIX2 Mux", "left ADC out", "ADC_1"},
+ {"RDMIX2 Mux", "right SDP1 in", "VOICESDPIR"},
+ {"RDMIX2 Mux", "right SDP2 in", "MASTERSDPIR"},
+ {"RDMIX2 Mux", "right SDP3 in", "AUXSDPIR"},
+ {"RDMIX2 Mux", "right ADC out", "ADC_1"},
+
+ /* VOICE/SDP1 AIF IN mixer */
+ {"VOICEIN AIF Mixer", NULL, "VOICESDPIL"},
+ {"VOICEIN AIF Mixer", NULL, "VOICESDPIR"},
+ /* master/SDP2 AIF IN mixer */
+ {"MASTERIN AIF Mixer", NULL, "MASTERSDPIL"},
+ {"MASTERIN AIF Mixer", NULL, "MASTERSDPIR"},
+ /* aux/SDP3 AIF IN mixer */
+ {"AUXIN AIF Mixer", NULL, "AUXSDPIL"},
+ {"AUXIN AIF Mixer", NULL, "AUXSDPIR"},
+ /* VOICE/SDP1 AIF OUT */
+ {"VOICESDPOL", NULL, "VOICESDPO Mux"},
+ {"VOICESDPOR", NULL, "VOICESDPO Mux"},
+
+ {"VOICESDPO Mux", "ADC out", "ADC_1"},
+ {"VOICESDPO Mux", "SDP1 in", "VOICEIN AIF Mixer"},
+ {"VOICESDPO Mux", "SDP2 in", "MASTERIN AIF Mixer"},
+ {"VOICESDPO Mux", "SDP3 in", "AUXIN AIF Mixer"},
+ {"VOICESDPO Mux", "EQ stereo", "Equalizer"},
+ {"VOICESDPO Mux", "EQ left", "Digital Left Mixer"},
+ {"VOICESDPO Mux", "EQ right", "Digital Right Mixer"},
+
+ /* master/SDP2 AIF OUT */
+ {"MASTERSDPOL", NULL, "MASTERSDPO Mux"},
+ {"MASTERSDPOR", NULL, "MASTERSDPO Mux"},
+
+ {"MASTERSDPO Mux", "ADC out", "ADC_1"},
+ {"MASTERSDPO Mux", "SDP1 in", "VOICEIN AIF Mixer"},
+ {"MASTERSDPO Mux", "SDP2 in", "MASTERIN AIF Mixer"},
+ {"MASTERSDPO Mux", "SDP3 in", "AUXIN AIF Mixer"},
+ {"MASTERSDPO Mux", "EQ stereo", "Equalizer"},
+ {"MASTERSDPO Mux", "EQ left", "Digital Left Mixer"},
+ {"MASTERSDPO Mux", "EQ right", "Digital Right Mixer"},
+
+ /* AUX/SDP3 AIF OUT */
+ {"AUXSDPOL", NULL, "AUXSDPO Mux"},
+ {"AUXSDPOR", NULL, "AUXSDPO Mux"},
+
+ {"AUXSDPO Mux", "ADC out", "ADC_1"},
+ {"AUXSDPO Mux", "SDP1 in", "VOICEIN AIF Mixer"},
+ {"AUXSDPO Mux", "SDP2 in", "MASTERIN AIF Mixer"},
+ {"AUXSDPO Mux", "SDP3 in", "AUXIN AIF Mixer"},
+ {"AUXSDPO Mux", "EQ stereo", "Equalizer"},
+ {"AUXSDPO Mux", "EQ left", "Digital Left Mixer"},
+ {"AUXSDPO Mux", "EQ right", "Digital Right Mixer"},
+
+ /* DAC */
+ {"Left DAC", NULL, "DAC_1"},
+ {"Right DAC", NULL, "DAC_1"},
+
+ {"DAC_1", "Switch", "DACSRC Mux"},
+
+ {"DACSRC Mux", "SDP1 in", "VOICEIN AIF Mixer"},
+ {"DACSRC Mux", "SDP2 in", "MASTERIN AIF Mixer"},
+ {"DACSRC Mux", "SDP3 in", "AUXIN AIF Mixer"},
+ {"DACSRC Mux", "ADC out", "ADC_1"},
+ {"DACSRC Mux", "EQ stereo", "Equalizer"},
+ {"DACSRC Mux", "EQ left", "Digital Left Mixer"},
+ {"DACSRC Mux", "EQ right", "Digital Right Mixer"},
+
+ /* SPEAKER Paths */
+ {"SPKOUTL", NULL, "SPK Amp"},
+ {"SPKOUTR", NULL, "SPK Amp"},
+
+ {"SPK Amp", "Switch", "SPKL Mix"},
+ {"SPK Amp", "Switch", "SPKR Mix"},
+ /*
+ * {"SPK Amp", "Switch", "SPKL Mux"},
+ * {"SPK Amp", "Switch", "SPKR Mux"},
+ *
+ * {"SPKL Mux", "SPKR Route", "SPKR Mix"},
+ * {"SPKL Mux", "SPKL Route", "SPKL Mix"},
+ *
+ * {"SPKR Mux", "SPKR Route", "SPKR Mix"},
+ * {"SPKR Mux", "SPKL Route", "SPKL Mix"},
+ */
+ {"SPKL Mix", "LLNMUX2SPKMIX Switch", "LLN Mux"},
+ {"SPKL Mix", "LAXMUX2SPKMIX Switch", "LAX Mux"},
+ {"SPKL Mix", "LDAC2SPKMIX Switch", "Left DAC"},
+
+ {"SPKR Mix", "RLNMUX2SPKMIX Switch", "RLN Mux"},
+ {"SPKR Mix", "RAXMUX2SPKMIX Switch", "RAX Mux"},
+ {"SPKR Mix", "RDAC2SPKMIX Switch", "Right DAC"},
+
+ /* HEADPHONE Paths */
+ {"HPL", NULL, "HP Amp"},
+ {"HPR", NULL, "HP Amp"},
+
+ {"HP Amp", "Switch", "HPL Mix"},
+ {"HP Amp", "Switch", "HPR Mix"},
+
+ {"HPL Mix", "LNMUX2HPMIX_L Switch", "LLN Mux"},
+ {"HPL Mix", "AXMUX2HPMIX_L Switch", "LAX Mux"},
+ {"HPL Mix", "DACL2HPMIX Switch", "Left DAC"},
+
+ {"HPR Mix", "LNMUX2HPMIX_R Switch", "RLN Mux"},
+ {"HPR Mix", "AXMUX2HPMIX_R Switch", "RAX Mux"},
+ {"HPR Mix", "DACR2HPMIX Switch", "Right DAC"},
+
+ /* EARPIECE Paths */
+ {"MONOOUTP", NULL, "MNOUTP PGA"},
+ {"MONOOUTN", NULL, "MNOUTN PGA"},
+
+ {"MNOUTP PGA", NULL, "MNOUTP Mix"},
+ {"MNOUTN PGA", NULL, "MNOUTN Mix"},
+
+ {"MNOUTP Mix", "LHPMIX2MNMIXP Switch", "HPL Mix"},
+ {"MNOUTP Mix", "RHPMIX2MNOMIXP Switch", "HPR Mix"},
+ {"MNOUTP Mix", "RMNMIX2MNOMIXP Switch", "RMONINMIX PGA"},
+ {"MNOUTP Mix", "RAXMIX2MNOMIXP Switch", "RAXINMIX PGA"},
+ {"MNOUTP Mix", "LLNMIX2MNOMIXP Switch", "LLNINMIX PGA"},
+
+ {"MNOUTN Mix", "LMNMIX2MNMIXN Switch", "LMONINMIX PGA"},
+ {"MNOUTN Mix", "RHPMIX2MNOMIXN Switch", "HPR Mix"},
+ {"MNOUTN Mix", "MOPINV2MNOMIXN Switch", "MNOUTP Mix"},
+ {"MNOUTN Mix", "LLNMIX2MNOMIXN Switch", "LLNINMIX PGA"},
+ {"MNOUTN Mix", "LAXMIX2MNOMIXN Switch", "LAXINMIX PGA"},
+
+ /* LNOUT Paths */
+ {"LOUTP", NULL, "LNOUTMIX1 PGA"},
+ {"ROUTN", NULL, "RNOUTMIX1 PGA"},
+
+ {"LNOUTMIX1 PGA", NULL, "LOUT1 Mix"},
+ {"RNOUTMIX1 PGA", NULL, "ROUT1 Mix"},
+
+ {"LOUT1 Mix", "LDAC2LO1MIXP Switch", "Left DAC"},
+ {"LOUT1 Mix", "LAXMIX2LO1MIXP Switch", "LAXINMIX PGA"},
+ {"LOUT1 Mix", "LLNMIX2LO1MIXP Switch", "LLNINMIX PGA"},
+ {"LOUT1 Mix", "LMNMIX2LO1MIXP Switch", "LMONINMIX PGA"},
+ {"LOUT1 Mix", "RO1INV2LO1MIXP Switch", "ROUT1 Mix"},
+
+ {"ROUT1 Mix", "RDAC2RO1MIXN Switch", "Right DAC"},
+ {"ROUT1 Mix", "RAXMIX2RO1MIXN Switch", "RAXINMIX PGA"},
+ {"ROUT1 Mix", "RLNMIX2RO1MIXN Switch", "RLNINMIX PGA"},
+ {"ROUT1 Mix", "RMNMIX2RO1MIXN Switch", "RMONINMIX PGA"},
+ {"ROUT1 Mix", "LO1INV2RO1MIXN Switch", "LOUT1 Mix"},
+};
+
+struct _pll_div {
+ u32 pll_in;
+ u32 pll_out;
+ u8 mclkdiv;
+ u8 plldiv;
+ u8 n;
+ u8 k1;
+ u8 k2;
+ u8 k3;
+};
+
+static const struct _pll_div codec_pll_div[] = {
+ {7500000, 11289600, 1, 8, 12, 0x01, 0xc6, 0xee},
+ {7500000, 12288000, 1, 8, 13, 0x04, 0x82, 0x90},
+
+ {7600000, 11289600, 1, 8, 11, 0x25, 0x2e, 0x93},
+ {7600000, 12288000, 1, 8, 12, 0x27, 0x53, 0x49},
+
+ {8192000, 11289600, 1, 8, 11, 0x01, 0x0d, 0x41},
+ {8192000, 12288000, 1, 8, 12, 0x00, 0x00, 0x01},
+
+ {8380000, 11289600, 1, 8, 10, 0x20, 0xb7, 0x8d},
+ {8380000, 12288000, 1, 8, 11, 0x1e, 0xbe, 0xb7},
+
+ {9000000, 11289600, 1, 8, 10, 0x01, 0x7b, 0x1c},
+ {9000000, 12288000, 1, 8, 10, 0x26, 0xd1, 0x4a},
+
+ {9600000, 11289600, 1, 8, 9, 0x11, 0x2a, 0x3c},
+ {9600000, 12288000, 1, 8, 10, 0x0a, 0x18, 0xd8},
+
+ {9800000, 11289600, 1, 8, 9, 0x09, 0x16, 0x5c},
+ {9800000, 12288000, 1, 8, 10, 0x01, 0x4e, 0x18},
+
+ {10000000, 11289600, 1, 8, 9, 0x01, 0x55, 0x33},
+ {10000000, 12288000, 1, 8, 9, 0x22, 0xef, 0x8f},
+
+ {11059200, 11289600, 1, 8, 8, 0x07, 0x03, 0x07},
+ {11059200, 12288000, 1, 8, 8, 0x25, 0x65, 0x7f},
+
+ {11289600, 11289600, 1, 8, 8, 0x00, 0x00, 0x01},
+ {11289600, 12288000, 1, 8, 8, 0x1d, 0xc3, 0xb8},
+
+ {11500000, 11289600, 1, 8, 7, 0x23, 0xe9, 0xcd},
+ {11500000, 12288000, 1, 8, 8, 0x17, 0x0f, 0xee},
+
+ {12000000, 11289600, 1, 8, 7, 0x16, 0x25, 0x6c},
+ {12000000, 12288000, 1, 8, 8, 0x08, 0x13, 0xe0},
+
+ {12288000, 11289600, 1, 8, 7, 0x0e, 0xb9, 0x90},
+ {12288000, 12288000, 1, 8, 8, 0x00, 0x00, 0x01},
+
+ {12500000, 11289600, 1, 8, 7, 0x09, 0x7a, 0xff},
+ {12500000, 12288000, 1, 8, 7, 0x24, 0x5c, 0xe2},
+
+ {12800000, 11289600, 1, 8, 7, 0x02, 0x5b, 0x21},
+ {12800000, 12288000, 1, 8, 7, 0x1c, 0x9b, 0xb9},
+
+ {13000000, 11289600, 1, 8, 6, 0x27, 0xdc, 0x2b},
+ {13000000, 12288000, 1, 8, 7, 0x17, 0xa3, 0x2f},
+
+ {13500000, 11289600, 1, 8, 6, 0x1d, 0x08, 0xdc},
+ {13500000, 12288000, 1, 8, 7, 0x0b, 0xda, 0xcc},
+
+ {13560000, 11289600, 1, 8, 6, 0x1b, 0xca, 0x0a},
+ {13560000, 12288000, 1, 8, 7, 0x0a, 0x7f, 0xc7},
+
+ {14000000, 11289600, 1, 8, 6, 0x12, 0xfb, 0x81},
+ {14000000, 12288000, 1, 8, 7, 0x00, 0xe9, 0xdd},
+
+ {15000000, 11289600, 1, 8, 6, 0x00, 0xe3, 0x77},
+ {15000000, 12288000, 1, 8, 6, 0x17, 0x4a, 0x5f},
+
+ {15360000, 11289600, 1, 8, 5, 0x25, 0x05, 0xc2},
+ {15360000, 12288000, 1, 8, 6, 0x10, 0xd4, 0x12},
+
+ {16000000, 11289600, 1, 8, 5, 0x1b, 0x20, 0x9d},
+ {16000000, 12288000, 1, 8, 6, 0x06, 0x0e, 0xe8},
+
+ {16384000, 11289600, 1, 8, 5, 0x15, 0x8f, 0xb8},
+ {16384000, 12288000, 1, 8, 6, 0x00, 0x00, 0x01},
+
+ {16800000, 11289600, 1, 8, 5, 0x0f, 0xd1, 0x96},
+ {16800000, 12288000, 1, 8, 5, 0x23, 0xd2, 0x0a},
+
+ {18432000, 11289600, 2, 8, 9, 0x21, 0xa8, 0x25},
+ {18432000, 12288000, 2, 8, 10, 0x1c, 0x0c, 0x1f},
+
+ {19200000, 11289600, 2, 8, 9, 0x11, 0x2a, 0x3c},
+ {19200000, 12288000, 2, 8, 10, 0x0a, 0x18, 0xd8},
+
+ {19800000, 11289600, 2, 8, 9, 0x05, 0x2b, 0xc0},
+ {19800000, 12288000, 2, 8, 9, 0x27, 0x1d, 0x01},
+
+ {20000000, 11289600, 2, 8, 9, 0x01, 0x55, 0x33},
+ {20000000, 12288000, 2, 8, 9, 0x22, 0xef, 0x8f},
+
+ {22118400, 11289600, 2, 8, 8, 0x07, 0x03, 0x07},
+ {22118400, 12288000, 2, 8, 8, 0x25, 0x65, 0x7f},
+
+ {22579200, 11289600, 2, 8, 8, 0x00, 0x00, 0x01},
+ {22579200, 12288000, 2, 8, 8, 0x1d, 0xc3, 0xb8},
+
+ {24000000, 11289600, 2, 8, 7, 0x16, 0x25, 0x6c},
+ {24000000, 12288000, 2, 8, 8, 0x08, 0x13, 0xe0},
+
+ {24576000, 11289600, 2, 8, 7, 0x0e, 0xb9, 0x90},
+ {24576000, 12288000, 2, 8, 8, 0x00, 0x00, 0x01},
+
+ {25000000, 11289600, 2, 8, 7, 0x09, 0x7a, 0xff},
+ {25000000, 12288000, 2, 8, 7, 0x24, 0x5c, 0xe2},
+
+ {26000000, 11289600, 2, 8, 6, 0x27, 0xdc, 0x2b},
+ {26000000, 12288000, 2, 8, 7, 0x17, 0xa3, 0x2f},
+
+ {27000000, 11289600, 2, 8, 6, 0x1d, 0x08, 0xdc},
+ {27000000, 12288000, 2, 8, 7, 0x0b, 0xda, 0xcc},
+
+ {30000000, 11289600, 2, 8, 6, 0x00, 0xe3, 0x77},
+ {30000000, 12288000, 2, 8, 6, 0x17, 0x4a, 0x5f},
+};
+
+static int es8396_set_pll(struct snd_soc_dai *dai, int pll_id,
+ int source, unsigned int freq_in,
+ unsigned int freq_out)
+{
+ int i;
+ struct snd_soc_codec *codec = dai->codec;
+ struct es8396_private *priv = snd_soc_codec_get_drvdata(codec);
+ u16 reg;
+ u8 N, K1, K2, K3, mclk_div, pll_div, tmp;
+
+ switch (pll_id) {
+ case ES8396_PLL:
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* Disable PLL, power down and hold in reset state */
+ snd_soc_write(codec, ES8396_PLL_CTRL_1_REG02, 0x81);
+
+ if (!freq_in || !freq_out)
+ return 0;
+
+ switch (source) {
+ case ES8396_PLL_NO_SRC_0:
+ /* Allow no source specification when stopping */
+ if (freq_out)
+ return -EINVAL;
+ reg = snd_soc_read(codec, ES8396_CLK_SRC_SEL_REG01);
+ reg &= 0xF0;
+ if (source == 0)
+ reg |= 0x01; /* clksrc2= 0, clksrc1 = 1 */
+ else
+ reg |= 0x09; /* clksrc2= 1, clksrc1 = 1 */
+
+ snd_soc_write(codec, ES8396_CLK_SRC_SEL_REG01, reg);
+ reg = snd_soc_read(codec, ES8396_CLK_CTRL_REG08);
+ reg |= 0x0F;
+ snd_soc_write(codec, ES8396_CLK_CTRL_REG08, reg);
+ pr_debug("ES8396 PLL No Clock source\n");
+ break;
+ case ES8396_PLL_SRC_FRM_MCLK:
+ reg = snd_soc_read(codec, ES8396_CLK_SRC_SEL_REG01);
+ reg &= 0xF3;
+ reg |= 0x04; /* clksrc2= mclk */
+ /* use clk2 for pll clk source */
+ snd_soc_write(codec, ES8396_CLK_SRC_SEL_REG01, reg);
+ reg = snd_soc_read(codec, ES8396_CLK_CTRL_REG08);
+ reg |= 0x0F;
+ snd_soc_write(codec, ES8396_CLK_CTRL_REG08, reg);
+ pr_debug("ES8396 PLL Clock Source from MCLK pin\n");
+ break;
+ case ES8396_PLL_SRC_FRM_BCLK:
+ reg = snd_soc_read(codec, ES8396_CLK_SRC_SEL_REG01);
+ reg &= 0xF3;
+ reg |= 0x0c; /* clksrc2= bclk, */
+ /* use clk2 for pll clk source */
+ snd_soc_write(codec, ES8396_CLK_SRC_SEL_REG01, reg);
+ reg = snd_soc_read(codec, ES8396_CLK_CTRL_REG08);
+ reg |= 0x0F;
+ snd_soc_write(codec, ES8396_CLK_CTRL_REG08, reg);
+ pr_debug("ES8396 PLL Clock Source from BCLK signal\n");
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* get N & K */
+ tmp = 0;
+ if ((source == ES8396_PLL_SRC_FRM_MCLK) ||
+ (source == ES8396_PLL_SRC_FRM_BCLK)) {
+ for (i = 0; i < ARRAY_SIZE(codec_pll_div); i++) {
+ if (codec_pll_div[i].pll_in == freq_in &&
+ codec_pll_div[i].pll_out == freq_out) {
+ /* PLL source from MCLK */
+ mclk_div = codec_pll_div[i].mclkdiv;
+ pll_div = codec_pll_div[i].plldiv;
+ N = codec_pll_div[i].n;
+ K3 = codec_pll_div[i].k1;
+ K2 = codec_pll_div[i].k2;
+ K1 = codec_pll_div[i].k3;
+ tmp = 1;
+ break;
+ }
+ }
+
+ if (tmp == 1) {
+ pr_debug("MCLK DIV=%d PLL DIV=%d PLL CLOCK SOURCE=%dHz\n",
+ mclk_div, pll_div, freq_in);
+ pr_debug("N=%d, K3=%d, K2=%d, K1=%d\n", N, K3, K2, K1);
+
+ /* set N & K */
+ snd_soc_write(codec, ES8396_PLL_N_REG04, N);
+ snd_soc_write(codec, ES8396_PLL_K2_REG05, K3);
+ snd_soc_write(codec, ES8396_PLL_K1_REG06, K2);
+ snd_soc_write(codec, ES8396_PLL_K0_REG07, K1);
+ if (mclk_div == 1)
+ /* mclk div2 = 0 */
+ snd_soc_update_bits(codec,
+ ES8396_CLK_SRC_SEL_REG01,
+ 0x10, 0x00);
+ else
+ /* mclk div2 = 1 */
+ snd_soc_update_bits(codec,
+ ES8396_CLK_SRC_SEL_REG01,
+ 0x10, 0x10);
+
+ /* pll div 8 */
+ snd_soc_update_bits(codec, ES8396_PLL_CTRL_1_REG02,
+ 0x3, 0x01);
+
+ /* configure the pll power voltage */
+ switch (priv->dvdd_pwr_vol) {
+ case 0x18:
+ /* dvdd=1.8v */
+ snd_soc_update_bits(codec,
+ ES8396_PLL_CTRL_2_REG03,
+ 0x0c, 0x00);
+ break;
+ case 0x25:
+ /* dvdd=2.5v */
+ snd_soc_update_bits(codec,
+ ES8396_PLL_CTRL_2_REG03,
+ 0x0c, 0x04);
+ break;
+ case 0x33:
+ /* dvdd=3.3v */
+ snd_soc_update_bits(codec,
+ ES8396_PLL_CTRL_2_REG03,
+ 0x0c, 0x08);
+ break;
+ default:
+ /* dvdd=1.8v */
+ snd_soc_update_bits(codec,
+ ES8396_PLL_CTRL_2_REG03,
+ 0x0c, 0x00);
+ break;
+ }
+ /* enable PLL analog power up */
+ snd_soc_update_bits(codec, ES8396_PLL_CTRL_1_REG02,
+ 0x80, 0x00);
+ /* pll digital on */
+ snd_soc_update_bits(codec, ES8396_PLL_CTRL_1_REG02,
+ 0x40, 0x40);
+ priv->mclk[dai->id - 1] = freq_out;
+ snd_soc_write(codec, ES8396_PLL_N_REG04, 0x08);
+ snd_soc_write(codec, ES8396_PLL_K2_REG05, 0X1D);
+ snd_soc_write(codec, ES8396_PLL_K1_REG06, 0XC3);
+ snd_soc_write(codec, ES8396_PLL_K0_REG07, 0XB8);
+ } else {
+ pr_debug("Can not find the correct clock frequency!!!!!\n");
+ }
+ }
+ return 0;
+}
+
+/*
+ * if PLL not be used, use internal clk1 for mclk,
+ * otherwise, use internal clk2 for PLL source.
+ */
+static int es8396_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct es8396_private *priv = snd_soc_codec_get_drvdata(codec);
+ u8 reg;
+
+ switch (dai->id) {
+ case ES8396_SDP1:
+ case ES8396_SDP2:
+ case ES8396_SDP3:
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ switch (clk_id) {
+ /* the clock source form MCLK pin, don't use PLL */
+ case ES8396_CLKID_MCLK:
+ reg = snd_soc_read(codec, ES8396_CLK_SRC_SEL_REG01);
+ reg &= 0xFC;
+ reg |= 0x00; /* clksrc1= mclk */
+ snd_soc_write(codec, ES8396_CLK_SRC_SEL_REG01, reg);
+
+ /* always use clk1 */
+ reg = snd_soc_read(codec, ES8396_CLK_CTRL_REG08);
+ reg &= 0xf0;
+ snd_soc_write(codec, ES8396_CLK_CTRL_REG08, reg);
+
+ priv->sysclk[dai->id] = clk_id;
+ priv->mclk[dai->id] = freq;
+ if (freq > 19600000) {
+ /* mclk div2 */
+ snd_soc_update_bits(codec, ES8396_CLK_SRC_SEL_REG01,
+ 0x10, 0x10);
+ }
+ switch (dai->id) {
+ case ES8396_SDP1:
+ /* bclkdiv m1 use clk1 */
+ snd_soc_update_bits(codec, ES8396_BCLK_DIV_M1_REG0E,
+ 0x20, 0x00);
+ /* lrckdiv m3 use clk1 */
+ snd_soc_update_bits(codec, ES8396_LRCK_DIV_M3_REG10,
+ 0x20, 0x00);
+ break;
+ case ES8396_SDP2:
+ case ES8396_SDP3:
+ /* bclkdiv m1 use clk1 */
+ snd_soc_update_bits(codec, ES8396_BCLK_DIV_M2_REG0F,
+ 0x20, 0x00);
+ /* lrckdiv m4 use clk1 */
+ snd_soc_update_bits(codec, ES8396_LRCK_DIV_M4_REG11,
+ 0x20, 0x00);
+ break;
+ default:
+ break;
+ }
+ pr_debug("ES8396 using MCLK as SYSCLK at %uHz\n", freq);
+ break;
+ /* the clock source form internal BCLK signal, don't use PLL */
+ case ES8396_CLKID_BCLK:
+ reg = snd_soc_read(codec, ES8396_CLK_SRC_SEL_REG01);
+ reg &= 0xFC;
+ reg |= 0x03; /* clksrc1= bclk */
+ snd_soc_write(codec, ES8396_CLK_SRC_SEL_REG01, reg);
+ /* always use clk1 */
+ reg = snd_soc_read(codec, ES8396_CLK_CTRL_REG08);
+ reg &= 0xf0;
+ snd_soc_write(codec, ES8396_CLK_CTRL_REG08, reg);
+
+ priv->sysclk[dai->id] = clk_id;
+ priv->mclk[dai->id] = freq;
+ if (freq > 19600000) {
+ /* mclk div2 */
+ snd_soc_update_bits(codec, ES8396_CLK_SRC_SEL_REG01,
+ 0x10, 0x10);
+ }
+ switch (dai->id) {
+ case ES8396_SDP1:
+ /* bclkdiv m1 use clk1 */
+ snd_soc_update_bits(codec, ES8396_BCLK_DIV_M1_REG0E,
+ 0x20, 0x00);
+ /* lrckdiv m3 use clk1 */
+ snd_soc_update_bits(codec, ES8396_LRCK_DIV_M3_REG10,
+ 0x20, 0x00);
+ break;
+ case ES8396_SDP2:
+ case ES8396_SDP3:
+ /* bclkdiv m1 use clk1 */
+ snd_soc_update_bits(codec, ES8396_BCLK_DIV_M2_REG0F,
+ 0x20, 0x00);
+ /* lrckdiv m4 use clk1 */
+ snd_soc_update_bits(codec, ES8396_LRCK_DIV_M4_REG11,
+ 0x20, 0x00);
+ break;
+ default:
+ break;
+ }
+ pr_debug("ES8396 using BCLK as SYSCLK at %uHz\n", freq);
+ break;
+ case ES8396_CLKID_PLLO:
+ priv->sysclk[dai->id] = ES8396_CLKID_PLLO;
+ switch (dai->id) {
+ case ES8396_SDP1:
+ /* bclkdiv m1 use clk1 */
+ snd_soc_update_bits(codec, ES8396_BCLK_DIV_M1_REG0E,
+ 0x20, 0x00);
+ /* lrckdiv m3 use clk1 */
+ snd_soc_update_bits(codec, ES8396_LRCK_DIV_M3_REG10,
+ 0x20, 0x00);
+ break;
+ case ES8396_SDP2:
+ /* bclkdiv m1 use clk2 */
+ snd_soc_update_bits(codec, ES8396_BCLK_DIV_M1_REG0E,
+ 0x20, 0x20);
+ /* lrckdiv m3 use clk2 */
+ snd_soc_update_bits(codec, ES8396_LRCK_DIV_M3_REG10,
+ 0x20, 0x20);
+ break;
+ case ES8396_SDP3:
+ /* bclkdiv m1 use clk2 */
+ snd_soc_update_bits(codec, ES8396_BCLK_DIV_M2_REG0F,
+ 0x20, 0x20);
+ /* lrckdiv m4 use clk2 */
+ snd_soc_update_bits(codec, ES8396_LRCK_DIV_M4_REG11,
+ 0x20, 0x20);
+ break;
+ default:
+ break;
+ }
+ pr_debug("ES8396 using PLL Output as SYSCLK\n");
+ break;
+ default:
+ pr_err("ES8396 System clock error\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+struct es8396_mclk_div {
+ u32 mclk;
+ u32 srate;
+ u8 lrcdiv;
+ u8 bclkdiv;
+};
+
+static struct es8396_mclk_div es8396_mclk_coeffs[] = {
+ /* MCLK, Sample Rate, lrckdiv, bclkdiv */
+ {5644800, 11025, 0x04, 0x08},
+ {5644800, 22050, 0x02, 0x04},
+ {5644800, 44100, 0x00, 0x02},
+
+ {6000000, 8000, 0x17, 0x0f},
+ {6000000, 11025, 0x16, 0x08},
+ {6000000, 12000, 0x15, 0x0a},
+ {6000000, 16000, 0x14, 0x05},
+ {6000000, 22050, 0x13, 0x04},
+ {6000000, 24000, 0x12, 0x05},
+ {6000000, 44100, 0x11, 0x02},
+ {6000000, 48000, 0x10, 0x01},
+
+ {6144000, 8000, 0x06, 0x0c},
+ {6144000, 12000, 0x04, 0x08},
+ {6144000, 16000, 0x03, 0x06},
+ {6144000, 24000, 0x02, 0x04},
+ {6144000, 32000, 0x01, 0x03},
+ {6144000, 48000, 0x00, 0x02},
+
+ {8192000, 8000, 0x07, 0x10},
+ {8192000, 16000, 0x04, 0x08},
+ {8192000, 32000, 0x02, 0x04},
+
+ {11289600, 11025, 0x07, 0x10},
+ {11289600, 22050, 0x04, 0x08},
+ {11289600, 44100, 0x02, 0x04},
+
+ {12000000, 8000, 0x1b, 0x17},
+ {12000000, 11025, 0x19, 0x11},
+ {12000000, 12000, 0x18, 0x13},
+ {12000000, 16000, 0x17, 0x0f},
+ {12000000, 22050, 0x16, 0x08},
+ {12000000, 24000, 0x15, 0x0a},
+ {12000000, 32000, 0x14, 0x05},
+ {12000000, 44100, 0x13, 0x04},
+ {12000000, 48000, 0x12, 0x05},
+
+ {12288000, 8000, 0x0a, 0x15},
+ {12288000, 12000, 0x07, 0x10},
+ {12288000, 16000, 0x06, 0x0c},
+ {12288000, 24000, 0x04, 0x08},
+ {12288000, 32000, 0x03, 0x06},
+ {12288000, 48000, 0x02, 0x04},
+};
+
+static int es8396_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct es8396_private *priv = snd_soc_codec_get_drvdata(codec);
+ u8 id = codec_dai->id;
+ unsigned int inv, format;
+ u8 spc, mmcc;
+
+ switch (id) {
+ case ES8396_SDP1:
+ spc = snd_soc_read(codec, ES8396_SDP1_IN_FMT_REG1F) & 0x3f;
+ mmcc = snd_soc_read(codec, ES8396_SDP_1_MS_REG12);
+ break;
+ case ES8396_SDP2:
+ spc = snd_soc_read(codec, ES8396_SDP2_IN_FMT_REG22) & 0x3f;
+ mmcc = snd_soc_read(codec, ES8396_SDP_2_MS_REG13);
+ break;
+ case ES8396_SDP3:
+ spc = snd_soc_read(codec, ES8396_SDP3_IN_FMT_REG24) & 0x3f;
+ mmcc = snd_soc_read(codec, ES8396_SDP_3_MS_REG14);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ mmcc &= ~MS_MASTER;
+ mmcc |= 0x24;
+ if (id == ES8396_SDP1) {
+ mmcc &= 0xe4; /* select bclkm1,lrckm3 */
+ } else {
+ mmcc &= 0xe4; /* select bclkm2,lrckm4 */
+ mmcc |= 0x09;
+ }
+ break;
+
+ case SND_SOC_DAIFMT_CBS_CFS:
+ mmcc &= ~MS_MASTER;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ inv = (fmt & SND_SOC_DAIFMT_INV_MASK);
+
+ switch (format) {
+ case SND_SOC_DAIFMT_I2S:
+ spc &= 0xC7;
+ /* lrck polarity normal, TO CHECK THE L&R Inverted for i-net */
+ spc |= 0x00;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ spc &= 0xC7;
+ spc |= 0x18; /* lrck polarity normal */
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ if (id == ES8396_SDP1) {
+ spc &= 0xC7;
+ spc |= 0x28; /* lrck polarity normal */
+ } else {
+ pr_err("ES8396 SDP2&SDP3 don't Support Right Justified\n");
+ return -EINVAL;
+ }
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ spc &= 0xC7;
+
+ if (format == SND_SOC_DAIFMT_DSP_A)
+ spc |= 0x30;
+ else
+ spc |= 0x38;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_write(codec, ES8396_SDP1_IN_FMT_REG1F, 00);
+ pr_debug("es8396_set_dai_fmt-->\n");
+
+ priv->config[id].spc = spc;
+ priv->config[id].mmcc = mmcc;
+
+ return 0;
+}
+
+static int es8396_pcm_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 es8396_private *priv = snd_soc_codec_get_drvdata(codec);
+ int id = dai->id;
+ int mclk_coeff = 0;
+ int srate = params_rate(params);
+ u8 bdiv, lrdiv;
+
+ pr_debug("DAI[%d]: MCLK= %u, srate= %u, lrckdiv= %x, bclkdiv= %x\n",
+ id, priv->mclk[0], srate,
+ es8396_mclk_coeffs[mclk_coeff].lrcdiv,
+ es8396_mclk_coeffs[mclk_coeff].bclkdiv);
+
+ switch (id) {
+ case ES8396_SDP1:
+ bdiv = snd_soc_read(codec, ES8396_BCLK_DIV_M2_REG0F);
+ bdiv &= 0xe0;
+ bdiv |= es8396_mclk_coeffs[mclk_coeff].bclkdiv;
+ lrdiv = snd_soc_read(codec, ES8396_LRCK_DIV_M4_REG11);
+ lrdiv &= 0xe0;
+ lrdiv |= 0x22; /* es8396_mclk_coeffs[mclk_coeff].lrcdiv; */
+ snd_soc_write(codec, ES8396_BCLK_DIV_M2_REG0F, bdiv);
+ snd_soc_write(codec, ES8396_LRCK_DIV_M4_REG11, lrdiv);
+ priv->config[id].srate = srate;
+ priv->config[id].lrcdiv = lrdiv;
+ priv->config[id].sclkdiv = bdiv;
+ break;
+ case ES8396_SDP2:
+ case ES8396_SDP3:
+ bdiv = snd_soc_read(codec, ES8396_BCLK_DIV_M1_REG0E);
+ bdiv &= 0xe0;
+ bdiv |= es8396_mclk_coeffs[mclk_coeff].bclkdiv;
+ lrdiv = snd_soc_read(codec, ES8396_LRCK_DIV_M3_REG10);
+ lrdiv &= 0xe0;
+ lrdiv |= es8396_mclk_coeffs[mclk_coeff].lrcdiv;
+ snd_soc_write(codec, ES8396_BCLK_DIV_M1_REG0E, bdiv);
+ snd_soc_write(codec, ES8396_LRCK_DIV_M3_REG10, lrdiv);
+ priv->config[id].srate = srate;
+ priv->config[id].lrcdiv = lrdiv;
+ priv->config[id].sclkdiv = bdiv;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int es8396_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ u8 value;
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(codec);
+
+ printk("es8396_set_bias_level = 0x%x\n",
+ snd_soc_codec_get_bias_level(codec));
+ printk("bias_level = %d\n", level);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ /*
+ * dac csm startup, dac digital still oN
+ * snd_soc_update_bits(codec, ES8396_DAC_CSM_REG66, 0xFF, 0x00);
+ * dac analog power on
+ * snd_soc_update_bits(codec, ES8396_DAC_REF_PWR_CTRL_REG6E,
+ * 0xff, 0x00);
+ */
+ snd_soc_write(codec, 0x4E, 0x80);
+ snd_soc_write(codec, 0x4F, 0x81);
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (es8396->aif1_select == 0 && es8396->aif2_select == 0) {
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+ snd_soc_write(codec, ES8396_SYS_VMID_REF_REG71,
+ 0xFF);
+ if (es8396_valid_analdo(es8396->ana_ldo_lvl)) {
+ value = es8396->ana_ldo_lvl;
+ value &= 0x07;
+ snd_soc_write(codec, 0x70, value);
+ }
+ }
+ }
+ /*
+ * dac csm startup, dac digital still stop
+ * snd_soc_update_bits(codec, ES8396_DAC_CSM_REG66, 0xFF, 0x04);
+ * adc csm startup, adc digital still stop
+ * snd_soc_update_bits(codec, ES8396_ADC_CSM_REG53, 0xFF, 0x00);
+ */
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ break;
+ }
+
+ return 0;
+}
+
+static int es8396_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int id = dai->id;
+
+ pr_debug("es8396_set_tristate\n");
+ pr_debug("ES8396 SDP NUM = %d\n", id);
+ switch (id) {
+ case ES8396_SDP1:
+ return snd_soc_update_bits(codec, ES8396_SDP1_DGAIN_TDM_REG21,
+ 0x0a, 0x0a);
+ case ES8396_SDP2:
+ case ES8396_SDP3:
+ pr_err("SDP NUM = %d, Can not support tristate\n", id);
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int es8396_pcm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(tron_codec);
+ int ret;
+ int regv;
+ int i;
+ pr_debug(">>>>>>>>es8396_pcm_startup\n");
+ ret = snd_soc_read(tron_codec, ES8396_ADC_CSM_REG53);
+ pr_debug("ES8396_ADC_CSM_REG53===0x%x\n", ret);
+ /*
+ * set the clock source to MCLK pin
+ * set divider for music playback
+ * set DAC source from SDP1 in
+ */
+ if ((es8396->aif2_select & 0x01) == 0) {
+ pr_debug(">>>>>>>>es8396_pcm_startup, only power on sdp1 for music\n");
+ /* if don't have voice requirement */
+ snd_soc_write(tron_codec, 0x1A, 0x00);
+ snd_soc_write(tron_codec, 0x8, 0x10);
+ snd_soc_write(tron_codec, 0xd, 0x00);
+ snd_soc_write(tron_codec, 0x9, 0x04);
+ snd_soc_write(tron_codec, 0x69, 0x00);
+ snd_soc_write(tron_codec, 0x67, 0x00);
+ } else {
+ pr_debug(">>>>>>>>es8396_pcm_startup, already power on sdp2 for voice\n");
+ snd_soc_write(tron_codec, 0x18, 0x00); /* set eq source */
+ snd_soc_write(tron_codec, 0x19, 0x51); /* set eq source */
+ /* if have voice requirement */
+ snd_soc_write(tron_codec, 0x1A, 0x40);
+ snd_soc_write(tron_codec, 0x8, 0x10);
+ snd_soc_write(tron_codec, 0xd, 0x00);
+ snd_soc_write(tron_codec, 0x9, 0x04);
+ snd_soc_write(tron_codec, 0x67, 0x0c);
+ snd_soc_write(tron_codec, 0x69, 0x04);
+ }
+
+ if (playback) {
+ pr_debug(">>>>>>>>>>>es8396_pcm_startup playback\n");
+ es8396->aif1_select |= 0x01;
+ snd_soc_write(tron_codec, 0x66, 0x01);
+ for (i = 0; i < 120; i = i + 2) {
+ snd_soc_write(tron_codec, 0x6A, i + 1);
+ snd_soc_write(tron_codec, 0x6B, i + 1);
+ usleep_range(100, 200);
+ }
+ if (es8396->calibrate == 0) {
+ pr_debug("Enter into %s %d\n", __func__, __LINE__);
+ es8396->calibrate = true;
+ }
+ schedule_delayed_work(&es8396->pcm_pop_work,
+ msecs_to_jiffies(10));
+
+ } else {
+ pr_debug(">>>>>>>>>>>es8396_pcm_startup capture\n");
+ snd_soc_update_bits(tron_codec, ES8396_SDP1_OUT_FMT_REG20, 0x40,
+ 0x40);
+ /* set adc alc */
+ snd_soc_write(tron_codec, ES8396_ADC_ALC_CTRL_1_REG58, 0xC6);
+ snd_soc_write(tron_codec, ES8396_ADC_ALC_CTRL_2_REG59, 0x12);
+ snd_soc_write(tron_codec, ES8396_ADC_ALC_CTRL_4_REG5B, 0x04);
+ snd_soc_write(tron_codec, ES8396_ADC_ALC_CTRL_5_REG5C, 0xC8);
+ snd_soc_write(tron_codec, ES8396_ADC_ALC_CTRL_6_REG5D, 0x11);
+ snd_soc_write(tron_codec, ES8396_ADC_ANALOG_CTRL_REG5E, 0x0);
+ /* Enable MIC BOOST */
+ snd_soc_write(tron_codec, ES8396_SYS_MIC_IBIAS_EN_REG75, 0x02);
+
+ /* axMixer Gain boost */
+ regv = snd_soc_read(tron_codec, ES8396_AX_MIXER_BOOST_REG2F);
+ regv |= 0x88;
+ snd_soc_write(tron_codec, ES8396_AX_MIXER_BOOST_REG2F, regv);
+ /* axmixer vol = +12db */
+ snd_soc_write(tron_codec, ES8396_AX_MIXER_VOL_REG30, 0xaa);
+ /* axmixer high driver capacility */
+ snd_soc_write(tron_codec, ES8396_AX_MIXER_REF_LP_REG31, 0x02);
+ snd_soc_write(tron_codec, 0x33, 0);
+ /* MNMixer Gain boost */
+ regv = snd_soc_read(tron_codec, ES8396_MN_MIXER_BOOST_REG37);
+ regv |= 0x88;
+ snd_soc_write(tron_codec, ES8396_MN_MIXER_BOOST_REG37, regv);
+ /* mnmixer vol = +12db */
+ snd_soc_write(tron_codec, ES8396_MN_MIXER_VOL_REG38, 0x44);
+ /* mnmixer high driver capacility */
+ snd_soc_write(tron_codec, ES8396_MN_MIXER_REF_LP_REG39, 0x02);
+
+ /* ADC STM and Digital Startup, ADC DS Mode */
+ snd_soc_write(tron_codec, ES8396_ADC_CSM_REG53, 0x00);
+ /* force adc stm to normal */
+ snd_soc_write(tron_codec, ES8396_ADC_FORCE_REG77, 0x40);
+ snd_soc_write(tron_codec, ES8396_ADC_FORCE_REG77, 0x0);
+ /* ADC Volume =0db */
+ snd_soc_write(tron_codec, ES8396_ADC_LADC_VOL_REG56, 0x0);
+ snd_soc_write(tron_codec, ES8396_ADC_RADC_VOL_REG57, 0x0);
+ snd_soc_write(tron_codec, ES8396_ADC_CLK_DIV_REG09, 0x04);
+ es8396->aif1_select |= 0x02;
+ schedule_delayed_work(&es8396->adc_depop_work,
+ msecs_to_jiffies(150));
+ }
+ return 0;
+}
+
+static void es8396_pcm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(tron_codec);
+
+ pr_debug(">>>>>>>>es8396_pcm_shutdown\n");
+
+ /*
+ * mute SDP1 in and mute SDP1 out
+ */
+ if (playback) {
+ pr_debug(">>>>>>>>es8396_pcm_shutdown, playback\n");
+ schedule_delayed_work(&es8396->pcm_shutdown_depop_work,
+ msecs_to_jiffies(20));
+ } else {
+ pr_debug(">>>>>>>>es8396_pcm_shutdown, capture\n");
+ snd_soc_update_bits(tron_codec, ES8396_SDP1_OUT_FMT_REG20, 0x40,
+ 0x40);
+ es8396->aif1_select &= 0xfd;
+ }
+}
+
+static int es8396_voice_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ unsigned int index;
+ bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(tron_codec);
+ int regv;
+ int i;
+
+ pr_debug("****************es8396_voice_startup\n");
+
+ if (playback) {
+ pr_debug("****************es8396_voice_startup, playback\n");
+ es8396->aif2_select |= 0x01;
+ snd_soc_write(tron_codec, 0x4e, 0x84);
+ snd_soc_write(tron_codec, 0x4f, 0x85);
+
+ for (i = 0; i < 120; i = i + 2) {
+ snd_soc_write(tron_codec, 0x6A, i + 1);
+ snd_soc_write(tron_codec, 0x6B, i + 1);
+ usleep_range(100, 200);
+ }
+
+ /* mute dac */
+ snd_soc_write(tron_codec, 0x66, 0x01);
+ /* DSP-B, 1st SCLK after LRCK edge, I2S2 SDPIN */
+ snd_soc_update_bits(tron_codec, ES8396_SDP2_IN_FMT_REG22,
+ 0x7F, 0x13);
+ snd_soc_write(tron_codec, 0x18, 0x51); /* set eq source */
+ snd_soc_write(tron_codec, 0x19, 0x51); /* set eq source */
+ snd_soc_write(tron_codec, 0x8, 0x10);
+ snd_soc_write(tron_codec, 0xd, 0x00);
+ snd_soc_write(tron_codec, 0x9, 0x04);
+ if ((es8396->aif1_select & 0x01) == 0) {
+ /* if only voice */
+ snd_soc_write(tron_codec, 0x67, 0x0c);
+ snd_soc_write(tron_codec, 0x69, 0x04);
+ } else {
+ snd_soc_write(tron_codec, 0x67, 0x0c);
+ snd_soc_write(tron_codec, 0x69, 0x04);
+ }
+ /* clk2 used as EQ clk, OSR = 6xFs for 8k resampling to 48k */
+ snd_soc_write(tron_codec, ES8396_EQ_CLK_OSR_SEL_REG1C, 0x35);
+ snd_soc_write(tron_codec, ES8396_SHARED_ADDR_REG1D, 0x00);
+
+ for (index = 0; index < 59; index++) {
+ snd_soc_write(tron_codec, ES8396_SHARED_DATA_REG1E,
+ es8396_equalizer_lpf_bt_incall[index]);
+ }
+ snd_soc_write(tron_codec, ES8396_SHARED_ADDR_REG1D, 0xbb);
+ snd_soc_write(tron_codec, ES8396_SHARED_DATA_REG1E,
+ es8396_equalizer_lpf_bt_incall[59]);
+
+ schedule_delayed_work(&es8396->voice_pop_work,
+ msecs_to_jiffies(50));
+ } else {
+ pr_debug("****************es8396_voice_startup, capture\n");
+ es8396->aif2_select |= 0x02;
+ /* set adc alc */
+ snd_soc_write(tron_codec, ES8396_ADC_ALC_CTRL_1_REG58, 0xC6);
+ snd_soc_write(tron_codec, ES8396_ADC_ALC_CTRL_2_REG59, 0x12);
+ snd_soc_write(tron_codec, ES8396_ADC_ALC_CTRL_4_REG5B, 0x04);
+ snd_soc_write(tron_codec, ES8396_ADC_ALC_CTRL_5_REG5C, 0xC8);
+ snd_soc_write(tron_codec, ES8396_ADC_ALC_CTRL_6_REG5D, 0x11);
+ snd_soc_write(tron_codec, ES8396_ADC_ANALOG_CTRL_REG5E, 0x0);
+ snd_soc_write(tron_codec, ES8396_SYS_MIC_IBIAS_EN_REG75, 0x02);
+
+ /* axMixer Gain boost */
+ regv = snd_soc_read(tron_codec, ES8396_AX_MIXER_BOOST_REG2F);
+ regv |= 0x88;
+ snd_soc_write(tron_codec, ES8396_AX_MIXER_BOOST_REG2F, regv);
+ /* axmixer vol = +12db */
+ snd_soc_write(tron_codec, ES8396_AX_MIXER_VOL_REG30, 0xaa);
+ /* axmixer high driver capacility */
+ snd_soc_write(tron_codec, ES8396_AX_MIXER_REF_LP_REG31, 0x02);
+ snd_soc_write(tron_codec, 0x33, 0);
+ /* MNMixer Gain boost */
+ regv = snd_soc_read(tron_codec, ES8396_MN_MIXER_BOOST_REG37);
+ regv |= 0x88;
+ snd_soc_write(tron_codec, ES8396_MN_MIXER_BOOST_REG37, regv);
+ /* mnmixer vol = +12db */
+ snd_soc_write(tron_codec, ES8396_MN_MIXER_VOL_REG38, 0x44);
+ /* mnmixer high driver capacility */
+ snd_soc_write(tron_codec, ES8396_MN_MIXER_REF_LP_REG39, 0x02);
+
+ /* ADC STM and Digital Startup, ADC DS Mode */
+ snd_soc_write(tron_codec, ES8396_ADC_CSM_REG53, 0x00);
+ /* force adc stm to normal */
+ snd_soc_write(tron_codec, ES8396_ADC_FORCE_REG77, 0x40);
+ snd_soc_write(tron_codec, ES8396_ADC_FORCE_REG77, 0x0);
+ /* ADC Volume =0db */
+ snd_soc_write(tron_codec, ES8396_ADC_LADC_VOL_REG56, 0x0);
+ snd_soc_write(tron_codec, ES8396_ADC_RADC_VOL_REG57, 0x0);
+
+ /* clk2 used as EQ clk, OSR = 6xFs for 8k resampling to 48k */
+ snd_soc_update_bits(tron_codec, ES8396_SDP2_OUT_FMT_REG23,
+ 0x7F, 0x33);
+ }
+ return 0;
+}
+
+static void es8396_voice_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(tron_codec);
+ bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+
+ pr_debug("****************es8396_voice_shutdown\n");
+
+ /* DSP-B, 1st SCLK after LRCK edge, I2S2 SDPIN */
+ if (playback) {
+ snd_soc_write(tron_codec, 0x66, 0x01);
+ pr_debug("****************es8396_voice_shutdown, playback\n");
+ schedule_delayed_work(&es8396->voice_shutdown_depop_work,
+ msecs_to_jiffies(10));
+ } else {
+ pr_debug("****************es8396_voice_shutdown, captuer\n");
+ /* //DSP-B, 1st SCLK after LRCK edge, I2S2 SDPO */
+ snd_soc_update_bits(tron_codec, ES8396_SDP2_OUT_FMT_REG23,
+ 0x7F, 0x73);
+ es8396->aif2_select &= 0xfd;
+ }
+}
+
+/*
+ * Only mute SDP IN(for dac)
+ */
+static int es8396_aif1_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(codec);
+ pr_debug("es8396_aif1_mute id = %d, mute = %d", codec_dai->id, mute);
+ if (mute) {
+ if (es8396->spk_ctl_gpio != INVALID_GPIO &&
+ es8396->aif2_select == 0) {
+ pr_debug("spk_ctl_gpio set %d\n", es8396->spk_ctl_gpio);
+ gpio_set_value(es8396->spk_ctl_gpio, 0);
+ }
+ if (es8396->lineout_ctl_gpio != INVALID_GPIO &&
+ es8396->aif2_select == 0) {
+ pr_debug("lineout_ctl_gpio set %d\n",
+ es8396->lineout_ctl_gpio);
+ gpio_set_value(es8396->lineout_ctl_gpio, 0);
+ }
+ msleep(100);
+ } else {
+ if (es8396->spk_ctl_gpio != INVALID_GPIO) {
+ pr_debug("spk_ctl_gpio set %d\n", es8396->spk_ctl_gpio);
+ gpio_set_value(es8396->spk_ctl_gpio, 1);
+ }
+ if (es8396->lineout_ctl_gpio != INVALID_GPIO) {
+ pr_debug("lineout_ctl_gpio set %d\n",
+ es8396->lineout_ctl_gpio);
+ gpio_set_value(es8396->lineout_ctl_gpio, 1);
+ }
+ }
+
+ return 0;
+}
+
+static int es8396_aif2_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("es8396_aif2_mute id = %d, mute = %d", codec_dai->id, mute);
+
+ if (mute) {
+ if (es8396->spk_ctl_gpio != INVALID_GPIO &&
+ es8396->aif1_select == 0) {
+ pr_debug("spk_ctl_gpio set %d\n", es8396->spk_ctl_gpio);
+ gpio_set_value(es8396->spk_ctl_gpio, 0);
+ }
+ if (es8396->lineout_ctl_gpio != INVALID_GPIO &&
+ es8396->aif1_select == 0) {
+ pr_debug("lineout_ctl_gpio set %d\n",
+ es8396->lineout_ctl_gpio);
+ gpio_set_value(es8396->lineout_ctl_gpio, 0);
+ }
+ msleep(100);
+ } else {
+ if (es8396->spk_ctl_gpio != INVALID_GPIO) {
+ pr_debug("spk_ctl_gpio set %d\n", es8396->spk_ctl_gpio);
+ gpio_set_value(es8396->spk_ctl_gpio, 1);
+ }
+ if (es8396->lineout_ctl_gpio != INVALID_GPIO) {
+ pr_debug("lineout_ctl_gpio set %d\n",
+ es8396->lineout_ctl_gpio);
+ gpio_set_value(es8396->lineout_ctl_gpio, 1);
+ }
+ }
+ return 0;
+}
+
+/* SNDRV_PCM_RATE_KNOT -> 12000, 24000 Hz, limit with constraint list */
+#define ES8396_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
+#define ES8396_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops es8396_aif1_dai_ops = {
+ .startup = es8396_pcm_startup,
+ .shutdown = es8396_pcm_shutdown,
+ .set_sysclk = es8396_set_dai_sysclk,
+ .set_fmt = es8396_set_dai_fmt,
+ .hw_params = es8396_pcm_hw_params,
+ .digital_mute = es8396_aif1_mute,
+ .set_pll = es8396_set_pll,
+ .set_tristate = es8396_set_tristate,
+};
+
+static const struct snd_soc_dai_ops es8396_aif2_dai_ops = {
+ .startup = es8396_voice_startup,
+ .shutdown = es8396_voice_shutdown,
+ .set_sysclk = es8396_set_dai_sysclk,
+ .set_fmt = es8396_set_dai_fmt,
+ .hw_params = es8396_pcm_hw_params,
+ .digital_mute = es8396_aif2_mute,
+ .set_pll = es8396_set_pll,
+};
+
+static struct snd_soc_dai_driver es8396_dai[] = {
+ {
+ .name = "es8396-aif1",
+ .playback = {
+ .stream_name = "SDP1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ES8396_RATES,
+ .formats = ES8396_FORMATS,
+ },
+ .capture = {
+ .stream_name = "SDP1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ES8396_RATES,
+ .formats = ES8396_FORMATS,
+ },
+ .ops = &es8396_aif1_dai_ops,
+ },
+/*
+ {
+ .name = "es8396-aif2",
+ .playback = {
+ .stream_name = "SDP2 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ES8396_RATES,
+ .formats = ES8396_FORMATS,
+ },
+ .capture = {
+ .stream_name = "SDP2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ES8396_RATES,
+ .formats = ES8396_FORMATS,
+ },
+ .ops = &es8396_aif2_dai_ops,
+ },
+*/
+};
+
+static int es8396_suspend(struct device *dev)
+{
+ pr_debug("CODEC going into suspend mode\n");
+
+ snd_soc_write(tron_codec, 0x4e, 0x84);
+ snd_soc_write(tron_codec, 0x4f, 0x85);
+ snd_soc_write(tron_codec, 0x66, 0x01);
+ snd_soc_write(tron_codec, 0x6e, 0x00);
+
+ return 0;
+}
+
+static int es8396_resume(struct device *dev)
+{
+ pr_debug("CODEC going into es8396_resume mode\n");
+
+ usleep_range(20000, 21000);
+
+ snd_soc_write(tron_codec, 0x6e, 0x00);
+ snd_soc_write(tron_codec, 0x66, 0x00);
+ snd_soc_write(tron_codec, 0x4e, 0x80);
+ snd_soc_write(tron_codec, 0x4f, 0x81);
+ return 0;
+}
+
+static int es8396_probe(struct snd_soc_codec *codec)
+{
+ int ret = 0, regv;
+ u8 value;
+
+ struct es8396_private *es8396 = snd_soc_codec_get_drvdata(codec);
+
+ es8396->mclk_clock = devm_clk_get(codec->dev, "mclk");
+ if (PTR_ERR(es8396->mclk_clock) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ ret = clk_prepare_enable(es8396->mclk_clock);
+ if (ret)
+ return ret;
+/*
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ if (ret < 0) {
+ pr_err("Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+*/
+ tron_codec = codec;
+ regv = snd_soc_read(codec, ES8396_PLL_K2_REG05);
+
+ if (regv == 0x00) {
+ /*
+ * setup system analog control
+ */
+ snd_soc_write(codec, ES8396_DLL_CTRL_REG0D, 0x20);
+ snd_soc_write(codec, ES8396_CLK_SRC_SEL_REG01, 0x04);
+ snd_soc_write(codec, ES8396_PLL_CTRL_1_REG02, 0xc1);
+ snd_soc_write(codec, ES8396_PLL_CTRL_2_REG03, 0x00);
+ snd_soc_write(codec, ES8396_PLL_N_REG04, 0x08);
+ snd_soc_write(codec, ES8396_PLL_K2_REG05, 0X1d);
+ snd_soc_write(codec, ES8396_PLL_K1_REG06, 0Xc3);
+ snd_soc_write(codec, ES8396_PLL_K0_REG07, 0Xb8);
+ snd_soc_write(codec, ES8396_PLL_CTRL_1_REG02, 0x41);
+
+ /* adc,dac,cphp,class d clk enable,from clk2 */
+ snd_soc_write(codec, ES8396_CLK_CTRL_REG08, 0x00);
+ /* adc clk ratio=1 */
+ snd_soc_write(codec, ES8396_ADC_CLK_DIV_REG09, 0x04);
+ /* dac clk ratio=1 */
+ snd_soc_write(codec, ES8396_DAC_CLK_DIV_REG0A, 0x01);
+ snd_soc_write(codec, ES8396_BCLK_DIV_M2_REG0F, 0x24);
+ snd_soc_write(codec, ES8396_LRCK_DIV_M4_REG11, 0x22);
+
+ msleep(50);
+ snd_soc_write(codec, ES8396_SYS_VMID_REF_REG71, 0xFC);
+ snd_soc_write(codec, 0x72, 0xFF);
+ snd_soc_write(codec, 0x73, 0xFF);
+ if (es8396_valid_analdo(es8396->ana_ldo_lvl) == false) {
+ pr_err("Analog LDO Level error.\n");
+ return -EINVAL;
+ } else {
+ value = es8396->ana_ldo_lvl;
+ value &= 0x07;
+ snd_soc_write(codec, ES8396_SYS_CHIP_ANA_CTL_REG70,
+ value);
+ }
+ /* mic enable, mic d2se enable */
+ snd_soc_write(codec, ES8396_SYS_MIC_IBIAS_EN_REG75, 0x01);
+ msleep(50);
+ snd_soc_write(codec, ES8396_TEST_MODE_REG76, 0xA0);
+ snd_soc_write(codec, ES8396_NGTH_REG7A, 0x20);
+ msleep(50);
+
+ /* power up adc and dac analog */
+ snd_soc_write(codec, ES8396_ADC_ANALOG_CTRL_REG5E, 0x00);
+ snd_soc_write(codec, ES8396_DAC_REF_PWR_CTRL_REG6E, 0x00);
+ /* set L,R DAC volume */
+ snd_soc_write(codec, ES8396_DAC_LDAC_VOL_REG6A, 0x01);
+ snd_soc_write(codec, ES8396_DAC_RDAC_VOL_REG6B, 0x01);
+ /* setup charge current for calibrate */
+ snd_soc_write(codec, ES8396_ADC_LADC_VOL_REG56, 0x84);
+ snd_soc_write(codec, ES8396_ADC_RADC_VOL_REG57, 0xdc);
+ snd_soc_write(codec, ES8396_DAC_OFFSET_CALI_REG6F, 0x06);
+ snd_soc_write(codec, ES8396_DAC_RAMP_RATE_REG67, 0x00);
+ /* enable adc and dac stm for calibrate */
+ snd_soc_write(codec, ES8396_DAC_CSM_REG66, 0x00);
+ snd_soc_write(codec, ES8396_ADC_CSM_REG53, 0x00);
+ snd_soc_write(codec, ES8396_ADC_FORCE_REG77, 0x40);
+ snd_soc_write(codec, ES8396_ADC_FORCE_REG77, 0x00);
+ snd_soc_write(codec, ES8396_DLL_CTRL_REG0D, 0x00);
+ msleep(100);
+ snd_soc_write(codec, ES8396_DAC_CSM_REG66, 0x00);
+ snd_soc_write(codec, ES8396_ADC_ANALOG_CTRL_REG5E, 0x00);
+ snd_soc_write(codec, 0x5f, 0xf2);
+ snd_soc_write(tron_codec, 0x1f, 0x00);
+ snd_soc_write(tron_codec, 0x20, 0x40);
+ /* FM */
+ msleep(100);
+ snd_soc_write(tron_codec, 0x65, 0x88);
+ snd_soc_write(tron_codec, 0x2E, 0x88);
+ snd_soc_write(tron_codec, 0x2F, 0x00);
+ snd_soc_write(tron_codec, 0x30, 0xBB);
+
+ if (es8396_valid_micbias(es8396->mic_bias_lvl) == false) {
+ pr_err("MIC BIAS Level error.\n");
+ return -EINVAL;
+ } else {
+ value = es8396->mic_bias_lvl;
+ value &= 0x07;
+ value = (value << 4) | 0x08;
+ /* enable micbias1 */
+ snd_soc_write(codec, ES8396_SYS_MICBIAS_CTRL_REG74,
+ value);
+ }
+
+ snd_soc_write(codec, ES8396_ADC_CSM_REG53, 0x20);
+ snd_soc_write(codec, ES8396_ADC_PGA_GAIN_REG61, 0x33);
+ snd_soc_write(codec, ES8396_ADC_MICBOOST_REG60, 0x22);
+ if (es8396->dmic_amic == MIC_AMIC)
+ /*use analog mic */
+ snd_soc_write(codec, ES8396_ADC_DMIC_RAMPRATE_REG54,
+ 0x00);
+ else
+ /*use digital mic */
+ snd_soc_write(codec, ES8396_ADC_DMIC_RAMPRATE_REG54,
+ 0xf0);
+
+ /*Enable HPF, LDATA= LADC, RDATA = LADC */
+ snd_soc_write(codec, ES8396_ADC_HPF_COMP_DASEL_REG55, 0x31);
+
+ /*
+ * setup hp detection
+ */
+
+ /* gpio 2 for irq, AINL as irq src, gpio1 for dmic clk */
+ snd_soc_write(codec, ES8396_ALRCK_GPIO_SEL_REG15, 0xfa);
+ snd_soc_write(codec, ES8396_DAC_JACK_DET_COMP_REG69, 0x00);
+ if (es8396->jackdet_enable == 1) {
+ /* jack detection from AINL pin, AINL=0, HP Insert */
+ snd_soc_write(codec, ES8396_DAC_JACK_DET_COMP_REG69,
+ 0x04);
+ if (es8396->gpio_int_pol == 0)
+ /* if HP insert, GPIO2=Low */
+ snd_soc_write(codec, ES8396_GPIO_IRQ_REG16,
+ 0x80);
+ else
+ /* if HP insert, GPIO2=High */
+ snd_soc_write(codec, ES8396_GPIO_IRQ_REG16,
+ 0xc0);
+ } else {
+ snd_soc_write(codec, ES8396_GPIO_IRQ_REG16, 0x00);
+ }
+
+ /*
+ * setup mono in in differential mode or stereo mode
+ */
+
+ /* monoin in differential mode */
+ if (es8396->monoin_differential == 1)
+ snd_soc_update_bits(codec, ES8396_MN_MIXER_REF_LP_REG39,
+ 0x08, 0x08);
+ else
+ snd_soc_update_bits(codec, ES8396_MN_MIXER_REF_LP_REG39,
+ 0x08, 0x00);
+
+ snd_soc_write(codec, ES8396_DAC_JACK_DET_COMP_REG69, 0x00);
+ snd_soc_write(codec, ES8396_BCLK_DIV_M1_REG0E, 0x24);
+ snd_soc_write(codec, ES8396_LRCK_DIV_M3_REG10, 0x22);
+ snd_soc_write(codec, ES8396_SDP_2_MS_REG13, 0x00);
+ //codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
+ }
+
+ INIT_DELAYED_WORK(&es8396->adc_depop_work, adc_depop_work_events);
+ mutex_init(&es8396->adc_depop_mlock);
+ INIT_DELAYED_WORK(&es8396->pcm_pop_work, pcm_pop_work_events);
+ mutex_init(&es8396->pcm_depop_mlock);
+
+ INIT_DELAYED_WORK(&es8396->voice_pop_work, voice_pop_work_events);
+ mutex_init(&es8396->voice_depop_mlock);
+
+ INIT_DELAYED_WORK(&es8396->init_cali_work, init_cali_work_events);
+ mutex_init(&es8396->init_cali_mlock);
+
+ INIT_DELAYED_WORK(&es8396->pcm_shutdown_depop_work,
+ pcm_shutdown_depop_events);
+ mutex_init(&es8396->pcm_shutdown_depop_mlock);
+
+ INIT_DELAYED_WORK(&es8396->voice_shutdown_depop_work,
+ voice_shutdown_depop_events);
+ mutex_init(&es8396->voice_shutdown_depop_mlock);
+
+ snd_soc_write(codec, 0x6f, 0x83);
+ snd_soc_write(codec, ES8396_SYS_VMID_REF_REG71, 0xFC);
+ msleep(100);
+ snd_soc_write(codec, 0x4E, 0x84);
+ snd_soc_write(codec, 0x4F, 0x85);
+ snd_soc_write(codec, 0x4A, 0x60);
+ snd_soc_write(codec, 0x4B, 0x60);
+ /*
+ * TODO: pop noise occur when HS calibration during probe
+ * increase the delay of a period of time if necessary
+ * msleep(50);
+ */
+ return ret;
+}
+
+static int es8396_remove(struct snd_soc_codec *codec)
+{
+ pr_debug("!!!!!!CODEC going into es8396_remove!!!!!!\n");
+
+ snd_soc_write(codec, 0X4E, 0x84);
+ snd_soc_write(codec, 0X4F, 0x85);
+ snd_soc_write(codec, 0X4A, 0x80);
+ snd_soc_write(codec, 0X4B, 0x80);
+ snd_soc_write(codec, 0x70, 0xd4);
+ msleep(300);
+
+ return 0;
+}
+
+const struct regmap_config es8396_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = ES8396_MAX_REGISTER,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = es8396_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(es8396_reg_defaults),
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_es8396 = {
+ .probe = es8396_probe,
+ .remove = es8396_remove,
+ .set_bias_level = es8396_set_bias_level,
+
+ .dapm_widgets = es8396_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(es8396_dapm_widgets),
+ .dapm_routes = es8396_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(es8396_dapm_routes),
+
+ .controls = es8396_snd_controls,
+ .num_controls = ARRAY_SIZE(es8396_snd_controls),
+/*
+ .reg_cache_size = ARRAY_SIZE(es8396_reg_defaults),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = es8396_reg_defaults,
+ .volatile_register = es8396_volatile_register,
+ .readable_register = es8396_readable_register,
+*/
+};
+
+static int init_es8396_prv(struct es8396_private *es8396)
+{
+ if (es8396 == NULL)
+ return -EINVAL;
+
+ es8396->dvdd_pwr_vol = 0x18;
+ es8396->spkmono = false;
+ es8396->earpiece = true;
+ es8396->monoin_differential = true;
+ es8396->lno_differential = 0;
+ es8396->ana_ldo_lvl = ANA_LDO_2_1V;
+ es8396->spk_ldo_lvl = SPK_LDO_3V;
+ es8396->mic_bias_lvl = MICBIAS_3V;
+ es8396->jackdet_enable = true;
+ es8396->gpio_int_pol = 0;
+ es8396->dmic_amic = MIC_AMIC;
+ es8396->calibrate = false;
+ es8396->pcm_pop_work_retry = 1;
+ es8396->output_device_selected = 0;
+ es8396->aif1_select = 0;
+ es8396->aif2_select = 0;
+ return 0;
+}
+
+static int es8396_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
+{
+ struct es8396_private *es8396;
+ int ret;
+ enum of_gpio_flags flags;
+ struct device_node *np = i2c_client->dev.of_node;
+
+ pr_debug("%s %d\n", __func__, __LINE__);
+ es8396 = devm_kzalloc(&i2c_client->dev, sizeof(struct es8396_private),
+ GFP_KERNEL);
+ if (!es8396) {
+ dev_err(&i2c_client->dev, "could not allocate codec\n");
+
+ return -ENOMEM;
+ }
+ /*
+ * INIT ES8396 private here
+ * TODO
+ * id->driver_data
+ */
+ ret = init_es8396_prv(es8396);
+ if (ret < 0)
+ return -EINVAL;
+
+ es8396->regmap = devm_regmap_init_i2c(i2c_client, &es8396_regmap_config);
+ if (IS_ERR(es8396->regmap)) {
+ ret = PTR_ERR(es8396->regmap);
+ dev_err(&i2c_client->dev, "Failed to init regmap: %d\n", ret);
+ return ret;
+ }
+
+ /* initialize codec */
+ i2c_set_clientdata(i2c_client, es8396);
+
+ /* external speaker amp controller */
+ es8396->spk_ctl_gpio = of_get_named_gpio_flags(np,
+ "spk-con-gpio", 0,
+ &flags);
+ if (es8396->spk_ctl_gpio < 0) {
+ pr_err("%s() Can not read property spk codec-en-gpio\n",
+ __func__);
+ es8396->spk_ctl_gpio = INVALID_GPIO;
+ } else {
+ pr_debug("%d() spk codec-en-gpio\n", es8396->spk_ctl_gpio);
+ es8396->spk_gpio_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
+ ret = devm_gpio_request(&i2c_client->dev, es8396->spk_ctl_gpio,
+ "spk_ctl");
+ if (!ret) {
+ pr_debug("requset codec-en-gpio success!:%d\n", ret);
+ gpio_direction_output(es8396->spk_ctl_gpio,
+ !es8396->spk_gpio_level);
+ } else {
+ pr_err("requset codec-en-gpio failed:%d\n", ret);
+ return ret;
+ }
+ }
+
+ /* lineout output controller*/
+ es8396->lineout_ctl_gpio = of_get_named_gpio_flags(np,
+ "lineout-con-gpio",
+ 0, &flags);
+ if (es8396->lineout_ctl_gpio < 0) {
+ pr_err("%s() Can not read property lineout en-gpio\n",
+ __func__);
+ es8396->lineout_ctl_gpio = INVALID_GPIO;
+ } else {
+ pr_debug("%d() lineout en-gpio\n", es8396->lineout_ctl_gpio);
+ es8396->lineout_gpio_level = (flags & OF_GPIO_ACTIVE_LOW) ?
+ 0 : 1;
+ ret = devm_gpio_request(&i2c_client->dev,
+ es8396->lineout_ctl_gpio,
+ "lineout_ctl");
+ if (!ret) {
+ pr_debug("requset lineout en-gpio success!:%d\n", ret);
+ gpio_direction_output(es8396->lineout_ctl_gpio,
+ !es8396->lineout_gpio_level);
+ } else {
+ pr_err("requset lineout en-gpio failed:%d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = snd_soc_register_codec(&i2c_client->dev,
+ &soc_codec_dev_es8396, es8396_dai,
+ ARRAY_SIZE(es8396_dai));
+
+ return ret;
+}
+
+static void es8396_i2c_shutdown(struct i2c_client *client)
+{
+ struct es8396_private *es8396 = i2c_get_clientdata(client);
+ pr_debug("Enter into %s\n", __func__);
+
+ if (es8396->spk_ctl_gpio != INVALID_GPIO)
+ gpio_set_value(es8396->spk_ctl_gpio, 0);
+
+ usleep_range(20000, 21000);
+ snd_soc_write(tron_codec, 0X4E, 0x84);
+ snd_soc_write(tron_codec, 0X4F, 0x85);
+ snd_soc_write(tron_codec, 0X4a, 0x80);
+ snd_soc_write(tron_codec, 0X4b, 0x80);
+ snd_soc_write(tron_codec, 0x70, 0xd4);
+ msleep(300);
+}
+
+static int es8396_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ i2c_set_clientdata(client, NULL);
+ return 0;
+}
+
+static const struct i2c_device_id es8396_id[] = {
+ {"es8396", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, es8396_id);
+static const struct dev_pm_ops es8396_pm_ops = {
+ .suspend = es8396_suspend,
+ .resume = es8396_resume,
+};
+
+static struct i2c_driver es8396_i2c_driver = {
+ .driver = {
+ .name = "es8396",
+ .owner = THIS_MODULE,
+ .pm = &es8396_pm_ops,
+ },
+ .id_table = es8396_id,
+ .probe = es8396_i2c_probe,
+ .shutdown = es8396_i2c_shutdown,
+ .remove = es8396_i2c_remove,
+};
+
+module_i2c_driver(es8396_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ES8396 driver");
+MODULE_AUTHOR("DavidYang, Everest Semiconductor Co., Ltd, <yangxiaohua@everest-semi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8396.h b/sound/soc/codecs/es8396.h
new file mode 100644
index 000000000000..927517e842cc
--- /dev/null
+++ b/sound/soc/codecs/es8396.h
@@ -0,0 +1,359 @@
+/*
+* ES8396.h -- ES8396 ALSA SoC Audio Codec
+**
+* Authors:
+*
+* Based on alc5632.h by Arnaud Patard
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*/
+
+#ifndef _ES8396_H
+#define _ES8396_H
+
+/* THE REGISTER DEFINITION FORMAT */
+/* ES8396_REGISTER NAME_REG_REGISTER ADDRESS */
+
+/* write 0x01 to Register 0x00 will reset all registers of codec.
+ * Register 0x00 must be cleared before normal
+*/
+#define ES8396_RESET_REG00 0x00
+
+/* Clock Scheme Register definition */
+/* Register 0x01 for MCLK source selection */
+#define ES8396_CLK_SRC_SEL_REG01 0x01
+/* Register 0x02 for PLL power down/up, reset, divider and divider dither */
+#define ES8396_PLL_CTRL_1_REG02 0x02
+/* Register 0x03 for PLL low power mode and PLL power supply selection */
+#define ES8396_PLL_CTRL_2_REG03 0x03
+/* Register 0x04 for PLL N cofficient, must be in 5 to 13 range*/
+#define ES8396_PLL_N_REG04 0x04
+/* Register 0x05-0x07 for PLL k cofficient*/
+#define ES8396_PLL_K2_REG05 0x05
+#define ES8396_PLL_K1_REG06 0x06
+#define ES8396_PLL_K0_REG07 0x07
+/* Register 0x08 for ADC,DAC CHARGE PUMP and CLASS D clock switch*/
+#define ES8396_CLK_CTRL_REG08 0x08
+/* Register 0x09 for ADC MCLK divider*/
+#define ES8396_ADC_CLK_DIV_REG09 0x09
+ /* Register 0x0A for DAC MCLK divider*/
+#define ES8396_DAC_CLK_DIV_REG0A 0x0A
+ /* Register 0x0B for CHARGE PUMP CLOCK divider*/
+#define ES8396_CP_CLK_DIV_REG0B 0x0B
+/* Register 0x0C for CLASS D Amplifier Clock divider*/
+#define ES8396_DAMP_CLK_DIV_REG0C 0x0C
+/* Register 0x0D for DLL control and DAC MCLK SELECTION*/
+#define ES8396_DLL_CTRL_REG0D 0x0D
+/* Register 0x0E for BCLK divider1 in I2S BUS Master mode*/
+#define ES8396_BCLK_DIV_M1_REG0E 0x0E
+/* Register 0x0F for BCLK divider2 in I2S BUS Master mode*/
+#define ES8396_BCLK_DIV_M2_REG0F 0x0F
+/* Register 0x10 for LRCK divider3 in I2S BUS Master mode*/
+#define ES8396_LRCK_DIV_M3_REG10 0x10
+/* Register 0x11 for LRCK divider4 in I2S BUS Master mode*/
+#define ES8396_LRCK_DIV_M4_REG11 0x11
+
+/* PAD MUX REGISTER DEFINITION */
+/* Register 0x12 for SDP1 Master or slave mode*/
+#define ES8396_SDP_1_MS_REG12 0x12
+/* Register 0x13 for SDP2 Master or slave mode*/
+#define ES8396_SDP_2_MS_REG13 0x13
+/* Register 0x14 for SDP1 Master or slave mode*/
+#define ES8396_SDP_3_MS_REG14 0x14
+/* Register 0x15 for ADLRCK or GPIO control*/
+#define ES8396_ALRCK_GPIO_SEL_REG15 0x15
+
+/* GPIO REGISTER DEFINITION */
+/* Register 0x16 for GPIO interrupt*/
+#define ES8396_GPIO_IRQ_REG16 0x16
+/* Register 0x17 for GPIO STATUS*/
+#define ES8396_GPIO_STA_REG17 0x17
+
+/* Digital Mixer Register Definition */
+/* Register 0x18 for Digital Mixer Source*/
+#define ES8396_DMIX_SRC_1_REG18 0x18
+/* Register 0x19 for Digital Mixer Source*/
+#define ES8396_DMIX_SRC_2_REG19 0x19
+/* Register 0x1A for DAC Digital Source and SDP1 Digital Output Source*/
+#define ES8396_DAC_SRC_SDP1O_SRC_REG1A 0x1A
+/* Register 0x1B for SDP2 and SDP3 Digital Output Source*/
+#define ES8396_SDP2O_SDP3O_SRC_REG1B 0x1B
+/* Register 0x1C for EQ CLOCK and OSR Selection*/
+#define ES8396_EQ_CLK_OSR_SEL_REG1C 0x1C
+/* Register 0x1D for Address of shared register map*/
+#define ES8396_SHARED_ADDR_REG1D 0x1D
+/* Register 0x1E for DATA of shared register map*/
+#define ES8396_SHARED_DATA_REG1E 0x1E
+
+/* Serial AUDIO Interface Register Definition */
+/* Register 0x1F for SDP1 INPUT FORMAT*/
+#define ES8396_SDP1_IN_FMT_REG1F 0x1F
+/* Register 0x20 for SDP1 OUTPUT FORMAT*/
+#define ES8396_SDP1_OUT_FMT_REG20 0x20
+/* Register 0x21 for SDP1 Digital GAIN AND TDM MODE*/
+#define ES8396_SDP1_DGAIN_TDM_REG21 0x21
+/* Register 0x22 for SDP2 INPUT FORMAT*/
+#define ES8396_SDP2_IN_FMT_REG22 0x22
+/* Register 0x23 for SDP2 OUTPUT FORMAT*/
+#define ES8396_SDP2_OUT_FMT_REG23 0x23
+/* Register 0x24 for SDP3 INPUT FORMAT*/
+#define ES8396_SDP3_IN_FMT_REG24 0x24
+/* Register 0x25 for SDP3 OUTPUT FORMAT*/
+#define ES8396_SDP3_OUT_FMT_REG25 0x25
+
+/* SPEAKER MIXER Register Definition */
+/* Register 0x26 for SPK MIXER*/
+#define ES8396_SPK_MIXER_REG26 0x26
+/* Register 0x27 for SPK MIXER BOOST GAIN*/
+#define ES8396_SPK_MIXER_BOOST_REG27 0x27
+/* Register 0x28 for SPK MIXER VOLUME*/
+#define ES8396_SPK_MIXER_VOL_REG28 0x28
+/* Register 0x29 for SPK MIXER REFERENCE AND LOW POWER MODE*/
+#define ES8396_SPK_MIXER_REF_LP_REG29 0x29
+
+/* HP MIXER Register Definition */
+/* Register 0x2A for HP MIXER*/
+#define ES8396_HP_MIXER_REG2A 0x2A
+/* Register 0x2B for HP MIXER BOOST GAIN*/
+#define ES8396_HP_MIXER_BOOST_REG2B 0x2B
+/* Register 0x2C for HP MIXER VOLUME*/
+#define ES8396_HP_MIXER_VOL_REG2C 0x2C
+/* Register 0x2D for HP MIXER REFERENCE AND LOW POWER MODE*/
+#define ES8396_HP_MIXER_REF_LP_REG2D 0x2D
+
+/* AX MIXER Register Definition */
+/* Register 0x2E for AX MIXER*/
+#define ES8396_AX_MIXER_REG2E 0x2E
+/* Register 0x2F for AX MIXER BOOST GAIN*/
+#define ES8396_AX_MIXER_BOOST_REG2F 0x2F
+/* Register 0x30 for AX MIXER VOLUME*/
+#define ES8396_AX_MIXER_VOL_REG30 0x30
+/* Register 0x31 for AX MIXER REFERENCE AND LOW POWER MODE*/
+#define ES8396_AX_MIXER_REF_LP_REG31 0x31
+
+/* LN MIXER Register Definition */
+/* Register 0x32 for LN MIXER*/
+#define ES8396_LN_MIXER_REG32 0x32
+/* Register 0x33 for LN MIXER BOOST GAIN*/
+#define ES8396_LN_MIXER_BOOST_REG33 0x33
+/* Register 0x34 for LN MIXER VOLUME*/
+#define ES8396_LN_MIXER_VOL_REG34 0x34
+/* Register 0x35 for LN MIXER REFERENCE AND LOW POWER MODE*/
+#define ES8396_LN_MIXER_REF_LP_REG35 0x35
+
+/* MN MIXER Register Definition */
+/* Register 0x36 for MN MIXER*/
+#define ES8396_MN_MIXER_REG36 0x36
+/* Register 0x37 for MN MIXER BOOST GAIN*/
+#define ES8396_MN_MIXER_BOOST_REG37 0x37
+/* Register 0x38 for MN MIXER VOLUME*/
+#define ES8396_MN_MIXER_VOL_REG38 0x38
+/* Register 0x39 for MN MIXER REFERENCE AND LOW POWER MODE*/
+#define ES8396_MN_MIXER_REF_LP_REG39 0x39
+
+/* SPKD Register Definition */
+/* Register 0x3A for CLASS D control and SOURCE SELECTION*/
+#define ES8396_SPK_CTRL_SRC_REG3A 0x3A
+/* Register 0x3B for CLASS D Enabled and Volume Control*/
+#define ES8396_SPK_EN_VOL_REG3B 0x3B
+/* Register 0x3C for CLASS D CONTROL */
+#define ES8396_SPK_CTRL_1_REG3C 0x3C
+/* Register 0x3D for CLASS D CONTROL*/
+#define ES8396_SPK_CTRL_2_REG3D 0x3D
+
+/* CPHP Register Definition */
+/* Register 0x3E for CPHP HPL ICAL VALUE*/
+#define ES8396_CPHP_HPL_ICAL_REG3E 0x3E
+/* Register 0x3F for CPHP HPR ICAL VALUE*/
+#define ES8396_CPHP_HPR_ICAL_REG3F 0x3F
+/* Register 0x40 for CPHP ENABLE */
+#define ES8396_CPHP_ENABLE_REG40 0x40
+/* Register 0x41 for CPHP VOLUME AND ICAL ENABLE*/
+#define ES8396_CPHP_ICAL_VOL_REG41 0x41
+/* Register 0x42 for CPHP CONTROL */
+#define ES8396_CPHP_CTRL_1_REG42 0x42
+/* Register 0x43 for CPHP CONTROL*/
+#define ES8396_CPHP_CTRL_2_REG43 0x43
+/* Register 0x44 for CPHP CONTROL*/
+#define ES8396_CPHP_CTRL_3_REG44 0x44
+
+/* MONOHP Register Definition */
+/* Register 0x45 for MONOHP REFERENCE AND LOW POWER MODE*/
+#define ES8396_MONOHP_REF_LP_REG45 0x45
+/* Register 0x46 for MONOHP N MIXER*/
+#define ES8396_MONOHP_N_MIXER_REG46 0x46
+/* Register 0x47 for MONOHP P MIXER */
+#define ES8396_MONOHP_P_MIXER_REG47 0x47
+/* Register 0x48 for MONOHP P BOOST AND MUTE CONTROL*/
+#define ES8396_MONOHP_P_BOOST_MUTE_REG48 0x48
+/* Register 0x49 for MONOHP N BOOST AND MUTE CONTROL */
+#define ES8396_MONOHP_N_BOOST_MUTE_REG49 0x49
+
+/* LNOUT Register Definition */
+/* Register 0x4A for LNOUT LOUT1 ENABLE AND MIXER*/
+#define ES8396_LNOUT_LO1EN_LO1MIX_REG4A 0x4A
+/* Register 0x4B for LNOUT ROUT1 ENABLE AND MIXER*/
+#define ES8396_LNOUT_RO1EN_RO1MIX_REG4B 0x4B
+/* Register 0x4C for LNOUT LOUT2 ENABLE AND MIXER*/
+#define ES8396_LNOUT_LO2EN_LO2MIX_REG4C 0x4C
+/* Register 0x4D for LNOUT ROUT2 ENABLE AND MIXER*/
+#define ES8396_LNOUT_RO2EN_RO2MIX_REG4D 0x4D
+/* Register 0x4E for LNOUT LOUT1 GAIN CONTROL */
+#define ES8396_LNOUT_LO1_GAIN_CTRL_REG4E 0x4E
+/* Register 0x4F for LNOUT ROUT1 GAIN CONTROL */
+#define ES8396_LNOUT_RO1_GAIN_CTRL_REG4F 0x4F
+/* Register 0x50 for LNOUT LOUT2 GAIN CONTROL */
+#define ES8396_LNOUT_LO2_GAIN_CTRL_REG50 0x50
+/* Register 0x51 for LNOUT ROUT2 GAIN CONTROL */
+#define ES8396_LNOUT_RO2_GAIN_CTRL_REG51 0x51
+/* Register 0x52 for LNOUT REFERENCE */
+#define ES8396_LNOUT_REFERENCE_REG52 0x52
+
+/* ADC Register Definition */
+/* Register 0x53 for ADC CHIP STATE MACHINE and Digital Control*/
+#define ES8396_ADC_CSM_REG53 0x53
+/* Register 0x54 for ADC DMIC and Ramp Rate*/
+#define ES8396_ADC_DMIC_RAMPRATE_REG54 0x54
+/* Register 0x55 for ADC HIGH PASS FILTER,U-LAW/A-LAW COMPMODE,DATA SELECTION*/
+#define ES8396_ADC_HPF_COMP_DASEL_REG55 0x55
+/* Register 0x56 for ADC LEFT ADC VOLUME*/
+#define ES8396_ADC_LADC_VOL_REG56 0x56
+/* Register 0x57 for ADC RIGHT ADC VOLUME */
+#define ES8396_ADC_RADC_VOL_REG57 0x57
+/* Register 0x58 for ADC ALC CONTROL 1*/
+#define ES8396_ADC_ALC_CTRL_1_REG58 0x58
+/* Register 0x59 for ADC ALC CONTROL 2 */
+#define ES8396_ADC_ALC_CTRL_2_REG59 0x59
+/* Register 0x5A for ADC ALC CONTROL 3 */
+#define ES8396_ADC_ALC_CTRL_3_REG5A 0x5A
+/* Register 0x5B for ADC ALC CONTROL 4 */
+#define ES8396_ADC_ALC_CTRL_4_REG5B 0x5B
+/* Register 0x5C for ADC ALC CONTROL 5*/
+#define ES8396_ADC_ALC_CTRL_5_REG5C 0x5C
+/* Register 0x5D for ADC ALC CONTROL 6*/
+#define ES8396_ADC_ALC_CTRL_6_REG5D 0x5D
+/* Register 0x5E for ADC ANALOG CONTROL*/
+#define ES8396_ADC_ANALOG_CTRL_REG5E 0x5E
+/* Register 0x5F for ADC LOW POWER MODE AND REFERENCE*/
+#define ES8396_ADC_LP_REFERENCE_REG5F 0x5F
+/* Register 0x60 for ADC MIC BOOST */
+#define ES8396_ADC_MICBOOST_REG60 0x60
+/* Register 0x61 for ADC L/R PGA GAIN */
+#define ES8396_ADC_PGA_GAIN_REG61 0x61
+/* Register 0x62 for ADC LPGA MIXER */
+#define ES8396_ADC_LPGA_MIXER_REG62 0x62
+/* Register 0x63 for ADC RPGA MIXER */
+#define ES8396_ADC_RPGA_MIXER_REG63 0x63
+/* Register 0x64 for ADC LNMUX */
+#define ES8396_ADC_LN_MUX_REG64 0x64
+/* Register 0x65 for ADC AXMUX */
+#define ES8396_ADC_AX_MUX_REG65 0x65
+
+/* DAC Register Definition */
+/* Register 0x66 for DAC CHIP STATE MACHINE AND MUTE CONTROL*/
+#define ES8396_DAC_CSM_REG66 0x66
+/* Register 0x67 for DAC RAMPE RATE AND MONO/ZERO CONTROL*/
+#define ES8396_DAC_RAMP_RATE_REG67 0x67
+/* Register 0x68 for DAC STEREO ENHANCEMENT */
+#define ES8396_DAC_STEREO_ENHANCE_REG68 0x68
+/* Register 0x69 for DAC JACK DETECTION AND U/A-LAW COMPRESS */
+#define ES8396_DAC_JACK_DET_COMP_REG69 0x69
+/* Register 0x6A for DAC LEFT DAC VOLUME */
+#define ES8396_DAC_LDAC_VOL_REG6A 0x6A
+/* Register 0x6B for DAC RIGHT DAC VOLUME */
+#define ES8396_DAC_RDAC_VOL_REG6B 0x6B
+/* Register 0x6C for DAC LIMITER CONTROL 1 */
+#define ES8396_DAC_DPL_CTRL_1_REG6C 0x6C
+/* Register 0x6D for DAC LIMITER CONTROL 2 */
+#define ES8396_DAC_DPL_CTRL_2_REG6D 0x6D
+/* Register 0x6E for DAC REFERENCE AND POWER CONTROL */
+#define ES8396_DAC_REF_PWR_CTRL_REG6E 0x6E
+/* Register 0x6F for DAC DC OFFSET CALIBRATION */
+#define ES8396_DAC_OFFSET_CALI_REG6F 0x6F
+
+/* SYSTEM Register Definition */
+/* Register 0x70 for CHIP ANALOG CONTROL,
+ * SUCH AS ANALOG POWER CONTROL, AVDDLDO POWER CONTROL */
+#define ES8396_SYS_CHIP_ANA_CTL_REG70 0x70
+/* Register 0x71 for VMID SELECTION AND REFERENCE */
+#define ES8396_SYS_VMID_REF_REG71 0x71
+/* Register 0x72 for VSEL 1 */
+#define ES8396_SYS_VSEL_1_REG72 0x72
+/* Register 0x73 for VSEL 2 */
+#define ES8396_SYS_VSEL_2_REG73 0x73
+/* Register 0x74 for MICBIAS CONTROL */
+#define ES8396_SYS_MICBIAS_CTRL_REG74 0x74
+/* Register 0x75 for MIC ENABLE AND IBIASGEN SELECTION*/
+#define ES8396_SYS_MIC_IBIAS_EN_REG75 0x75
+
+/* undocumented */
+/* Write 0XA0 TO REG0X76 to ENABLE TEST MODE*/
+#define ES8396_TEST_MODE_REG76 0x76
+#define ES8396_ADC_FORCE_REG77 0x77
+#define ES8396_NGTH_REG7A 0X7A
+#define ES8396_MAX_REGISTER 0x7F
+
+#define NO_EVENT 0
+#define JD_EVENT 1
+#define BOT_EVENT 2
+
+#define DET_HEADPHONE 1
+#define DET_HEADSET 2
+
+#define BOT_NULL 0
+#define BOT_DWN 1
+
+#define MICBIAS_3V 7
+#define MICBIAS_2_8V 6
+#define MICBIAS_2_5V 1
+#define MICBIAS_2_3V 2
+#define MICBIAS_2V 4
+#define MICBIAS_1_5V 0
+
+#define MIC_AMIC 0
+#define MIC_DMIC 1
+
+#define ANA_LDO_3V 3
+#define ANA_LDO_2_9V 2
+#define ANA_LDO_2_8V 1
+#define ANA_LDO_2_7V 0
+#define ANA_LDO_2_4V 7
+#define ANA_LDO_2_3V 6
+#define ANA_LDO_2_2V 5
+#define ANA_LDO_2_1V 4
+
+#define SPK_LDO_3_3V 3
+#define SPK_LDO_3_2V 2
+#define SPK_LDO_3V 1
+#define SPK_LDO_2_9V 0
+#define SPK_LDO_2_8V 7
+#define SPK_LDO_2_6V 6
+#define SPK_LDO_2_5V 5
+#define SPK_LDO_2_4V 4
+
+#define ES8396_AIF_MUTE 0x40
+
+#define ES8396_SDP1 0
+#define ES8396_SDP2 1
+#define ES8396_SDP3 2
+/*
+* es8396 System clock derived from MCLK or BCLK
+*/
+#define ES8396_CLKID_MCLK 0
+#define ES8396_CLKID_BCLK 1
+#define ES8396_CLKID_PLLO 2
+/*
+* PLL clock source
+*/
+#define ES8396_PLL 0
+
+#define ES8396_PLL_NO_SRC_0 0
+#define ES8396_PLL_SRC_FRM_MCLK 1
+#define ES8396_PLL_NO_SRC_1 2
+#define ES8396_PLL_SRC_FRM_BCLK 3
+
+#define MS_MASTER (0x24)
+
+#endif