Alsa-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ASoC: codecs: add support for ES8326
@ 2022-04-05 13:12 Zhu Ning
  2022-04-05 14:02 ` Mark Brown
  0 siblings, 1 reply; 11+ messages in thread
From: Zhu Ning @ 2022-04-05 13:12 UTC (permalink / raw)
  To: alsa-devel; +Cc: Zhu Ning, broonie, pierre-louis.bossart, yangxiaohua, tiwai

From: yangxiaohua <yangxiaohua@everest-semi.com>

The ES8326 codec is not compatible with ES8316 and requires a dedicated driver.

Signed-off-by: David Yang <yangxiaohua@everest-semi.com>
Signed-off-by: Zhu Ning <zhuning@everest-semi.com>
---
 sound/soc/codecs/Kconfig  |   5 +
 sound/soc/codecs/Makefile |   2 +
 sound/soc/codecs/es8326.c | 753 ++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/es8326.h | 184 ++++++++++
 4 files changed, 944 insertions(+)
 create mode 100755 sound/soc/codecs/es8326.c
 create mode 100755 sound/soc/codecs/es8326.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index c2627f7489a4..66bc2358e31e 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -95,6 +95,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_DA9055
 	imply SND_SOC_DMIC
 	imply SND_SOC_ES8316
+	imply SND_SOC_ES8326
 	imply SND_SOC_ES8328_SPI
 	imply SND_SOC_ES8328_I2C
 	imply SND_SOC_ES7134
@@ -867,6 +868,10 @@ config SND_SOC_ES8316
 	tristate "Everest Semi ES8316 CODEC"
 	depends on I2C
 
+config SND_SOC_ES8326
+	tristate "Everest Semi ES8326 CODEC"
+	depends on I2C
+
 config SND_SOC_ES8328
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index b4e11c3e4a08..73043d5bc1ea 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -95,6 +95,7 @@ snd-soc-dmic-objs := dmic.o
 snd-soc-es7134-objs := es7134.o
 snd-soc-es7241-objs := es7241.o
 snd-soc-es8316-objs := es8316.o
+snd-soc-es8326-objs := es8326.o
 snd-soc-es8328-objs := es8328.o
 snd-soc-es8328-i2c-objs := es8328-i2c.o
 snd-soc-es8328-spi-objs := es8328-spi.o
@@ -437,6 +438,7 @@ obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_ES7134)	+= snd-soc-es7134.o
 obj-$(CONFIG_SND_SOC_ES7241)	+= snd-soc-es7241.o
 obj-$(CONFIG_SND_SOC_ES8316)    += snd-soc-es8316.o
+obj-$(CONFIG_SND_SOC_ES8326)    += snd-soc-es8326.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
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
new file mode 100755
index 000000000000..a80649e04aa6
--- /dev/null
+++ b/sound/soc/codecs/es8326.c
@@ -0,0 +1,753 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * es8326.c -- es8326 ALSA SoC audio driver
+ * Copyright Everest Semiconductor Co., Ltd
+ *
+ * Authors: David Yang <yangxiaohua@everest-semi.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "es8326.h"
+
+struct es8326_priv {
+	struct clk *mclk;
+	struct snd_pcm_hw_constraint_list *sysclk_constraints;
+	struct i2c_client *i2c;
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct delayed_work jack_detect_work;
+	bool amic;
+	bool start;
+	bool muted;
+	bool hp_inserted;
+	bool spk_gpio_level;
+	bool hp_det_level;
+	struct snd_soc_jack *jack;
+	int irq;
+	/* The lock protects the situation that an irq is generated
+	 * while the previous irq is still being processed.
+	 */
+	struct mutex lock;
+	u8 amic1_src;
+	u8 amic2_src;
+	u8 mic1_src;
+	u8 mic2_src;
+	u8 jack_pol;
+	bool jd_inverted;
+	unsigned int sysclk;
+};
+
+static void es8326_jack_detect_handler(struct work_struct *work)
+{
+	struct es8326_priv *es8326 =
+		container_of(work, struct es8326_priv, jack_detect_work.work);
+	struct snd_soc_component *comp = es8326->component;
+	unsigned int iface;
+
+	iface = snd_soc_component_read(comp, ES8326_HP_DECTECT_FB);
+	dev_dbg(comp->dev, "gpio flag %#04x", iface);
+	if ((iface & ES8326_HPINSERT_FLAG) == 0) {
+		dev_dbg(comp->dev, "No headset detected");
+		snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
+		snd_soc_component_write(comp, ES8326_ADC1_SRC_2A, es8326->mic2_src);
+		snd_soc_component_update_bits(comp, ES8326_PAGGAIN_23,
+					      ES8326_MIC_SEL_MASK, es8326->amic2_src);
+		snd_soc_component_write(comp, ES8326_ANA_MICBIAS_1B, 0x70);
+	} else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) {
+		if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) {
+			dev_dbg(comp->dev, "Headset detected");
+			snd_soc_jack_report(es8326->jack, SND_JACK_HEADSET, SND_JACK_HEADSET);
+			snd_soc_component_write(comp, ES8326_ADC1_SRC_2A, es8326->mic1_src);
+			snd_soc_component_update_bits(comp, ES8326_PAGGAIN_23,
+						      ES8326_MIC_SEL_MASK, es8326->amic1_src);
+		} else {
+			dev_dbg(comp->dev, "Headphone detected");
+			snd_soc_jack_report(es8326->jack, SND_JACK_HEADPHONE, SND_JACK_HEADSET);
+		}
+	}
+}
+
+static irqreturn_t es8326_irq(int irq, void *dev_id)
+{
+	struct es8326_priv *es8326 = dev_id;
+	struct snd_soc_component *comp = es8326->component;
+
+	snd_soc_component_write(comp, ES8326_ANA_MICBIAS_1B, 0x7c);
+
+	queue_delayed_work(system_wq, &es8326->jack_detect_work,
+			   msecs_to_jiffies(500));
+
+	return IRQ_HANDLED;
+}
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9550, 50, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_analog_pga_tlv, 0, 300, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_pga_tlv, 0, 600, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(softramp_rate, 0, 100, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(drc_target_tlv, -3200, 200, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(drc_recovery_tlv, -125, 250, 0);
+
+static const char *const winsize[] = {
+	"0.25db/2  LRCK",
+	"0.25db/4  LRCK",
+	"0.25db/8  LRCK",
+	"0.25db/16  LRCK",
+	"0.25db/32  LRCK",
+	"0.25db/64  LRCK",
+	"0.25db/128  LRCK",
+	"0.25db/256  LRCK",
+	"0.25db/512  LRCK",
+	"0.25db/1024  LRCK",
+	"0.25db/2048  LRCK",
+	"0.25db/4096  LRCK",
+	"0.25db/8192  LRCK",
+	"0.25db/16384  LRCK",
+	"0.25db/32768  LRCK",
+	"0.25db/65536  LRCK",
+};
+
+static const char *const dacpol_txt[] =	{
+	"Normal", "R Invert", "L Invert", "L + R Invert" };
+static const struct soc_enum dacpol =
+	SOC_ENUM_SINGLE(0x4d, 4, 4, dacpol_txt);
+static const struct soc_enum alc_winsize =
+	SOC_ENUM_SINGLE(0x2e, 4, 16, winsize);
+static const struct soc_enum drc_winsize =
+	SOC_ENUM_SINGLE(0x54, 4, 16, winsize);
+static const struct snd_kcontrol_new es8326_snd_controls[] = {
+	SOC_SINGLE_TLV("DAC Playback Volume", ES8326_DAC_VOL_50, 0, 0xff, 0, dac_vol_tlv),
+	SOC_ENUM("Playback Polarity", dacpol),
+	SOC_SINGLE_TLV("DAC Ramp Rate", ES8326_DAC_RAMPRATE_4E, 0, 0x0f, 0, softramp_rate),
+	SOC_SINGLE("DRC Switch", ES8326_DRC_RECOVERY_53, 3, 1, 0),
+	SOC_SINGLE_TLV("DRC Recovery Level", ES8326_DRC_RECOVERY_53, 0, 4, 0, drc_recovery_tlv),
+	SOC_ENUM("DRC Winsize", drc_winsize),
+	SOC_SINGLE_TLV("DRC Target Level", ES8326_DRC_WINSIZE_54, 0, 0x0f, 0, drc_target_tlv),
+
+	SOC_DOUBLE_R_TLV("ADC Capture Volume", ES8326_ADC1_VOL_2C, ES8326_ADC2_VOL_2D, 0, 0xff, 0,
+			 adc_vol_tlv),
+	SOC_DOUBLE_TLV("ADC PGA Gain", ES8326_ADC_SCALE_29, 4, 0, 5, 0, adc_pga_tlv),
+	SOC_SINGLE_TLV("ADC Analog PGA Gain", ES8326_PAGGAIN_23, 0, 10, 0, adc_analog_pga_tlv),
+	SOC_SINGLE_TLV("ADC Ramp Rate", ES8326_ADC_RAMPRATE_2E, 0, 0x0f, 0, softramp_rate),
+	SOC_SINGLE("ALC Switch", ES8326_ALC_RECOVERY_32, 3, 1, 0),
+	SOC_SINGLE_TLV("ALC Recovery Level", ES8326_ALC_LEVEL_33, 0, 4, 0, drc_recovery_tlv),
+	SOC_ENUM("ALC Winsize", alc_winsize),
+	SOC_SINGLE_TLV("ALC Target Level", ES8326_ALC_LEVEL_33, 0, 0x0f, 0, drc_target_tlv),
+};
+
+static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+
+	SND_SOC_DAPM_ADC("Right ADC", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("Left ADC", NULL, SND_SOC_NOPM, 0, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_DAC("Right DAC", NULL, ES8326_ANA_PDN_16, 0, 1),
+	SND_SOC_DAPM_DAC("Left DAC", NULL, ES8326_ANA_PDN_16, 1, 1),
+	SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX_25, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX_25, 3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HPOR Cal", ES8326_HP_CAL_27, 7, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HPOL Cal", ES8326_HP_CAL_27, 3, 1, NULL, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL_27,
+			 ES8326_HPOR_SHIFT, 7, 7, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL_27,
+			 0, 7, 7, 0),
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_route es8326_dapm_routes[] = {
+	{"Left ADC", NULL, "MIC1"},
+	{"Right ADC", NULL, "MIC2"},
+
+	{"I2S OUT", NULL, "Left ADC"},
+	{"I2S OUT", NULL, "Right ADC"},
+
+	{"Right DAC", NULL, "I2S IN"},
+	{"Left DAC", NULL, "I2S IN"},
+
+	{"LHPMIX", NULL, "Left DAC"},
+	{"RHPMIX", NULL, "Right DAC"},
+
+	{"HPOR", NULL, "HPOR Cal"},
+	{"HPOL", NULL, "HPOL Cal"},
+	{"HPOR", NULL, "HPOR Supply"},
+	{"HPOL", NULL, "HPOL Supply"},
+
+	{"HPOL", NULL, "LHPMIX"},
+	{"HPOR", NULL, "RHPMIX"},
+};
+
+static const struct regmap_range es8316_volatile_ranges[] = {
+	regmap_reg_range(ES8326_HP_DECTECT_FB, ES8326_HP_DECTECT_FB),
+};
+
+static const struct regmap_access_table es8316_volatile_table = {
+	.yes_ranges = es8316_volatile_ranges,
+	.n_yes_ranges = ARRAY_SIZE(es8316_volatile_ranges),
+};
+
+const struct regmap_config es8326_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = 0xff,
+	.volatile_table = &es8316_volatile_table,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+struct _coeff_div {
+	u16 fs;
+	u32 rate;
+	u32 mclk;
+	u8 reg4;
+	u8 reg5;
+	u8 reg6;
+	u8 reg7;
+	u8 reg8;
+	u8 reg9;
+	u8 rega;
+	u8 regb;
+};
+
+/* codec hifi mclk clock divider coefficients */
+/* {ratio, LRCK, MCLK, REG04, REG05, REG06, REG07, REG08, REG09, REG10, REG11} */
+static const struct _coeff_div coeff_div[] = {
+	{32, 8000, 256000, 0x60, 0x00, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{32, 16000, 512000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{32, 44100, 1411200, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{32, 48000, 1536000, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{36, 8000, 288000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+	{36, 16000, 576000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+	{48, 8000, 384000, 0x60, 0x02, 0x1F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{48, 16000, 768000, 0x20, 0x02, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{48, 48000, 2304000, 0x00, 0x02, 0x0D, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{64, 8000, 512000, 0x60, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{64, 16000, 1024000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{64, 44100, 2822400, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{64, 48000, 3072000, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{72, 8000, 576000, 0x20, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{72, 16000, 1152000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+	{96, 8000, 768000, 0x60, 0x02, 0x1D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{96, 16000, 1536000, 0x20, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{100, 48000, 4800000, 0x04, 0x01, 0x0F, 0x6D, 0x38, 0x08, 0x53, 0x28},
+	{125, 48000, 6000000, 0x04, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{128, 8000, 1024000, 0x60, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{128, 16000, 2048000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{128, 44100, 5644800, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{128, 48000, 6144000, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{144, 8000, 1152000, 0x20, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{144, 16000, 2304000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{192, 8000, 1536000, 0x60, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{192, 16000, 3072000, 0x20, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{200, 48000, 9600000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{250, 48000, 12000000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{256, 8000, 2048000, 0x60, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{256, 16000, 4096000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{256, 44100, 11289600, 0x00, 0x00, 0x10, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{256, 48000, 12288000, 0x00, 0x00, 0x30, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{288, 8000, 2304000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{384, 8000, 3072000, 0x60, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{384, 16000, 6144000, 0x20, 0x02, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{384, 48000, 18432000, 0x00, 0x02, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{400, 48000, 19200000, 0x09, 0x04, 0x0f, 0x6d, 0x3a, 0x0A, 0x4F, 0x1F},
+	{500, 48000, 24000000, 0x18, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{512, 8000, 4096000, 0x60, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{512, 16000, 8192000, 0x20, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{512, 44100, 22579200, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{512, 48000, 24576000, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{768, 8000, 6144000, 0x60, 0x02, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{768, 16000, 12288000, 0x20, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{800, 48000, 38400000, 0x00, 0x18, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{1024, 8000, 8192000, 0x60, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{1024, 16000, 16384000, 0x20, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{1152, 16000, 18432000, 0x20, 0x08, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{1536, 8000, 12288000, 0x60, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+
+	{1536, 16000, 24576000, 0x20, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{1625, 8000, 13000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{1625, 16000, 26000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{2048, 8000, 16384000, 0x60, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{2304, 8000, 18432000, 0x40, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x5F},
+	{3072, 8000, 24576000, 0x60, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{3250, 8000, 26000000, 0x0C, 0x18, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static unsigned int es8326_rates[] = {
+	8000, 12000, 16000, 24000, 32000, 48000, 96000
+};
+
+static struct snd_pcm_hw_constraint_list es8326_constraints = {
+	.count = ARRAY_SIZE(es8326_rates),
+	.list = es8326_rates,
+};
+
+/*
+ * Note that this should be called from init rather than from hw_params.
+ */
+static int es8326_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *codec = codec_dai->component;
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec);
+
+	es8326->sysclk = freq;
+
+	if (freq == 0) {
+		es8326->sysclk_constraints->list = NULL;
+		es8326->sysclk_constraints->count = 0;
+		return 0;
+	}
+
+	es8326->sysclk_constraints = &es8326_constraints;
+	return 0;
+}
+
+static int es8326_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u8 iface = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+	case SND_SOC_DAIFMT_CBP_CFP:
+		snd_soc_component_update_bits(component, ES8326_RESET_00,
+					      ES8326_MASTER_MODE_EN, ES8326_MASTER_MODE_EN);
+		break;
+	case SND_SOC_DAIFMT_CBC_CFC:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		dev_err(component->dev, "Codec driver does not support right justified\n");
+		return -EINVAL;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= ES8326_DAIFMT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= ES8326_DAIFMT_DSP_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= ES8326_DAIFMT_DSP_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, ES8326_FMT_13, ES8326_DAIFMT_MASK, iface);
+
+	return 0;
+}
+
+static int es8326_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *codec = dai->component;
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec);
+	u8 srate = 0;
+	int coeff;
+
+	coeff = get_coeff(es8326->sysclk, params_rate(params));
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		srate |= ES8326_S16_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		srate |= ES8326_S20_3_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S18_3LE:
+		srate |= ES8326_S18_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		srate |= ES8326_S24_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		srate |= ES8326_S32_LE;
+		break;
+	default:
+		break;
+	}
+
+	/* set iface & srate */
+	snd_soc_component_update_bits(codec, ES8326_FMT_13, ES8326_DATA_LEN_MASK, srate);
+
+	if (coeff >= 0) {
+		regmap_write(es8326->regmap,  ES8326_CLK_DIV1_04,
+			     coeff_div[coeff].reg4);
+		regmap_write(es8326->regmap,  ES8326_CLK_DIV2_05,
+			     coeff_div[coeff].reg5);
+		regmap_write(es8326->regmap,  ES8326_CLK_DLL_06,
+			     coeff_div[coeff].reg6);
+		regmap_write(es8326->regmap,  ES8326_CLK_MUX_07,
+			     coeff_div[coeff].reg7);
+		regmap_write(es8326->regmap,  ES8326_CLK_ADC_SEL_08,
+			     coeff_div[coeff].reg8);
+		regmap_write(es8326->regmap,  ES8326_CLK_DAC_SEL_09,
+			     coeff_div[coeff].reg9);
+		regmap_write(es8326->regmap,  ES8326_CLK_ADC_OSR_0A,
+			     coeff_div[coeff].rega);
+		regmap_write(es8326->regmap,  ES8326_CLK_DAC_OSR_0B,
+			     coeff_div[coeff].regb);
+	}
+
+	return 0;
+}
+
+static int es8326_set_bias_level(struct snd_soc_component *codec,
+				 enum snd_soc_bias_level level)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		if (!IS_ERR(es8326->mclk)) {
+			if (snd_soc_component_get_bias_level(codec) == SND_SOC_BIAS_ON) {
+				clk_disable_unprepare(es8326->mclk);
+			} else {
+				ret = clk_prepare_enable(es8326->mclk);
+				if (ret)
+					return ret;
+			}
+		}
+		regmap_write(es8326->regmap, ES8326_CLK_CTL_01, ES8326_CLK_ON);
+		regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_PWRUP_SEQ_EN);
+		regmap_write(es8326->regmap, ES8326_INTOUT_IO_59, 0x45);
+		regmap_write(es8326->regmap, ES8326_SDINOUT1_IO_5A,
+			    (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT));
+		regmap_write(es8326->regmap, ES8326_SDINOUT23_IO_5B, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE_03, 0x05);
+		regmap_write(es8326->regmap, ES8326_HP_DRVIER_24, 0x00);
+		regmap_write(es8326->regmap, ES8326_VMIDSEL_18, 0x02);
+		regmap_write(es8326->regmap, ES8326_ANA_PDN_16, 0x00);
+		regmap_write(es8326->regmap, ES8326_PGA_PDN_17, 0x40);
+		regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0xAA);
+		regmap_write(es8326->regmap, ES8326_ADC_MUTE_15, 0x00);
+		regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_ON);
+
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		break;
+	case SND_SOC_BIAS_OFF:
+		if (es8326->mclk)
+			clk_disable_unprepare(es8326->mclk);
+		regmap_write(es8326->regmap, ES8326_ADC_MUTE_15, 0x1F);
+		regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0x11);
+		regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_OFF);
+		regmap_write(es8326->regmap, ES8326_PGA_PDN_17, 0xF8);
+		regmap_write(es8326->regmap, ES8326_ANA_PDN_16, 0xFB);
+		regmap_write(es8326->regmap, ES8326_VMIDSEL_18, 0x00);
+		regmap_write(es8326->regmap, ES8326_HP_DRVIER_24, 0x0F);
+		regmap_write(es8326->regmap, ES8326_INT_SOURCE_58, 0x08);
+		regmap_write(es8326->regmap, ES8326_SDINOUT1_IO_5A, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_SDINOUT23_IO_5B, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_RESET_00,
+			     ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN);
+		regmap_write(es8326->regmap, ES8326_CLK_CTL_01, ES8326_CLK_OFF);
+		break;
+	}
+
+	return 0;
+}
+
+#define es8326_RATES SNDRV_PCM_RATE_8000_96000
+
+#define es8326_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops es8326_ops = {
+	.hw_params = es8326_pcm_hw_params,
+	.set_fmt = es8326_set_dai_fmt,
+	.set_sysclk = es8326_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver es8326_dai = {
+	.name = "ES8326 HiFi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = es8326_RATES,
+		.formats = es8326_FORMATS,
+		},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = es8326_RATES,
+		.formats = es8326_FORMATS,
+		},
+	.ops = &es8326_ops,
+	.symmetric_rate = 1,
+};
+
+static int es8326_probe(struct snd_soc_component *component)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	es8326->component = component;
+	es8326->jd_inverted = device_property_read_bool(component->dev,
+							"everest,jack-detect-inverted");
+	ret = device_property_read_u8(component->dev, "everest,amic1-src", &es8326->amic1_src);
+	if (ret != 0) {
+		dev_dbg(component->dev, "amic1-src return %d", ret);
+		es8326->amic1_src = ES8326_MIC1_SEL;
+	}
+
+	ret = device_property_read_u8(component->dev, "everest,amic2-src", &es8326->amic2_src);
+	if (ret != 0) {
+		dev_dbg(component->dev, "amic2-src return %d", ret);
+		es8326->amic2_src = ES8326_MIC1_SEL;
+	}
+
+	ret = device_property_read_u8(component->dev, "everest,mic1-src", &es8326->mic1_src);
+	if (ret != 0) {
+		dev_dbg(component->dev, "mic1-src return %d", ret);
+		es8326->mic1_src = ES8326_ADC_AMIC;
+	}
+	dev_dbg(component->dev, "mic1-src %x", es8326->mic1_src);
+
+	ret = device_property_read_u8(component->dev, "everest,mic2-src", &es8326->mic2_src);
+	if (ret != 0) {
+		dev_dbg(component->dev, "mic2-src return %d", ret);
+		es8326->mic2_src = ES8326_ADC_DMIC;
+	}
+	dev_dbg(component->dev, "mic2-src %x", es8326->mic2_src);
+
+	ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol);
+	if (ret != 0) {
+		dev_dbg(component->dev, "jack-pol return %d", ret);
+		es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP;
+	}
+	dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol);
+
+	regmap_write(es8326->regmap, ES8326_CLK_CTL_01, ES8326_CLK_ON);
+	/* Two channel ADC */
+	regmap_write(es8326->regmap, ES8326_PULLUP_CTL_F9, 0x02);
+	regmap_write(es8326->regmap, ES8326_CLK_INV_02, 0x00);
+	regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC_0C, 0x1F);
+	regmap_write(es8326->regmap, ES8326_CLK_TRI_0E, 0x00);
+	regmap_write(es8326->regmap, ES8326_CLK_VMIDS1_10, 0xC8);
+	regmap_write(es8326->regmap, ES8326_CLK_VMIDS2_11, 0x88);
+	regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME_12, 0x20);
+	regmap_write(es8326->regmap, ES8326_DAC_MUTE_14, 0x00);
+	regmap_write(es8326->regmap, ES8326_ANA_LOWPOWER_19, 0xF0);
+	regmap_write(es8326->regmap, ES8326_SYS_BIAS_1D, 0x08);
+	regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0x22);
+	regmap_write(es8326->regmap, ES8326_ADC_SCALE_29, 0x00);
+	regmap_write(es8326->regmap, ES8326_ADC1_SRC_2A, es8326->mic1_src);
+	regmap_write(es8326->regmap, ES8326_ADC2_SRC_2B, es8326->mic2_src);
+	regmap_write(es8326->regmap, ES8326_HP_CAL_4A, 0x00);
+	regmap_write(es8326->regmap, ES8326_DAC_DSM_4D, 0x08);
+	regmap_write(es8326->regmap, ES8326_DAC_RAMPRATE_4E, 0x20);
+	regmap_write(es8326->regmap, ES8326_DAC_VPPSCALE_4F, 0x15);
+	regmap_write(es8326->regmap, ES8326_HPJACK_TIMER_56, 0x88);
+	regmap_write(es8326->regmap, ES8326_HP_DET_57,
+		     ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol);
+	regmap_write(es8326->regmap, ES8326_INT_SOURCE_58, 0x08);
+	regmap_write(es8326->regmap, ES8326_INTOUT_IO_59, 0x45);
+	regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_ON);
+	snd_soc_component_update_bits(component, ES8326_PAGGAIN_23,
+				      ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL);
+
+	es8326_set_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+
+static void es8326_enable_jack_detect(struct snd_soc_component *component,
+				struct snd_soc_jack *jack)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "Enter into %s\n", __func__);
+
+	mutex_lock(&es8326->lock);
+	if (es8326->jd_inverted)
+		snd_soc_component_update_bits(component, ES8326_HP_DET_57,
+					      ES8326_HP_DET_JACK_POL, ES8326_HP_DET_JACK_POL);
+	es8326->jack = jack;
+
+	mutex_unlock(&es8326->lock);
+	/* Enable irq and sync initial jack state */
+	enable_irq(es8326->irq);
+	es8326_irq(es8326->irq, es8326);
+}
+
+static void es8326_disable_jack_detect(struct snd_soc_component *component)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "Enter into %s\n", __func__);
+	if (!es8326->jack)
+		return; /* Already disabled (or never enabled) */
+
+	disable_irq(es8326->irq);
+	cancel_delayed_work_sync(&es8326->jack_detect_work);
+
+	mutex_lock(&es8326->lock);
+	if (es8326->jack->status & SND_JACK_MICROPHONE)
+		snd_soc_jack_report(es8326->jack, 0, SND_JACK_BTN_0);
+
+	es8326->jack = NULL;
+	mutex_unlock(&es8326->lock);
+}
+
+static int es8326_set_jack(struct snd_soc_component *component,
+			struct snd_soc_jack *jack, void *data)
+{
+	if (jack)
+		es8326_enable_jack_detect(component, jack);
+	else
+		es8326_disable_jack_detect(component);
+
+	return 0;
+}
+
+static void es8326_remove(struct snd_soc_component *component)
+{
+	es8326_disable_jack_detect(component);
+	es8326_set_bias_level(component, SND_SOC_BIAS_OFF);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_es8326 = {
+	.probe = es8326_probe,
+	.remove = es8326_remove,
+	.set_bias_level = es8326_set_bias_level,
+	.set_jack = es8326_set_jack,
+
+	.dapm_widgets = es8326_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(es8326_dapm_widgets),
+	.dapm_routes = es8326_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(es8326_dapm_routes),
+	.controls = es8326_snd_controls,
+	.num_controls = ARRAY_SIZE(es8326_snd_controls),
+};
+
+static int es8326_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct es8326_priv *es8326;
+	int ret;
+
+	es8326 = devm_kzalloc(&i2c->dev, sizeof(struct es8326_priv), GFP_KERNEL);
+	if (!es8326)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, es8326);
+	es8326->i2c = i2c;
+	mutex_init(&es8326->lock);
+	es8326->regmap = devm_regmap_init_i2c(i2c, &es8326_regmap_config);
+	if (IS_ERR(es8326->regmap)) {
+		ret = PTR_ERR(es8326->regmap);
+		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
+	es8326->irq = i2c->irq;
+	/* ES8316 is level-based while ES8326 is edge-based */
+	ret = devm_request_threaded_irq(&i2c->dev, es8326->irq, NULL, es8326_irq,
+					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					"es8326", es8326);
+	if (ret == 0)
+		disable_irq(es8326->irq);
+	else
+		dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+	INIT_DELAYED_WORK(&es8326->jack_detect_work,
+			  es8326_jack_detect_handler);
+
+	es8326->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+	if (IS_ERR(es8326->mclk)) {
+		dev_err(&i2c->dev, "unable to get mclk\n");
+		return PTR_ERR(es8326->mclk);
+	}
+	if (!es8326->mclk)
+		dev_warn(&i2c->dev, "assuming static mclk\n");
+
+	ret = clk_prepare_enable(es8326->mclk);
+	if (ret) {
+		dev_err(&i2c->dev, "unable to enable mclk\n");
+		return ret;
+	}
+	return devm_snd_soc_register_component(&i2c->dev,
+					&soc_component_dev_es8326,
+					&es8326_dai, 1);
+}
+
+#ifdef CONFIG_OF
+static const struct i2c_device_id es8326_i2c_id[] = {
+	{"es8326", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, es8326_i2c_id);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id es8326_acpi_match[] = {
+	{"ESSX8326", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, es8326_acpi_match);
+#endif
+
+static const struct of_device_id es8326_of_match[] = {
+	{ .compatible = "everest, es8326", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, es8326_of_match);
+
+static struct i2c_driver es8326_i2c_driver = {
+	.driver = {
+		.name = "es8326",
+		.acpi_match_table = ACPI_PTR(es8326_acpi_match),
+		.of_match_table = of_match_ptr(es8326_of_match),
+	},
+	.probe = es8326_i2c_probe,
+};
+module_i2c_driver(es8326_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC es8326 driver");
+MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h
new file mode 100755
index 000000000000..4cc05e9cd2a8
--- /dev/null
+++ b/sound/soc/codecs/es8326.h
@@ -0,0 +1,184 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * es8326.c -- es8326 ALSA SoC audio driver
+ * Copyright Everest Semiconductor Co.,Ltd
+ *
+ * Authors: David Yang <yangxiaohua@everest-semi.com>
+ */
+
+#ifndef _ES8326_H
+#define _ES8326_H
+
+#define CONFIG_HHTECH_MINIPMP	1
+
+/* ES8326 register space */
+
+#define ES8326_RESET_00         0x00
+#define ES8326_CLK_CTL_01         0x01
+#define ES8326_CLK_INV_02        0x02
+#define ES8326_CLK_RESAMPLE_03         0x03
+#define ES8326_CLK_DIV1_04        0x04
+#define ES8326_CLK_DIV2_05       0x05
+#define ES8326_CLK_DLL_06       0x06
+#define ES8326_CLK_MUX_07      0x07
+#define ES8326_CLK_ADC_SEL_08       0x08
+#define ES8326_CLK_DAC_SEL_09      0x09
+#define ES8326_CLK_ADC_OSR_0A      0x0a
+#define ES8326_CLK_DAC_OSR_0B      0x0b
+#define ES8326_CLK_DIV_CPC_0C      0x0c
+#define ES8326_CLK_DIV_BCLK_0D      0x0d
+#define ES8326_CLK_TRI_0E      0x0e
+#define ES8326_CLK_DIV_LRCK_0F      0x0f
+#define ES8326_CLK_VMIDS1_10      0x10
+#define ES8326_CLK_VMIDS2_11      0x11
+#define ES8326_CLK_CAL_TIME_12     0x12
+#define ES8326_FMT_13     0x13
+
+#define ES8326_DAC_MUTE_14     0x14
+#define ES8326_ADC_MUTE_15     0x15
+#define ES8326_ANA_PDN_16     0x16
+#define ES8326_PGA_PDN_17      0x17
+#define ES8326_VMIDSEL_18      0x18
+#define ES8326_ANA_LOWPOWER_19      0x19
+#define ES8326_ANA_DMS_1A      0x1a
+#define ES8326_ANA_MICBIAS_1B      0x1b
+#define ES8326_ANA_VSEL_1C      0x1c
+#define ES8326_SYS_BIAS_1D      0x1d
+#define ES8326_BIAS_SW1_1E      0x1e
+#define ES8326_BIAS_SW2_1F      0x1f
+#define ES8326_BIAS_SW3_20     0x20
+#define ES8326_BIAS_SW4_21     0x21
+#define ES8326_VMIDLOW_22     0x22
+
+#define ES8326_PAGGAIN_23     0x23
+#define ES8326_HP_DRVIER_24     0x24
+#define ES8326_DAC2HPMIX_25     0x25
+#define ES8326_HP_VOL_26     0x26
+#define ES8326_HP_CAL_27     0x27
+#define ES8326_HP_DRIVER_REF_28     0x28
+#define ES8326_ADC_SCALE_29     0x29
+#define ES8326_ADC1_SRC_2A     0x2a
+#define ES8326_ADC2_SRC_2B     0x2b
+#define ES8326_ADC1_VOL_2C     0x2c
+#define ES8326_ADC2_VOL_2D     0x2d
+#define ES8326_ADC_RAMPRATE_2E     0x2e
+#define ES8326_2F     0x2f
+#define ES8326_30     0x30
+#define ES8326_31     0x31
+#define ES8326_ALC_RECOVERY_32     0x32
+#define ES8326_ALC_LEVEL_33     0x33
+#define ES8326_ADC_HPFS1_34     0x34
+#define ES8326_ADC_HPFS2_35     0x35
+#define ES8326_ADC_EQ_36		0x36
+#define ES8326_HP_CAL_4A		0x4A
+#define ES8326_HPL_OFFSET_INI_4B		0x4B
+#define ES8326_HPR_OFFSET_INI_4C		0x4C
+#define ES8326_DAC_DSM_4D		0x4D
+#define ES8326_DAC_RAMPRATE_4E		0x4E
+#define ES8326_DAC_VPPSCALE_4F		0x4F
+#define ES8326_DAC_VOL_50		0x50
+#define ES8326_DRC_RECOVERY_53		0x53
+#define ES8326_DRC_WINSIZE_54		0x54
+#define ES8326_HPJACK_TIMER_56		0x56
+#define ES8326_HP_DET_57	0x57
+#define ES8326_INT_SOURCE_58	0x58
+#define ES8326_INTOUT_IO_59	0x59
+#define ES8326_SDINOUT1_IO_5A	0x5A
+#define ES8326_SDINOUT23_IO_5B	0x5B
+#define ES8326_JACK_PULSE_5C	0x5C
+
+#define ES8326_PULLUP_CTL_F9	0xF9
+#define ES8326_HP_DECTECT_FB	0xFB
+#define ES8326_CHIP_ID1_FD	0xFD
+#define ES8326_CHIP_ID2_FE	0xFE
+#define ES8326_CHIP_VERSION_FF	0xFF
+
+/* ES8326_RESET_00 */
+#define ES8326_CSM_ON (1 << 7)
+#define ES8326_MASTER_MODE_EN	(1 << 6)
+#define	ES8326_PWRUP_SEQ_EN	(1 << 5)
+#define ES8326_CODEC_RESET (0x0f << 0)
+#define ES8326_CSM_OFF (0 << 7)
+
+/* ES8326_CLK_CTL_01 */
+#define ES8326_CLK_ON (0x7f << 0)
+#define ES8326_CLK_OFF (0 << 0)
+
+/* ES8326_CLK_INV_02 */
+#define ES8326_BCLK_AS_MCLK (1 << 3)
+
+/* ES8326_FMT_13 */
+#define ES8326_S24_LE	(0 << 2)
+#define ES8326_S20_3_LE	(1 << 2)
+#define ES8326_S18_LE	(2 << 2)
+#define ES8326_S16_LE	(3 << 2)
+#define ES8326_S32_LE	(4 << 2)
+#define ES8326_DATA_LEN_MASK	(7 << 2)
+
+#define ES8326_DAIFMT_MASK	((1 << 5) | (3 << 0))
+#define ES8326_DAIFMT_I2S	0
+#define ES8326_DAIFMT_LEFT_J	(1 << 0)
+#define ES8326_DAIFMT_DSP_A		(3 << 0)
+#define ES8326_DAIFMT_DSP_B		((1 << 5) | (3 << 0))
+
+/* ES8326_PAGGAIN_23 */
+#define ES8326_MIC_SEL_MASK (3 << 4)
+#define ES8326_MIC1_SEL	(1 << 4)
+#define ES8326_MIC2_SEL (1 << 5)
+
+/* ES8326_HP_CAL_27 */
+#define ES8326_HPOR_SHIFT 4
+
+/* ES8326_ADC1_SRC_2A */
+#define ES8326_ADC1_SHIFT 0
+#define ES8326_ADC2_SHIFT 4
+#define ES8326_ADC_SRC_ANA 0
+#define ES8326_ADC_SRC_ANA_INV_SW0 1
+#define ES8326_ADC_SRC_ANA_INV_SW1 2
+#define ES8326_ADC_SRC_DMIC_MCLK 3
+#define ES8326_ADC_SRC_DMIC_SDIN2 4
+#define ES8326_ADC_SRC_DMIC_SDIN2_INV 5
+#define ES8326_ADC_SRC_DMIC_SDIN3 6
+#define ES8326_ADC_SRC_DMIC_SDIN3_INV 7
+
+#define ES8326_ADC_AMIC	((ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC2_SHIFT) \
+		| (ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC1_SHIFT))
+#define ES8326_ADC_DMIC	((ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC2_SHIFT) \
+		| (ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC1_SHIFT))
+/* ES8326_ADC2_SRC_2B */
+#define ES8326_ADC3_SHIFT 0
+#define ES8326_ADC4_SHIFT 3
+
+/* ES8326_HP_DET_57 */
+#define ES8326_HP_DET_SRC_PIN27 (1 << 5)
+#define ES8326_HP_DET_SRC_PIN9 (1 << 4)
+#define ES8326_HP_DET_JACK_POL (1 << 3)
+#define ES8326_HP_DET_BUTTON_POL (1 << 2)
+#define ES8326_HP_TYPE_OMTP	(3 << 0)
+#define ES8326_HP_TYPE_CTIA	(2 << 0)
+#define ES8326_HP_TYPE_AUTO	(1 << 0)
+#define ES8326_HP_TYPE_AUTO_INV	(0 << 0)
+
+/* ES8326_SDINOUT1_IO_5A */
+#define ES8326_IO_INPUT	(0 << 0)
+#define ES8326_IO_SDIN_SLOT0 (1 << 0)
+#define ES8326_IO_SDIN_SLOT1 (2 << 0)
+#define ES8326_IO_SDIN_SLOT2 (3 << 0)
+#define ES8326_IO_SDIN_SLOT7 (8 << 0)
+#define ES8326_IO_DMIC_CLK (9 << 0)
+#define ES8326_IO_DMIC_CLK_INV (0x0a << 0)
+#define ES8326_IO_SDOUT2 (0x0b << 0)
+#define ES8326_IO_LOW (0x0e << 0)
+#define ES8326_IO_HIGH (0x0f << 0)
+#define ES8326_ADC2DAC (1 << 3)
+#define ES8326_SDINOUT1_SHIFT 4
+
+/* ES8326_SDINOUT23_IO_5B */
+#define ES8326_SDINOUT2_SHIFT 4
+#define ES8326_SDINOUT3_SHIFT 0
+
+/* ES8326_HP_DECTECT_FB */
+#define ES8326_HPINSERT_FLAG (1 << 1)
+#define ES8326_HPBUTTON_FLAG (1 << 0)
+
+#endif
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] ASoC: codecs: add support for ES8326
  2022-04-05 13:12 Zhu Ning
@ 2022-04-05 14:02 ` Mark Brown
  0 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2022-04-05 14:02 UTC (permalink / raw)
  To: Zhu Ning; +Cc: Zhu Ning, alsa-devel, pierre-louis.bossart, yangxiaohua, tiwai

[-- Attachment #1: Type: text/plain, Size: 3350 bytes --]

On Tue, Apr 05, 2022 at 09:12:20PM +0800, Zhu Ning wrote:

> The ES8326 codec is not compatible with ES8316 and requires a dedicated driver.

This looks mostly good - a few things below but nothing huge that should
require big restructurings or anything.

> +++ b/sound/soc/codecs/es8326.c
> @@ -0,0 +1,753 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * es8326.c -- es8326 ALSA SoC audio driver
> + * Copyright Everest Semiconductor Co., Ltd

Please make the entire comment a C++ one so things look more
intentional.

> +#include <linux/clk.h>
> +#include <linux/gpio.h>

The driver doesn't actually seem to use the GPIO APIs?

> +	/* The lock protects the situation that an irq is generated
> +	 * while the previous irq is still being processed.
> +	 */
> +	struct mutex lock;

It doesn't seem to, it seems to protect registrations and
deregistrations from racing against each other?  The actual interrupt
handling doesn't use it.

> +	SOC_SINGLE_TLV("ADC Analog PGA Gain", ES8326_PAGGAIN_23, 0, 10, 0, adc_analog_pga_tlv),

Control name should end in Volume - see control-names.rst.

> +	regmap_write(es8326->regmap, ES8326_CLK_CTL_01, ES8326_CLK_ON);
> +	/* Two channel ADC */
> +	regmap_write(es8326->regmap, ES8326_PULLUP_CTL_F9, 0x02);
> +	regmap_write(es8326->regmap, ES8326_CLK_INV_02, 0x00);
> +	regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC_0C, 0x1F);
> +	regmap_write(es8326->regmap, ES8326_CLK_TRI_0E, 0x00);
> +	regmap_write(es8326->regmap, ES8326_CLK_VMIDS1_10, 0xC8);
> +	regmap_write(es8326->regmap, ES8326_CLK_VMIDS2_11, 0x88);
> +	regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME_12, 0x20);
> +	regmap_write(es8326->regmap, ES8326_DAC_MUTE_14, 0x00);
> +	regmap_write(es8326->regmap, ES8326_ANA_LOWPOWER_19, 0xF0);
> +	regmap_write(es8326->regmap, ES8326_SYS_BIAS_1D, 0x08);
> +	regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0x22);
> +	regmap_write(es8326->regmap, ES8326_ADC_SCALE_29, 0x00);
> +	regmap_write(es8326->regmap, ES8326_ADC1_SRC_2A, es8326->mic1_src);
> +	regmap_write(es8326->regmap, ES8326_ADC2_SRC_2B, es8326->mic2_src);
> +	regmap_write(es8326->regmap, ES8326_HP_CAL_4A, 0x00);
> +	regmap_write(es8326->regmap, ES8326_DAC_DSM_4D, 0x08);
> +	regmap_write(es8326->regmap, ES8326_DAC_RAMPRATE_4E, 0x20);
> +	regmap_write(es8326->regmap, ES8326_DAC_VPPSCALE_4F, 0x15);
> +	regmap_write(es8326->regmap, ES8326_HPJACK_TIMER_56, 0x88);
> +	regmap_write(es8326->regmap, ES8326_HP_DET_57,
> +		     ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol);
> +	regmap_write(es8326->regmap, ES8326_INT_SOURCE_58, 0x08);
> +	regmap_write(es8326->regmap, ES8326_INTOUT_IO_59, 0x45);
> +	regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_ON);
> +	snd_soc_component_update_bits(component, ES8326_PAGGAIN_23,
> +				      ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL);

This looks like some or all of it is doing routing which would normally
be configured from userspace using controls - the ADC1/2 sources and
DAC controls jump out for example.  Some of it like the pullups might
make sense fixed, or as DT properties like the jack detect polarity is
here, but not all of it.

> +#ifdef CONFIG_OF
> +static const struct i2c_device_id es8326_i2c_id[] = {
> +	{"es8326", 0 },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(i2c, es8326_i2c_id);
> +#endif

This should be unconditional, the ifdefs should be around
es8326_of_match instead.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH] ASoC: codecs: add support for ES8326
@ 2022-07-07  1:18 Zhu Ning
  2022-07-07  9:38 ` kernel test robot
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Zhu Ning @ 2022-07-07  1:18 UTC (permalink / raw)
  To: alsa-devel
  Cc: Zhu Ning, pierre-louis.bossart, tiwai, broonie, Zhu Ning,
	David Yang

The ES8326 codec is not compatible with ES8316 and requires a dedicated driver.

Signed-off-by: David Yang <yangxiaohua@everest-semi.com>
Signed-off-by: Zhu Ning <zhuning@everest-semi.com>
---
 sound/soc/codecs/Kconfig  |   5 +
 sound/soc/codecs/Makefile |   2 +
 sound/soc/codecs/es8326.c | 776 ++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/es8326.h | 187 +++++++++
 4 files changed, 970 insertions(+)
 mode change 100644 => 100755 sound/soc/codecs/Kconfig
 mode change 100644 => 100755 sound/soc/codecs/Makefile
 create mode 100755 sound/soc/codecs/es8326.c
 create mode 100755 sound/soc/codecs/es8326.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
old mode 100644
new mode 100755
index 6165db92a629..b0a15cce416d
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -98,6 +98,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_DA9055
 	imply SND_SOC_DMIC
 	imply SND_SOC_ES8316
+	imply SND_SOC_ES8326
 	imply SND_SOC_ES8328_SPI
 	imply SND_SOC_ES8328_I2C
 	imply SND_SOC_ES7134
@@ -911,6 +912,10 @@ config SND_SOC_ES8316
 	tristate "Everest Semi ES8316 CODEC"
 	depends on I2C
 
+config SND_SOC_ES8326
+	tristate "Everest Semi ES8326 CODEC"
+	depends on I2C
+
 config SND_SOC_ES8328
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
old mode 100644
new mode 100755
index 28dc4edfd01f..ae9d789b5381
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -100,6 +100,7 @@ snd-soc-dmic-objs := dmic.o
 snd-soc-es7134-objs := es7134.o
 snd-soc-es7241-objs := es7241.o
 snd-soc-es8316-objs := es8316.o
+snd-soc-es8326-objs := es8326.o
 snd-soc-es8328-objs := es8328.o
 snd-soc-es8328-i2c-objs := es8328-i2c.o
 snd-soc-es8328-spi-objs := es8328-spi.o
@@ -452,6 +453,7 @@ obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_ES7134)	+= snd-soc-es7134.o
 obj-$(CONFIG_SND_SOC_ES7241)	+= snd-soc-es7241.o
 obj-$(CONFIG_SND_SOC_ES8316)    += snd-soc-es8316.o
+obj-$(CONFIG_SND_SOC_ES8326)    += snd-soc-es8326.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
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
new file mode 100755
index 000000000000..2d1f17fb72f9
--- /dev/null
+++ b/sound/soc/codecs/es8326.c
@@ -0,0 +1,776 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// es8326.c -- es8326 ALSA SoC audio driver
+// Copyright Everest Semiconductor Co., Ltd
+//
+// Authors: David Yang <yangxiaohua@everest-semi.com>
+//
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "es8326.h"
+
+struct es8326_priv {
+	struct clk *mclk;
+	struct snd_pcm_hw_constraint_list *sysclk_constraints;
+	struct i2c_client *i2c;
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct delayed_work jack_detect_work;
+	struct snd_soc_jack *jack;
+	int irq;
+	/* The lock protects the situation that an irq is generated
+	 * while enabling or disabling irq.
+	 */
+	struct mutex lock;
+	u8 mic1_src;
+	u8 mic2_src;
+	u8 jack_pol;
+	bool jd_inverted;
+	unsigned int sysclk;
+};
+
+static void es8326_jack_detect_handler(struct work_struct *work)
+{
+	struct es8326_priv *es8326 =
+		container_of(work, struct es8326_priv, jack_detect_work.work);
+	struct snd_soc_component *comp = es8326->component;
+	unsigned int iface;
+
+	iface = snd_soc_component_read(comp, ES8326_HP_DECTECT_FB);
+	dev_dbg(comp->dev, "gpio flag %#04x", iface);
+	if ((iface & ES8326_HPINSERT_FLAG) == 0) {
+		dev_dbg(comp->dev, "No headset detected");
+		snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
+		snd_soc_component_write(comp, ES8326_ADC1_SRC_2A, es8326->mic2_src);
+		snd_soc_component_write(comp, ES8326_ANA_MICBIAS_1B, 0x70);
+	} else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) {
+		if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) {
+			dev_dbg(comp->dev, "Headset detected");
+			snd_soc_jack_report(es8326->jack, SND_JACK_HEADSET, SND_JACK_HEADSET);
+			snd_soc_component_write(comp, ES8326_ADC1_SRC_2A, es8326->mic1_src);
+		} else {
+			dev_dbg(comp->dev, "Headphone detected");
+			snd_soc_jack_report(es8326->jack, SND_JACK_HEADPHONE, SND_JACK_HEADSET);
+		}
+	}
+}
+
+static irqreturn_t es8326_irq(int irq, void *dev_id)
+{
+	struct es8326_priv *es8326 = dev_id;
+	struct snd_soc_component *comp = es8326->component;
+
+	snd_soc_component_write(comp, ES8326_ANA_MICBIAS_1B, 0x7c);
+
+	queue_delayed_work(system_wq, &es8326->jack_detect_work,
+			   msecs_to_jiffies(300));
+
+	return IRQ_HANDLED;
+}
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9550, 50, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_analog_pga_tlv, 0, 300, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_pga_tlv, 0, 600, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(softramp_rate, 0, 100, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(drc_target_tlv, -3200, 200, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(drc_recovery_tlv, -125, 250, 0);
+
+static const char *const winsize[] = {
+	"0.25db/2  LRCK",
+	"0.25db/4  LRCK",
+	"0.25db/8  LRCK",
+	"0.25db/16  LRCK",
+	"0.25db/32  LRCK",
+	"0.25db/64  LRCK",
+	"0.25db/128  LRCK",
+	"0.25db/256  LRCK",
+	"0.25db/512  LRCK",
+	"0.25db/1024  LRCK",
+	"0.25db/2048  LRCK",
+	"0.25db/4096  LRCK",
+	"0.25db/8192  LRCK",
+	"0.25db/16384  LRCK",
+	"0.25db/32768  LRCK",
+	"0.25db/65536  LRCK",
+};
+
+static const char *const dacpol_txt[] =	{
+	"Normal", "R Invert", "L Invert", "L + R Invert" };
+static const struct soc_enum dacpol =
+	SOC_ENUM_SINGLE(ES8326_DAC_DSM_4D, 4, 4, dacpol_txt);
+static const struct soc_enum alc_winsize =
+	SOC_ENUM_SINGLE(ES8326_ADC_RAMPRATE_2E, 4, 16, winsize);
+static const struct soc_enum drc_winsize =
+	SOC_ENUM_SINGLE(ES8326_DRC_WINSIZE_54, 4, 16, winsize);
+static const struct snd_kcontrol_new es8326_snd_controls[] = {
+	SOC_SINGLE_TLV("DAC Playback Volume", ES8326_DAC_VOL_50, 0, 0xbf, 0, dac_vol_tlv),
+	SOC_ENUM("Playback Polarity", dacpol),
+	SOC_SINGLE_TLV("DAC Ramp Rate", ES8326_DAC_RAMPRATE_4E, 0, 0x0f, 0, softramp_rate),
+	SOC_SINGLE_TLV("DRC Recovery Level", ES8326_DRC_RECOVERY_53, 0, 4, 0, drc_recovery_tlv),
+	SOC_ENUM("DRC Winsize", drc_winsize),
+	SOC_SINGLE_TLV("DRC Target Level", ES8326_DRC_WINSIZE_54, 0, 0x0f, 0, drc_target_tlv),
+
+	SOC_DOUBLE_R_TLV("ADC Capture Volume", ES8326_ADC1_VOL_2C, ES8326_ADC2_VOL_2D, 0, 0xff, 0,
+			 adc_vol_tlv),
+	SOC_DOUBLE_TLV("ADC PGA Volume", ES8326_ADC_SCALE_29, 4, 0, 5, 0, adc_pga_tlv),
+	SOC_SINGLE_TLV("ADC PGA Gain Volume", ES8326_PAGGAIN_23, 0, 10, 0, adc_analog_pga_tlv),
+	SOC_SINGLE_TLV("ADC Ramp Rate", ES8326_ADC_RAMPRATE_2E, 0, 0x0f, 0, softramp_rate),
+	SOC_SINGLE("ALC Capture Switch", ES8326_ALC_RECOVERY_32, 3, 1, 0),
+	SOC_SINGLE_TLV("ALC Capture Recovery Level", ES8326_ALC_LEVEL_33, 0, 4, 0, drc_recovery_tlv),
+	SOC_ENUM("ALC Capture Winsize", alc_winsize),
+	SOC_SINGLE_TLV("ALC Capture Target Level", ES8326_ALC_LEVEL_33, 0, 0x0f, 0, drc_target_tlv),
+
+};
+
+static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("MIC3"),
+	SND_SOC_DAPM_INPUT("MIC4"),
+
+	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* ADC Digital Mute */
+	SND_SOC_DAPM_PGA("ADC L1", ES8326_ADC_MUTE_15, 0, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC R1", ES8326_ADC_MUTE_15, 1, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC L2", ES8326_ADC_MUTE_15, 2, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC R2", ES8326_ADC_MUTE_15, 3, 1, NULL, 0),
+
+	/* Analog Power Supply*/
+	SND_SOC_DAPM_DAC("Right DAC", NULL, ES8326_ANA_PDN_16, 0, 1),
+	SND_SOC_DAPM_DAC("Left DAC", NULL, ES8326_ANA_PDN_16, 1, 1),
+	SND_SOC_DAPM_SUPPLY("Analog Power", ES8326_ANA_PDN_16, 7, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("IBias Power", ES8326_ANA_PDN_16, 6, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Vref", ES8326_ANA_PDN_16, 5, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Vref", ES8326_ANA_PDN_16, 4, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Vref Power", ES8326_ANA_PDN_16, 3, 1, NULL, 0),
+
+	SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX_25, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX_25, 3, 0, NULL, 0),
+
+	/* Headphone Charge Pump and Output */
+	SND_SOC_DAPM_SUPPLY("HPOR Cal", ES8326_HP_CAL_27, 7, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HPOL Cal", ES8326_HP_CAL_27, 3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8326_HP_DRVIER_24,
+			    3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Driver Bias", ES8326_HP_DRVIER_24,
+			    2, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone LDO", ES8326_HP_DRVIER_24,
+			    1, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Reference", ES8326_HP_DRVIER_24,
+			    0, 1, NULL, 0),	
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL_27,
+			 ES8326_HPOR_SHIFT, 7, 7, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL_27,
+			 0, 7, 7, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_route es8326_dapm_routes[] = {
+	{"ADC L1", NULL, "MIC1"},
+	{"ADC R1", NULL, "MIC2"},
+	{"ADC L2", NULL, "MIC3"},
+	{"ADC R2", NULL, "MIC4"},
+
+
+	{"ADC L", NULL, "ADC L1"},
+	{"ADC R", NULL, "ADC R1"},
+	{"ADC L", NULL, "ADC L2"},
+	{"ADC R", NULL, "ADC R2"},
+
+	{"I2S OUT", NULL, "ADC L"},
+	{"I2S OUT", NULL, "ADC R"},
+
+	{"I2S OUT", NULL, "Analog Power"},
+	{"I2S OUT", NULL, "ADC Vref"},
+	{"I2S OUT", NULL, "Vref Power"},
+	{"I2S OUT", NULL, "IBias Power"},
+	{"I2S IN", NULL, "Analog Power"},
+	{"I2S IN", NULL, "DAC Vref"},
+	{"I2S IN", NULL, "Vref Power"},
+	{"I2S IN", NULL, "IBias Power"},
+
+	{"Right DAC", NULL, "I2S IN"},
+	{"Left DAC", NULL, "I2S IN"},
+	
+	{"LHPMIX", NULL, "Left DAC"},
+	{"RHPMIX", NULL, "Right DAC"},
+
+	{"HPOR", NULL, "HPOR Cal"},
+	{"HPOL", NULL, "HPOL Cal"},
+	{"HPOR", NULL, "HPOR Supply"},
+	{"HPOL", NULL, "HPOL Supply"},
+	{"HPOL", NULL, "Headphone Charge Pump"},
+	{"HPOR", NULL, "Headphone Charge Pump"},
+	{"HPOL", NULL, "Headphone Driver Bias"},
+	{"HPOR", NULL, "Headphone Driver Bias"},
+	{"HPOL", NULL, "Headphone LDO"},
+	{"HPOR", NULL, "Headphone LDO"},
+	{"HPOL", NULL, "Headphone Reference"},
+	{"HPOR", NULL, "Headphone Reference"},
+
+	{"HPOL", NULL, "LHPMIX"},
+	{"HPOR", NULL, "RHPMIX"},
+};
+
+static const struct regmap_range es8326_volatile_ranges[] = {
+	regmap_reg_range(ES8326_HP_DECTECT_FB, ES8326_HP_DECTECT_FB),
+};
+
+static const struct regmap_access_table es8326_volatile_table = {
+	.yes_ranges = es8326_volatile_ranges,
+	.n_yes_ranges = ARRAY_SIZE(es8326_volatile_ranges),
+};
+
+const struct regmap_config es8326_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = 0xff,
+	.volatile_table = &es8326_volatile_table,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+struct _coeff_div {
+	u16 fs;
+	u32 rate;
+	u32 mclk;
+	u8 reg4;
+	u8 reg5;
+	u8 reg6;
+	u8 reg7;
+	u8 reg8;
+	u8 reg9;
+	u8 rega;
+	u8 regb;
+};
+
+/* codec hifi mclk clock divider coefficients */
+/* {ratio, LRCK, MCLK, REG04, REG05, REG06, REG07, REG08, REG09, REG10, REG11} */
+static const struct _coeff_div coeff_div[] = {
+	{32, 8000, 256000, 0x60, 0x00, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{32, 16000, 512000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{32, 44100, 1411200, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{32, 48000, 1536000, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{36, 8000, 288000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+	{36, 16000, 576000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+	{48, 8000, 384000, 0x60, 0x02, 0x1F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{48, 16000, 768000, 0x20, 0x02, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{48, 48000, 2304000, 0x00, 0x02, 0x0D, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{64, 8000, 512000, 0x60, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{64, 16000, 1024000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{64, 44100, 2822400, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{64, 48000, 3072000, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{72, 8000, 576000, 0x20, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{72, 16000, 1152000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+	{96, 8000, 768000, 0x60, 0x02, 0x1D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{96, 16000, 1536000, 0x20, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{100, 48000, 4800000, 0x04, 0x04, 0x3F, 0x6D, 0x38, 0x08, 0x4f, 0x1f},
+	{125, 48000, 6000000, 0x04, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{128, 8000, 1024000, 0x60, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{128, 16000, 2048000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{128, 44100, 5644800, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{128, 48000, 6144000, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{144, 8000, 1152000, 0x20, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{144, 16000, 2304000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{192, 8000, 1536000, 0x60, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{192, 16000, 3072000, 0x20, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{200, 48000, 9600000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{250, 48000, 12000000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{256, 8000, 2048000, 0x60, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{256, 16000, 4096000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{256, 44100, 11289600, 0x00, 0x00, 0x10, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{256, 48000, 12288000, 0x00, 0x00, 0x30, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{288, 8000, 2304000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{384, 8000, 3072000, 0x60, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{384, 16000, 6144000, 0x20, 0x02, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{384, 48000, 18432000, 0x00, 0x02, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{400, 48000, 19200000, 0x09, 0x04, 0x0f, 0x6d, 0x3a, 0x0A, 0x4F, 0x1F},
+	{500, 48000, 24000000, 0x18, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{512, 8000, 4096000, 0x60, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{512, 16000, 8192000, 0x20, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{512, 44100, 22579200, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{512, 48000, 24576000, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{768, 8000, 6144000, 0x60, 0x02, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{768, 16000, 12288000, 0x20, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{800, 48000, 38400000, 0x00, 0x18, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{1024, 8000, 8192000, 0x60, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{1024, 16000, 16384000, 0x20, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{1152, 16000, 18432000, 0x20, 0x08, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{1536, 8000, 12288000, 0x60, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+
+	{1536, 16000, 24576000, 0x20, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{1625, 8000, 13000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{1625, 16000, 26000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{2048, 8000, 16384000, 0x60, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{2304, 8000, 18432000, 0x40, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x5F},
+	{3072, 8000, 24576000, 0x60, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{3250, 8000, 26000000, 0x0C, 0x18, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static unsigned int es8326_rates[] = {
+	8000, 12000, 16000, 24000, 32000, 48000, 96000
+};
+
+static struct snd_pcm_hw_constraint_list es8326_constraints = {
+	.count = ARRAY_SIZE(es8326_rates),
+	.list = es8326_rates,
+};
+
+/*
+ * Note that this should be called from init rather than from hw_params.
+ */
+static int es8326_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *codec = codec_dai->component;
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec);
+
+	es8326->sysclk = freq;
+
+	if (freq == 0) {
+		es8326->sysclk_constraints->list = NULL;
+		es8326->sysclk_constraints->count = 0;
+		return 0;
+	}
+
+	es8326->sysclk_constraints = &es8326_constraints;
+	return 0;
+}
+
+static int es8326_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u8 iface = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+	case SND_SOC_DAIFMT_CBP_CFP:
+		snd_soc_component_update_bits(component, ES8326_RESET_00,
+					      ES8326_MASTER_MODE_EN, ES8326_MASTER_MODE_EN);
+		break;
+	case SND_SOC_DAIFMT_CBC_CFC:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		dev_err(component->dev, "Codec driver does not support right justified\n");
+		return -EINVAL;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= ES8326_DAIFMT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= ES8326_DAIFMT_DSP_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= ES8326_DAIFMT_DSP_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, ES8326_FMT_13, ES8326_DAIFMT_MASK, iface);
+
+	return 0;
+}
+
+static int es8326_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *codec = dai->component;
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec);
+	u8 srate = 0;
+	int coeff;
+
+	coeff = get_coeff(es8326->sysclk, params_rate(params));
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		srate |= ES8326_S16_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		srate |= ES8326_S20_3_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S18_3LE:
+		srate |= ES8326_S18_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		srate |= ES8326_S24_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		srate |= ES8326_S32_LE;
+		break;
+	default:
+		break;
+	}
+
+	/* set iface & srate */
+	snd_soc_component_update_bits(codec, ES8326_FMT_13, ES8326_DATA_LEN_MASK, srate);
+
+	if (coeff >= 0) {
+		regmap_write(es8326->regmap,  ES8326_CLK_DIV1_04,
+			     coeff_div[coeff].reg4);
+		regmap_write(es8326->regmap,  ES8326_CLK_DIV2_05,
+			     coeff_div[coeff].reg5);
+		regmap_write(es8326->regmap,  ES8326_CLK_DLL_06,
+			     coeff_div[coeff].reg6);
+		regmap_write(es8326->regmap,  ES8326_CLK_MUX_07,
+			     coeff_div[coeff].reg7);
+		regmap_write(es8326->regmap,  ES8326_CLK_ADC_SEL_08,
+			     coeff_div[coeff].reg8);
+		regmap_write(es8326->regmap,  ES8326_CLK_DAC_SEL_09,
+			     coeff_div[coeff].reg9);
+		regmap_write(es8326->regmap,  ES8326_CLK_ADC_OSR_0A,
+			     coeff_div[coeff].rega);
+		regmap_write(es8326->regmap,  ES8326_CLK_DAC_OSR_0B,
+			     coeff_div[coeff].regb);
+	}
+
+	return 0;
+}
+
+static int es8326_set_bias_level(struct snd_soc_component *codec,
+				 enum snd_soc_bias_level level)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:		
+		if (!IS_ERR(es8326->mclk)) {
+			if (snd_soc_component_get_bias_level(codec) == SND_SOC_BIAS_ON) {
+				clk_disable_unprepare(es8326->mclk);
+			} else {
+				ret = clk_prepare_enable(es8326->mclk);
+				if (ret)
+					return ret;
+			}
+		}
+		regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_PWRUP_SEQ_EN);
+		regmap_write(es8326->regmap, ES8326_INTOUT_IO_59, 0x45);
+		regmap_write(es8326->regmap, ES8326_SDINOUT1_IO_5A,
+			    (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT));
+		regmap_write(es8326->regmap, ES8326_SDINOUT23_IO_5B, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE_03, 0x05);
+		regmap_write(es8326->regmap, ES8326_VMIDSEL_18, 0x02);
+		regmap_write(es8326->regmap, ES8326_PGA_PDN_17, 0x40);
+		regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0xAA);
+		regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_ON);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		break;
+	case SND_SOC_BIAS_OFF:
+		if (es8326->mclk)
+			clk_disable_unprepare(es8326->mclk);
+		regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0x11);
+		regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_OFF);
+		regmap_write(es8326->regmap, ES8326_PGA_PDN_17, 0xF8);
+		regmap_write(es8326->regmap, ES8326_VMIDSEL_18, 0x00);
+		regmap_write(es8326->regmap, ES8326_INT_SOURCE_58, 0x08);
+		regmap_write(es8326->regmap, ES8326_SDINOUT1_IO_5A, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_SDINOUT23_IO_5B, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_RESET_00,
+			     ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN);
+		break;
+	}
+
+	return 0;
+}
+
+#define es8326_RATES SNDRV_PCM_RATE_8000_96000
+
+#define es8326_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops es8326_ops = {
+	.hw_params = es8326_pcm_hw_params,
+	.set_fmt = es8326_set_dai_fmt,
+	.set_sysclk = es8326_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver es8326_dai = {
+	.name = "ES8326 HiFi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = es8326_RATES,
+		.formats = es8326_FORMATS,
+		},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = es8326_RATES,
+		.formats = es8326_FORMATS,
+		},
+	.ops = &es8326_ops,
+	.symmetric_rate = 1,
+};
+static int es8326_resume(struct snd_soc_component *component)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	regmap_write(es8326->regmap, ES8326_CLK_CTL_01, ES8326_CLK_ON);
+	/* Two channel ADC */
+	regmap_write(es8326->regmap, ES8326_PULLUP_CTL_F9, 0x02);
+	regmap_write(es8326->regmap, ES8326_CLK_INV_02, 0x00);
+	regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC_0C, 0x1F);
+	regmap_write(es8326->regmap, ES8326_CLK_VMIDS1_10, 0xC8);
+	regmap_write(es8326->regmap, ES8326_CLK_VMIDS2_11, 0x88);
+	regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME_12, 0x20);
+	regmap_write(es8326->regmap, ES8326_SYS_BIAS_1D, 0x08);
+	regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0x22);
+	regmap_write(es8326->regmap, ES8326_ADC1_SRC_2A, es8326->mic1_src);
+	regmap_write(es8326->regmap, ES8326_ADC2_SRC_2B, es8326->mic2_src);
+	regmap_write(es8326->regmap, ES8326_HPJACK_TIMER_56, 0x88);
+	regmap_write(es8326->regmap, ES8326_HP_DET_57,
+		     ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol);
+	regmap_write(es8326->regmap, ES8326_INT_SOURCE_58, 0x08);
+	regmap_write(es8326->regmap, ES8326_INTOUT_IO_59, 0x45);
+	regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_ON);
+	snd_soc_component_update_bits(component, ES8326_PAGGAIN_23,
+				      ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL);
+
+	es8326_irq(es8326->irq, es8326);
+	return 0;
+}
+static int es8326_probe(struct snd_soc_component *component)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+	int ret;
+	u8 reg;
+
+	es8326->component = component;
+	es8326->jd_inverted = device_property_read_bool(component->dev,
+							"everest,jack-detect-inverted");
+
+	ret = device_property_read_u8(component->dev, "everest,mic1-src", &es8326->mic1_src);
+	if (ret != 0) {
+		dev_dbg(component->dev, "mic1-src return %d", ret);
+		es8326->mic1_src = ES8326_ADC_AMIC;
+	}
+	dev_dbg(component->dev, "mic1-src %x", es8326->mic1_src);
+
+	ret = device_property_read_u8(component->dev, "everest,mic2-src", &es8326->mic2_src);
+	if (ret != 0) {
+		dev_dbg(component->dev, "mic2-src return %d", ret);
+		es8326->mic2_src = ES8326_ADC_DMIC;
+	}
+	dev_dbg(component->dev, "mic2-src %x", es8326->mic2_src);
+
+	ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol);
+	if (ret != 0) {
+		dev_dbg(component->dev, "jack-pol return %d", ret);
+		es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP;
+	}
+	dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol);
+
+	es8326_resume(component);
+	reg = snd_soc_component_read(component, ES8326_CHIP_VERSION_FF);
+	if((reg && ES8326_VERSION_B) == 1)
+	{
+		regmap_write(es8326->regmap, ES8326_ANA_VSEL_1C, 0x7F);
+		regmap_write(es8326->regmap, ES8326_VMIDLOW_22, 0x0F);
+		regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0xAA);
+		regmap_write(es8326->regmap, ES8326_HP_DRVIER_24, 0x20);
+	}
+	return 0;
+}
+
+static void es8326_enable_jack_detect(struct snd_soc_component *component,
+				struct snd_soc_jack *jack)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "Enter into %s\n", __func__);
+
+	mutex_lock(&es8326->lock);
+	if (es8326->jd_inverted)
+		snd_soc_component_update_bits(component, ES8326_HP_DET_57,
+					      ES8326_HP_DET_JACK_POL, ~es8326->jack_pol);
+	es8326->jack = jack;
+
+	mutex_unlock(&es8326->lock);
+	/* Enable irq and sync initial jack state */
+	enable_irq(es8326->irq);
+	es8326_irq(es8326->irq, es8326);
+}
+
+static void es8326_disable_jack_detect(struct snd_soc_component *component)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "Enter into %s\n", __func__);
+	if (!es8326->jack)
+		return; /* Already disabled (or never enabled) */
+
+	disable_irq(es8326->irq);
+	cancel_delayed_work_sync(&es8326->jack_detect_work);
+
+	mutex_lock(&es8326->lock);
+	if (es8326->jack->status & SND_JACK_MICROPHONE)
+		snd_soc_jack_report(es8326->jack, 0, SND_JACK_BTN_0);
+
+	es8326->jack = NULL;
+	mutex_unlock(&es8326->lock);
+}
+
+static int es8326_set_jack(struct snd_soc_component *component,
+			struct snd_soc_jack *jack, void *data)
+{
+	if (jack)
+		es8326_enable_jack_detect(component, jack);
+	else
+		es8326_disable_jack_detect(component);
+
+	return 0;
+}
+
+static void es8326_remove(struct snd_soc_component *component)
+{
+	es8326_disable_jack_detect(component);
+	es8326_set_bias_level(component, SND_SOC_BIAS_OFF);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_es8326 = {
+	.probe = es8326_probe,
+	.remove = es8326_remove,
+	.resume = es8326_resume,
+	.set_bias_level = es8326_set_bias_level,
+	.set_jack = es8326_set_jack,
+
+	.dapm_widgets = es8326_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(es8326_dapm_widgets),
+	.dapm_routes = es8326_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(es8326_dapm_routes),
+	.controls = es8326_snd_controls,
+	.num_controls = ARRAY_SIZE(es8326_snd_controls),
+};
+
+static int es8326_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct es8326_priv *es8326;
+	int ret;
+
+	es8326 = devm_kzalloc(&i2c->dev, sizeof(struct es8326_priv), GFP_KERNEL);
+	if (!es8326)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, es8326);
+	es8326->i2c = i2c;
+	mutex_init(&es8326->lock);
+	es8326->regmap = devm_regmap_init_i2c(i2c, &es8326_regmap_config);
+	if (IS_ERR(es8326->regmap)) {
+		ret = PTR_ERR(es8326->regmap);
+		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
+	es8326->irq = i2c->irq;
+	/* ES8316 is level-based while ES8326 is edge-based */
+	ret = devm_request_threaded_irq(&i2c->dev, es8326->irq, NULL, es8326_irq,
+					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					"es8326", es8326);
+	if (ret == 0)
+		disable_irq(es8326->irq);
+	else
+		dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+	INIT_DELAYED_WORK(&es8326->jack_detect_work,
+			  es8326_jack_detect_handler);
+
+	es8326->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+	if (IS_ERR(es8326->mclk)) {
+		dev_err(&i2c->dev, "unable to get mclk\n");
+		return PTR_ERR(es8326->mclk);
+	}
+	if (!es8326->mclk)
+		dev_warn(&i2c->dev, "assuming static mclk\n");
+
+	ret = clk_prepare_enable(es8326->mclk);
+	if (ret) {
+		dev_err(&i2c->dev, "unable to enable mclk\n");
+		return ret;
+	}
+	return devm_snd_soc_register_component(&i2c->dev,
+					&soc_component_dev_es8326,
+					&es8326_dai, 1);
+}
+
+static const struct i2c_device_id es8326_i2c_id[] = {
+	{"es8326", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, es8326_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id es8326_of_match[] = {
+	{ .compatible = "everest, es8326", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, es8326_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id es8326_acpi_match[] = {
+	{"ESSX8326", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, es8326_acpi_match);
+#endif
+
+static struct i2c_driver es8326_i2c_driver = {
+	.driver = {
+		.name = "es8326",
+		.acpi_match_table = ACPI_PTR(es8326_acpi_match),
+		.of_match_table = of_match_ptr(es8326_of_match),
+	},
+	.probe = es8326_i2c_probe,
+};
+module_i2c_driver(es8326_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC es8326 driver");
+MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h
new file mode 100755
index 000000000000..23a099add4d8
--- /dev/null
+++ b/sound/soc/codecs/es8326.h
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * es8326.c -- es8326 ALSA SoC audio driver
+ * Copyright Everest Semiconductor Co.,Ltd
+ *
+ * Authors: David Yang <yangxiaohua@everest-semi.com>
+ */
+
+#ifndef _ES8326_H
+#define _ES8326_H
+
+#define CONFIG_HHTECH_MINIPMP	1
+
+/* ES8326 register space */
+
+#define ES8326_RESET_00         0x00
+#define ES8326_CLK_CTL_01         0x01
+#define ES8326_CLK_INV_02        0x02
+#define ES8326_CLK_RESAMPLE_03         0x03
+#define ES8326_CLK_DIV1_04        0x04
+#define ES8326_CLK_DIV2_05       0x05
+#define ES8326_CLK_DLL_06       0x06
+#define ES8326_CLK_MUX_07      0x07
+#define ES8326_CLK_ADC_SEL_08       0x08
+#define ES8326_CLK_DAC_SEL_09      0x09
+#define ES8326_CLK_ADC_OSR_0A      0x0a
+#define ES8326_CLK_DAC_OSR_0B      0x0b
+#define ES8326_CLK_DIV_CPC_0C      0x0c
+#define ES8326_CLK_DIV_BCLK_0D      0x0d
+#define ES8326_CLK_TRI_0E      0x0e
+#define ES8326_CLK_DIV_LRCK_0F      0x0f
+#define ES8326_CLK_VMIDS1_10      0x10
+#define ES8326_CLK_VMIDS2_11      0x11
+#define ES8326_CLK_CAL_TIME_12     0x12
+#define ES8326_FMT_13     0x13
+
+#define ES8326_DAC_MUTE_14     0x14
+#define ES8326_ADC_MUTE_15     0x15
+#define ES8326_ANA_PDN_16     0x16
+#define ES8326_PGA_PDN_17      0x17
+#define ES8326_VMIDSEL_18      0x18
+#define ES8326_ANA_LOWPOWER_19      0x19
+#define ES8326_ANA_DMS_1A      0x1a
+#define ES8326_ANA_MICBIAS_1B      0x1b
+#define ES8326_ANA_VSEL_1C      0x1c
+#define ES8326_SYS_BIAS_1D      0x1d
+#define ES8326_BIAS_SW1_1E      0x1e
+#define ES8326_BIAS_SW2_1F      0x1f
+#define ES8326_BIAS_SW3_20     0x20
+#define ES8326_BIAS_SW4_21     0x21
+#define ES8326_VMIDLOW_22     0x22
+
+#define ES8326_PAGGAIN_23     0x23
+#define ES8326_HP_DRVIER_24     0x24
+#define ES8326_DAC2HPMIX_25     0x25
+#define ES8326_HP_VOL_26     0x26
+#define ES8326_HP_CAL_27     0x27
+#define ES8326_HP_DRIVER_REF_28     0x28
+#define ES8326_ADC_SCALE_29     0x29
+#define ES8326_ADC1_SRC_2A     0x2a
+#define ES8326_ADC2_SRC_2B     0x2b
+#define ES8326_ADC1_VOL_2C     0x2c
+#define ES8326_ADC2_VOL_2D     0x2d
+#define ES8326_ADC_RAMPRATE_2E     0x2e
+#define ES8326_2F     0x2f
+#define ES8326_30     0x30
+#define ES8326_31     0x31
+#define ES8326_ALC_RECOVERY_32     0x32
+#define ES8326_ALC_LEVEL_33     0x33
+#define ES8326_ADC_HPFS1_34     0x34
+#define ES8326_ADC_HPFS2_35     0x35
+#define ES8326_ADC_EQ_36		0x36
+#define ES8326_HP_CAL_4A		0x4A
+#define ES8326_HPL_OFFSET_INI_4B		0x4B
+#define ES8326_HPR_OFFSET_INI_4C		0x4C
+#define ES8326_DAC_DSM_4D		0x4D
+#define ES8326_DAC_RAMPRATE_4E		0x4E
+#define ES8326_DAC_VPPSCALE_4F		0x4F
+#define ES8326_DAC_VOL_50		0x50
+#define ES8326_DRC_RECOVERY_53		0x53
+#define ES8326_DRC_WINSIZE_54		0x54
+#define ES8326_HPJACK_TIMER_56		0x56
+#define ES8326_HP_DET_57	0x57
+#define ES8326_INT_SOURCE_58	0x58
+#define ES8326_INTOUT_IO_59	0x59
+#define ES8326_SDINOUT1_IO_5A	0x5A
+#define ES8326_SDINOUT23_IO_5B	0x5B
+#define ES8326_JACK_PULSE_5C	0x5C
+
+#define ES8326_PULLUP_CTL_F9	0xF9
+#define ES8326_HP_DECTECT_FB	0xFB
+#define ES8326_CHIP_ID1_FD	0xFD
+#define ES8326_CHIP_ID2_FE	0xFE
+#define ES8326_CHIP_VERSION_FF	0xFF
+
+/* ES8326_RESET_00 */
+#define ES8326_CSM_ON (1 << 7)
+#define ES8326_MASTER_MODE_EN	(1 << 6)
+#define	ES8326_PWRUP_SEQ_EN	(1 << 5)
+#define ES8326_CODEC_RESET (0x0f << 0)
+#define ES8326_CSM_OFF (0 << 7)
+
+/* ES8326_CLK_CTL_01 */
+#define ES8326_CLK_ON (0x7f << 0)
+#define ES8326_CLK_OFF (0 << 0)
+
+/* ES8326_CLK_INV_02 */
+#define ES8326_BCLK_AS_MCLK (1 << 3)
+
+/* ES8326_FMT_13 */
+#define ES8326_S24_LE	(0 << 2)
+#define ES8326_S20_3_LE	(1 << 2)
+#define ES8326_S18_LE	(2 << 2)
+#define ES8326_S16_LE	(3 << 2)
+#define ES8326_S32_LE	(4 << 2)
+#define ES8326_DATA_LEN_MASK	(7 << 2)
+
+#define ES8326_DAIFMT_MASK	((1 << 5) | (3 << 0))
+#define ES8326_DAIFMT_I2S	0
+#define ES8326_DAIFMT_LEFT_J	(1 << 0)
+#define ES8326_DAIFMT_DSP_A		(3 << 0)
+#define ES8326_DAIFMT_DSP_B		((1 << 5) | (3 << 0))
+
+/* ES8326_PAGGAIN_23 */
+#define ES8326_MIC_SEL_MASK (3 << 4)
+#define ES8326_MIC1_SEL	(1 << 4)
+#define ES8326_MIC2_SEL (1 << 5)
+
+/* ES8326_HP_CAL_27 */
+#define ES8326_HPOR_SHIFT 4
+
+/* ES8326_ADC1_SRC_2A */
+#define ES8326_ADC1_SHIFT 0
+#define ES8326_ADC2_SHIFT 4
+#define ES8326_ADC_SRC_ANA 0
+#define ES8326_ADC_SRC_ANA_INV_SW0 1
+#define ES8326_ADC_SRC_ANA_INV_SW1 2
+#define ES8326_ADC_SRC_DMIC_MCLK 3
+#define ES8326_ADC_SRC_DMIC_SDIN2 4
+#define ES8326_ADC_SRC_DMIC_SDIN2_INV 5
+#define ES8326_ADC_SRC_DMIC_SDIN3 6
+#define ES8326_ADC_SRC_DMIC_SDIN3_INV 7
+
+#define ES8326_ADC_AMIC	((ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC2_SHIFT) \
+		| (ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC1_SHIFT))
+#define ES8326_ADC_DMIC	((ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC2_SHIFT) \
+		| (ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC1_SHIFT))
+/* ES8326_ADC2_SRC_2B */
+#define ES8326_ADC3_SHIFT 0
+#define ES8326_ADC4_SHIFT 3
+
+/* ES8326_HP_DET_57 */
+#define ES8326_HP_DET_SRC_PIN27 (1 << 5)
+#define ES8326_HP_DET_SRC_PIN9 (1 << 4)
+#define ES8326_HP_DET_JACK_POL (1 << 3)
+#define ES8326_HP_DET_BUTTON_POL (1 << 2)
+#define ES8326_HP_TYPE_OMTP	(3 << 0)
+#define ES8326_HP_TYPE_CTIA	(2 << 0)
+#define ES8326_HP_TYPE_AUTO	(1 << 0)
+#define ES8326_HP_TYPE_AUTO_INV	(0 << 0)
+
+/* ES8326_SDINOUT1_IO_5A */
+#define ES8326_IO_INPUT	(0 << 0)
+#define ES8326_IO_SDIN_SLOT0 (1 << 0)
+#define ES8326_IO_SDIN_SLOT1 (2 << 0)
+#define ES8326_IO_SDIN_SLOT2 (3 << 0)
+#define ES8326_IO_SDIN_SLOT7 (8 << 0)
+#define ES8326_IO_DMIC_CLK (9 << 0)
+#define ES8326_IO_DMIC_CLK_INV (0x0a << 0)
+#define ES8326_IO_SDOUT2 (0x0b << 0)
+#define ES8326_IO_LOW (0x0e << 0)
+#define ES8326_IO_HIGH (0x0f << 0)
+#define ES8326_ADC2DAC (1 << 3)
+#define ES8326_SDINOUT1_SHIFT 4
+
+/* ES8326_SDINOUT23_IO_5B */
+#define ES8326_SDINOUT2_SHIFT 4
+#define ES8326_SDINOUT3_SHIFT 0
+
+/* ES8326_HP_DECTECT_FB */
+#define ES8326_HPINSERT_FLAG (1 << 1)
+#define ES8326_HPBUTTON_FLAG (1 << 0)
+
+/* ES8326_CHIP_VERSION_FF 0xFF */
+#define ES8326_VERSION_B (1 << 0)
+
+#endif
\ No newline at end of file
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] ASoC: codecs: add support for ES8326
  2022-07-07  1:18 [PATCH] ASoC: codecs: add support for ES8326 Zhu Ning
@ 2022-07-07  9:38 ` kernel test robot
  2022-07-07 12:35 ` kernel test robot
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 11+ messages in thread
From: kernel test robot @ 2022-07-07  9:38 UTC (permalink / raw)
  To: Zhu Ning, alsa-devel
  Cc: kbuild-all, Zhu Ning, tiwai, pierre-louis.bossart, broonie,
	David Yang

Hi Zhu,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on broonie-sound/for-next]
[also build test WARNING on tiwai-sound/for-next linus/master v5.19-rc5 next-20220706]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Zhu-Ning/ASoC-codecs-add-support-for-ES8326/20220707-115006
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: i386-allyesconfig (https://download.01.org/0day-ci/archive/20220707/202207071739.NIPiY4NM-lkp@intel.com/config)
compiler: gcc-11 (Debian 11.3.0-3) 11.3.0
reproduce (this is a W=1 build):
        # https://github.com/intel-lab-lkp/linux/commit/fda793f4ec55b33955344b93a8c290fe207d54d4
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Zhu-Ning/ASoC-codecs-add-support-for-ES8326/20220707-115006
        git checkout fda793f4ec55b33955344b93a8c290fe207d54d4
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        make W=1 O=build_dir ARCH=i386 SHELL=/bin/bash sound/soc/codecs/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> sound/soc/codecs/es8326.c:742:35: warning: 'es8326_i2c_id' defined but not used [-Wunused-const-variable=]
     742 | static const struct i2c_device_id es8326_i2c_id[] = {
         |                                   ^~~~~~~~~~~~~


vim +/es8326_i2c_id +742 sound/soc/codecs/es8326.c

   741	
 > 742	static const struct i2c_device_id es8326_i2c_id[] = {
   743		{"es8326", 0 },
   744		{}
   745	};
   746	MODULE_DEVICE_TABLE(i2c, es8326_i2c_id);
   747	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] ASoC: codecs: add support for ES8326
  2022-07-07  1:18 [PATCH] ASoC: codecs: add support for ES8326 Zhu Ning
  2022-07-07  9:38 ` kernel test robot
@ 2022-07-07 12:35 ` kernel test robot
  2022-07-07 21:39 ` kernel test robot
  2022-07-08 17:40 ` Mark Brown
  3 siblings, 0 replies; 11+ messages in thread
From: kernel test robot @ 2022-07-07 12:35 UTC (permalink / raw)
  To: Zhu Ning, alsa-devel
  Cc: kbuild-all, Zhu Ning, llvm, tiwai, pierre-louis.bossart, broonie,
	David Yang

Hi Zhu,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on broonie-sound/for-next]
[also build test WARNING on tiwai-sound/for-next linus/master v5.19-rc5 next-20220707]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Zhu-Ning/ASoC-codecs-add-support-for-ES8326/20220707-115006
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: arm-randconfig-r014-20220707 (https://download.01.org/0day-ci/archive/20220707/202207072002.QTXsBBqR-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 66ae1d60bb278793fd651cece264699d522bab84)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm cross compiling tool for clang build
        # apt-get install binutils-arm-linux-gnueabi
        # https://github.com/intel-lab-lkp/linux/commit/fda793f4ec55b33955344b93a8c290fe207d54d4
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Zhu-Ning/ASoC-codecs-add-support-for-ES8326/20220707-115006
        git checkout fda793f4ec55b33955344b93a8c290fe207d54d4
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash drivers/clk/qcom/ sound/soc/codecs/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> sound/soc/codecs/es8326.c:612:13: warning: converting the result of '<<' to a boolean always evaluates to true [-Wtautological-constant-compare]
           if((reg && ES8326_VERSION_B) == 1)
                      ^
   sound/soc/codecs/es8326.h:185:29: note: expanded from macro 'ES8326_VERSION_B'
   #define ES8326_VERSION_B (1 << 0)
                               ^
   1 warning generated.


vim +612 sound/soc/codecs/es8326.c

   531	
   532	static struct snd_soc_dai_driver es8326_dai = {
   533		.name = "ES8326 HiFi",
   534		.playback = {
   535			.stream_name = "Playback",
   536			.channels_min = 1,
   537			.channels_max = 2,
   538			.rates = es8326_RATES,
   539			.formats = es8326_FORMATS,
   540			},
   541		.capture = {
   542			.stream_name = "Capture",
   543			.channels_min = 1,
   544			.channels_max = 2,
   545			.rates = es8326_RATES,
   546			.formats = es8326_FORMATS,
   547			},
   548		.ops = &es8326_ops,
   549		.symmetric_rate = 1,
   550	};
   551	static int es8326_resume(struct snd_soc_component *component)
   552	{
   553		struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
   554	
   555		regmap_write(es8326->regmap, ES8326_CLK_CTL_01, ES8326_CLK_ON);
   556		/* Two channel ADC */
   557		regmap_write(es8326->regmap, ES8326_PULLUP_CTL_F9, 0x02);
   558		regmap_write(es8326->regmap, ES8326_CLK_INV_02, 0x00);
   559		regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC_0C, 0x1F);
   560		regmap_write(es8326->regmap, ES8326_CLK_VMIDS1_10, 0xC8);
   561		regmap_write(es8326->regmap, ES8326_CLK_VMIDS2_11, 0x88);
   562		regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME_12, 0x20);
   563		regmap_write(es8326->regmap, ES8326_SYS_BIAS_1D, 0x08);
   564		regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0x22);
   565		regmap_write(es8326->regmap, ES8326_ADC1_SRC_2A, es8326->mic1_src);
   566		regmap_write(es8326->regmap, ES8326_ADC2_SRC_2B, es8326->mic2_src);
   567		regmap_write(es8326->regmap, ES8326_HPJACK_TIMER_56, 0x88);
   568		regmap_write(es8326->regmap, ES8326_HP_DET_57,
   569			     ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol);
   570		regmap_write(es8326->regmap, ES8326_INT_SOURCE_58, 0x08);
   571		regmap_write(es8326->regmap, ES8326_INTOUT_IO_59, 0x45);
   572		regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_ON);
   573		snd_soc_component_update_bits(component, ES8326_PAGGAIN_23,
   574					      ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL);
   575	
   576		es8326_irq(es8326->irq, es8326);
   577		return 0;
   578	}
   579	static int es8326_probe(struct snd_soc_component *component)
   580	{
   581		struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
   582		int ret;
   583		u8 reg;
   584	
   585		es8326->component = component;
   586		es8326->jd_inverted = device_property_read_bool(component->dev,
   587								"everest,jack-detect-inverted");
   588	
   589		ret = device_property_read_u8(component->dev, "everest,mic1-src", &es8326->mic1_src);
   590		if (ret != 0) {
   591			dev_dbg(component->dev, "mic1-src return %d", ret);
   592			es8326->mic1_src = ES8326_ADC_AMIC;
   593		}
   594		dev_dbg(component->dev, "mic1-src %x", es8326->mic1_src);
   595	
   596		ret = device_property_read_u8(component->dev, "everest,mic2-src", &es8326->mic2_src);
   597		if (ret != 0) {
   598			dev_dbg(component->dev, "mic2-src return %d", ret);
   599			es8326->mic2_src = ES8326_ADC_DMIC;
   600		}
   601		dev_dbg(component->dev, "mic2-src %x", es8326->mic2_src);
   602	
   603		ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol);
   604		if (ret != 0) {
   605			dev_dbg(component->dev, "jack-pol return %d", ret);
   606			es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP;
   607		}
   608		dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol);
   609	
   610		es8326_resume(component);
   611		reg = snd_soc_component_read(component, ES8326_CHIP_VERSION_FF);
 > 612		if((reg && ES8326_VERSION_B) == 1)
   613		{
   614			regmap_write(es8326->regmap, ES8326_ANA_VSEL_1C, 0x7F);
   615			regmap_write(es8326->regmap, ES8326_VMIDLOW_22, 0x0F);
   616			regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0xAA);
   617			regmap_write(es8326->regmap, ES8326_HP_DRVIER_24, 0x20);
   618		}
   619		return 0;
   620	}
   621	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] ASoC: codecs: add support for ES8326
  2022-07-07  1:18 [PATCH] ASoC: codecs: add support for ES8326 Zhu Ning
  2022-07-07  9:38 ` kernel test robot
  2022-07-07 12:35 ` kernel test robot
@ 2022-07-07 21:39 ` kernel test robot
  2022-07-08 17:40 ` Mark Brown
  3 siblings, 0 replies; 11+ messages in thread
From: kernel test robot @ 2022-07-07 21:39 UTC (permalink / raw)
  To: Zhu Ning, alsa-devel
  Cc: kbuild-all, Zhu Ning, llvm, tiwai, pierre-louis.bossart, broonie,
	David Yang

Hi Zhu,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on broonie-sound/for-next]
[also build test WARNING on tiwai-sound/for-next linus/master v5.19-rc5 next-20220707]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Zhu-Ning/ASoC-codecs-add-support-for-ES8326/20220707-115006
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: arm64-buildonly-randconfig-r006-20220707 (https://download.01.org/0day-ci/archive/20220708/202207080557.twGXw3yY-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 66ae1d60bb278793fd651cece264699d522bab84)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm64 cross compiling tool for clang build
        # apt-get install binutils-aarch64-linux-gnu
        # https://github.com/intel-lab-lkp/linux/commit/fda793f4ec55b33955344b93a8c290fe207d54d4
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Zhu-Ning/ASoC-codecs-add-support-for-ES8326/20220707-115006
        git checkout fda793f4ec55b33955344b93a8c290fe207d54d4
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash sound/soc/codecs/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   sound/soc/codecs/es8326.c:612:13: warning: converting the result of '<<' to a boolean always evaluates to true [-Wtautological-constant-compare]
           if((reg && ES8326_VERSION_B) == 1)
                      ^
   sound/soc/codecs/es8326.h:185:29: note: expanded from macro 'ES8326_VERSION_B'
   #define ES8326_VERSION_B (1 << 0)
                               ^
>> sound/soc/codecs/es8326.c:742:35: warning: unused variable 'es8326_i2c_id' [-Wunused-const-variable]
   static const struct i2c_device_id es8326_i2c_id[] = {
                                     ^
   2 warnings generated.


vim +/es8326_i2c_id +742 sound/soc/codecs/es8326.c

   741	
 > 742	static const struct i2c_device_id es8326_i2c_id[] = {
   743		{"es8326", 0 },
   744		{}
   745	};
   746	MODULE_DEVICE_TABLE(i2c, es8326_i2c_id);
   747	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] ASoC: codecs: add support for ES8326
  2022-07-07  1:18 [PATCH] ASoC: codecs: add support for ES8326 Zhu Ning
                   ` (2 preceding siblings ...)
  2022-07-07 21:39 ` kernel test robot
@ 2022-07-08 17:40 ` Mark Brown
  3 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2022-07-08 17:40 UTC (permalink / raw)
  To: Zhu Ning; +Cc: Zhu Ning, alsa-devel, pierre-louis.bossart, David Yang, tiwai

[-- Attachment #1: Type: text/plain, Size: 2724 bytes --]

On Thu, Jul 07, 2022 at 09:18:56AM +0800, Zhu Ning wrote:

> The ES8326 codec is not compatible with ES8316 and requires a dedicated driver.

There's a bunch of bot reported issues as well as those below.  Other
than the interrupt management this should all be fairly small, the bulk
of the driver looks good:

> +	SOC_ENUM_SINGLE(ES8326_DAC_DSM_4D, 4, 4, dacpol_txt);
> +static const struct soc_enum alc_winsize =
> +	SOC_ENUM_SINGLE(ES8326_ADC_RAMPRATE_2E, 4, 16, winsize);
> +static const struct soc_enum drc_winsize =
> +	SOC_ENUM_SINGLE(ES8326_DRC_WINSIZE_54, 4, 16, winsize);
> +static const struct snd_kcontrol_new es8326_snd_controls[] = {

We needs osme blank lines between declarations here to improve
legibility.

> +/*
> + * Note that this should be called from init rather than from hw_params.
> + */
> +static int es8326_set_dai_sysclk(struct snd_soc_dai *codec_dai,
> +				 int clk_id, unsigned int freq, int dir)

I don't see any reason why it *couldn't* be called from hw_params -
it'll mean the constraints don't take effect but that might be desirable
if it's called from hw_params due to being able to reprogram the input
clock.

> +}
> +static int es8326_probe(struct snd_soc_component *component)

More missing blank lines.

> +	ret = device_property_read_u8(component->dev, "everest,mic1-src", &es8326->mic1_src);
> +	if (ret != 0) {
> +		dev_dbg(component->dev, "mic1-src return %d", ret);
> +		es8326->mic1_src = ES8326_ADC_AMIC;
> +	}
> +	dev_dbg(component->dev, "mic1-src %x", es8326->mic1_src);
> +
> +	ret = device_property_read_u8(component->dev, "everest,mic2-src", &es8326->mic2_src);

This is adding a DT binding, the binding needs to be documented.

> +	if((reg && ES8326_VERSION_B) == 1)

Coding style and I'm not sure the logic there is what's intended?

> +	{
> +		regmap_write(es8326->regmap, ES8326_ANA_VSEL_1C, 0x7F);
> +		regmap_write(es8326->regmap, ES8326_VMIDLOW_22, 0x0F);
> +		regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0xAA);
> +		regmap_write(es8326->regmap, ES8326_HP_DRVIER_24, 0x20);
> +	}

Should there be something similar in the resume path?  I'm also not
seeing anything that manages the register cache over suspend.

> +	/* Enable irq and sync initial jack state */
> +	enable_irq(es8326->irq);
> +	es8326_irq(es8326->irq, es8326);

The driver souldn't need to enable or disable the IRQ by hand, it should
just configure the device to not generate interrupts when not in use.
Enabling and disabling doesn't play nicely with shared interrupts and is
in general typically a warning sign.

> +#ifdef CONFIG_OF
> +static const struct of_device_id es8326_of_match[] = {
> +	{ .compatible = "everest, es8326", },

There shouldn't be a space in the compatible string.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH] ASoC: codecs: add support for ES8326
@ 2022-07-15  5:25 Zhu Ning
  0 siblings, 0 replies; 11+ messages in thread
From: Zhu Ning @ 2022-07-15  5:25 UTC (permalink / raw)
  To: alsa-devel
  Cc: devicetree, Zhu Ning, pierre-louis.bossart, tiwai, broonie,
	Zhu Ning, David Yang

The ES8326 codec is not compatible with ES8316 and requires a dedicated driver.

Signed-off-by: David Yang <yangxiaohua@everest-semi.com>
Signed-off-by: Zhu Ning <zhuning@everest-semi.com>
---
 sound/soc/codecs/Kconfig  |   5 +
 sound/soc/codecs/Makefile |   2 +
 sound/soc/codecs/es8326.c | 794 ++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/es8326.h | 187 +++++++++
 4 files changed, 988 insertions(+)
 mode change 100644 => 100755 sound/soc/codecs/Kconfig
 mode change 100644 => 100755 sound/soc/codecs/Makefile
 create mode 100755 sound/soc/codecs/es8326.c
 create mode 100755 sound/soc/codecs/es8326.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
old mode 100644
new mode 100755
index 6165db92a629..b0a15cce416d
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -98,6 +98,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_DA9055
 	imply SND_SOC_DMIC
 	imply SND_SOC_ES8316
+	imply SND_SOC_ES8326
 	imply SND_SOC_ES8328_SPI
 	imply SND_SOC_ES8328_I2C
 	imply SND_SOC_ES7134
@@ -911,6 +912,10 @@ config SND_SOC_ES8316
 	tristate "Everest Semi ES8316 CODEC"
 	depends on I2C
 
+config SND_SOC_ES8326
+	tristate "Everest Semi ES8326 CODEC"
+	depends on I2C
+
 config SND_SOC_ES8328
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
old mode 100644
new mode 100755
index 28dc4edfd01f..ae9d789b5381
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -100,6 +100,7 @@ snd-soc-dmic-objs := dmic.o
 snd-soc-es7134-objs := es7134.o
 snd-soc-es7241-objs := es7241.o
 snd-soc-es8316-objs := es8316.o
+snd-soc-es8326-objs := es8326.o
 snd-soc-es8328-objs := es8328.o
 snd-soc-es8328-i2c-objs := es8328-i2c.o
 snd-soc-es8328-spi-objs := es8328-spi.o
@@ -452,6 +453,7 @@ obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_ES7134)	+= snd-soc-es7134.o
 obj-$(CONFIG_SND_SOC_ES7241)	+= snd-soc-es7241.o
 obj-$(CONFIG_SND_SOC_ES8316)    += snd-soc-es8316.o
+obj-$(CONFIG_SND_SOC_ES8326)    += snd-soc-es8326.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
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
new file mode 100755
index 000000000000..d62c596ac878
--- /dev/null
+++ b/sound/soc/codecs/es8326.c
@@ -0,0 +1,794 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// es8326.c -- es8326 ALSA SoC audio driver
+// Copyright Everest Semiconductor Co., Ltd
+//
+// Authors: David Yang <yangxiaohua@everest-semi.com>
+//
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "es8326.h"
+
+struct es8326_priv {
+	struct clk *mclk;
+	struct snd_pcm_hw_constraint_list *sysclk_constraints;
+	struct i2c_client *i2c;
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct delayed_work jack_detect_work;
+	struct snd_soc_jack *jack;
+	int irq;
+	/* The lock protects the situation that an irq is generated
+	 * while enabling or disabling irq.
+	 */
+	struct mutex lock;
+	u8 mic1_src;
+	u8 mic2_src;
+	u8 jack_pol;
+	bool jd_inverted;
+	unsigned int sysclk;
+};
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9550, 50, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_analog_pga_tlv, 0, 300, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_pga_tlv, 0, 600, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(softramp_rate, 0, 100, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(drc_target_tlv, -3200, 200, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(drc_recovery_tlv, -125, 250, 0);
+
+static const char *const winsize[] = {
+	"0.25db/2  LRCK",
+	"0.25db/4  LRCK",
+	"0.25db/8  LRCK",
+	"0.25db/16  LRCK",
+	"0.25db/32  LRCK",
+	"0.25db/64  LRCK",
+	"0.25db/128  LRCK",
+	"0.25db/256  LRCK",
+	"0.25db/512  LRCK",
+	"0.25db/1024  LRCK",
+	"0.25db/2048  LRCK",
+	"0.25db/4096  LRCK",
+	"0.25db/8192  LRCK",
+	"0.25db/16384  LRCK",
+	"0.25db/32768  LRCK",
+	"0.25db/65536  LRCK",
+};
+
+static const char *const dacpol_txt[] =	{
+	"Normal", "R Invert", "L Invert", "L + R Invert" };
+
+static const struct soc_enum dacpol =
+	SOC_ENUM_SINGLE(ES8326_DAC_DSM_4D, 4, 4, dacpol_txt);
+static const struct soc_enum alc_winsize =
+	SOC_ENUM_SINGLE(ES8326_ADC_RAMPRATE_2E, 4, 16, winsize);
+static const struct soc_enum drc_winsize =
+	SOC_ENUM_SINGLE(ES8326_DRC_WINSIZE_54, 4, 16, winsize);
+
+static const struct snd_kcontrol_new es8326_snd_controls[] = {
+	SOC_SINGLE_TLV("DAC Playback Volume", ES8326_DAC_VOL_50, 0, 0xbf, 0, dac_vol_tlv),
+	SOC_ENUM("Playback Polarity", dacpol),
+	SOC_SINGLE_TLV("DAC Ramp Rate", ES8326_DAC_RAMPRATE_4E, 0, 0x0f, 0, softramp_rate),
+	SOC_SINGLE_TLV("DRC Recovery Level", ES8326_DRC_RECOVERY_53, 0, 4, 0, drc_recovery_tlv),
+	SOC_ENUM("DRC Winsize", drc_winsize),
+	SOC_SINGLE_TLV("DRC Target Level", ES8326_DRC_WINSIZE_54, 0, 0x0f, 0, drc_target_tlv),
+
+	SOC_DOUBLE_R_TLV("ADC Capture Volume", ES8326_ADC1_VOL_2C, ES8326_ADC2_VOL_2D, 0, 0xff, 0,
+			 adc_vol_tlv),
+	SOC_DOUBLE_TLV("ADC PGA Volume", ES8326_ADC_SCALE_29, 4, 0, 5, 0, adc_pga_tlv),
+	SOC_SINGLE_TLV("ADC PGA Gain Volume", ES8326_PGAGAIN_23, 0, 10, 0, adc_analog_pga_tlv),
+	SOC_SINGLE_TLV("ADC Ramp Rate", ES8326_ADC_RAMPRATE_2E, 0, 0x0f, 0, softramp_rate),
+	SOC_SINGLE("ALC Capture Switch", ES8326_ALC_RECOVERY_32, 3, 1, 0),
+	SOC_SINGLE_TLV("ALC Capture Recovery Level", ES8326_ALC_LEVEL_33,
+			0, 4, 0, drc_recovery_tlv),
+	SOC_ENUM("ALC Capture Winsize", alc_winsize),
+	SOC_SINGLE_TLV("ALC Capture Target Level", ES8326_ALC_LEVEL_33,
+			0, 0x0f, 0, drc_target_tlv),
+
+};
+
+static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("MIC3"),
+	SND_SOC_DAPM_INPUT("MIC4"),
+
+	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* ADC Digital Mute */
+	SND_SOC_DAPM_PGA("ADC L1", ES8326_ADC_MUTE_15, 0, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC R1", ES8326_ADC_MUTE_15, 1, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC L2", ES8326_ADC_MUTE_15, 2, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC R2", ES8326_ADC_MUTE_15, 3, 1, NULL, 0),
+
+	/* Analog Power Supply*/
+	SND_SOC_DAPM_DAC("Right DAC", NULL, ES8326_ANA_PDN_16, 0, 1),
+	SND_SOC_DAPM_DAC("Left DAC", NULL, ES8326_ANA_PDN_16, 1, 1),
+	SND_SOC_DAPM_SUPPLY("Analog Power", ES8326_ANA_PDN_16, 7, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("IBias Power", ES8326_ANA_PDN_16, 6, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Vref", ES8326_ANA_PDN_16, 5, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Vref", ES8326_ANA_PDN_16, 4, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Vref Power", ES8326_ANA_PDN_16, 3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", ES8326_ANA_MICBIAS_1B, 2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", ES8326_ANA_MICBIAS_1B, 3, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX_25, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX_25, 3, 0, NULL, 0),
+
+	/* Headphone Charge Pump and Output */
+	SND_SOC_DAPM_SUPPLY("HPOR Cal", ES8326_HP_CAL_27, 7, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HPOL Cal", ES8326_HP_CAL_27, 3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8326_HP_DRIVER_24,
+			    3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Driver Bias", ES8326_HP_DRIVER_24,
+			    2, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone LDO", ES8326_HP_DRIVER_24,
+			    1, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Reference", ES8326_HP_DRIVER_24,
+			    0, 1, NULL, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL_27,
+			 ES8326_HPOR_SHIFT, 7, 7, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL_27,
+			 0, 7, 7, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_route es8326_dapm_routes[] = {
+	{"ADC L1", NULL, "MIC1"},
+	{"ADC R1", NULL, "MIC2"},
+	{"ADC L2", NULL, "MIC3"},
+	{"ADC R2", NULL, "MIC4"},
+
+
+	{"ADC L", NULL, "ADC L1"},
+	{"ADC R", NULL, "ADC R1"},
+	{"ADC L", NULL, "ADC L2"},
+	{"ADC R", NULL, "ADC R2"},
+
+	{"I2S OUT", NULL, "ADC L"},
+	{"I2S OUT", NULL, "ADC R"},
+
+	{"I2S OUT", NULL, "Analog Power"},
+	{"I2S OUT", NULL, "ADC Vref"},
+	{"I2S OUT", NULL, "Vref Power"},
+	{"I2S OUT", NULL, "IBias Power"},
+	{"I2S IN", NULL, "Analog Power"},
+	{"I2S IN", NULL, "DAC Vref"},
+	{"I2S IN", NULL, "Vref Power"},
+	{"I2S IN", NULL, "IBias Power"},
+
+	{"Right DAC", NULL, "I2S IN"},
+	{"Left DAC", NULL, "I2S IN"},
+
+	{"LHPMIX", NULL, "Left DAC"},
+	{"RHPMIX", NULL, "Right DAC"},
+
+	{"HPOR", NULL, "HPOR Cal"},
+	{"HPOL", NULL, "HPOL Cal"},
+	{"HPOR", NULL, "HPOR Supply"},
+	{"HPOL", NULL, "HPOL Supply"},
+	{"HPOL", NULL, "Headphone Charge Pump"},
+	{"HPOR", NULL, "Headphone Charge Pump"},
+	{"HPOL", NULL, "Headphone Driver Bias"},
+	{"HPOR", NULL, "Headphone Driver Bias"},
+	{"HPOL", NULL, "Headphone LDO"},
+	{"HPOR", NULL, "Headphone LDO"},
+	{"HPOL", NULL, "Headphone Reference"},
+	{"HPOR", NULL, "Headphone Reference"},
+
+	{"HPOL", NULL, "LHPMIX"},
+	{"HPOR", NULL, "RHPMIX"},
+};
+
+static const struct regmap_range es8326_volatile_ranges[] = {
+	regmap_reg_range(ES8326_HP_DETECT_FB, ES8326_HP_DETECT_FB),
+};
+
+static const struct regmap_access_table es8326_volatile_table = {
+	.yes_ranges = es8326_volatile_ranges,
+	.n_yes_ranges = ARRAY_SIZE(es8326_volatile_ranges),
+};
+
+const struct regmap_config es8326_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = 0xff,
+	.volatile_table = &es8326_volatile_table,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+struct _coeff_div {
+	u16 fs;
+	u32 rate;
+	u32 mclk;
+	u8 reg4;
+	u8 reg5;
+	u8 reg6;
+	u8 reg7;
+	u8 reg8;
+	u8 reg9;
+	u8 rega;
+	u8 regb;
+};
+
+/* codec hifi mclk clock divider coefficients */
+/* {ratio, LRCK, MCLK, REG04, REG05, REG06, REG07, REG08, REG09, REG10, REG11} */
+static const struct _coeff_div coeff_div[] = {
+	{32, 8000, 256000, 0x60, 0x00, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{32, 16000, 512000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{32, 44100, 1411200, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{32, 48000, 1536000, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{36, 8000, 288000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+	{36, 16000, 576000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+	{48, 8000, 384000, 0x60, 0x02, 0x1F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{48, 16000, 768000, 0x20, 0x02, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{48, 48000, 2304000, 0x00, 0x02, 0x0D, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{64, 8000, 512000, 0x60, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{64, 16000, 1024000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{64, 44100, 2822400, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{64, 48000, 3072000, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{72, 8000, 576000, 0x20, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{72, 16000, 1152000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+	{96, 8000, 768000, 0x60, 0x02, 0x1D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{96, 16000, 1536000, 0x20, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{100, 48000, 4800000, 0x04, 0x04, 0x3F, 0x6D, 0x38, 0x08, 0x4f, 0x1f},
+	{125, 48000, 6000000, 0x04, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{128, 8000, 1024000, 0x60, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{128, 16000, 2048000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{128, 44100, 5644800, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{128, 48000, 6144000, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{144, 8000, 1152000, 0x20, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{144, 16000, 2304000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{192, 8000, 1536000, 0x60, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{192, 16000, 3072000, 0x20, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{200, 48000, 9600000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{250, 48000, 12000000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{256, 8000, 2048000, 0x60, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{256, 16000, 4096000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{256, 44100, 11289600, 0x00, 0x00, 0x10, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{256, 48000, 12288000, 0x00, 0x00, 0x30, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{288, 8000, 2304000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{384, 8000, 3072000, 0x60, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{384, 16000, 6144000, 0x20, 0x02, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{384, 48000, 18432000, 0x00, 0x02, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{400, 48000, 19200000, 0x09, 0x04, 0x0f, 0x6d, 0x3a, 0x0A, 0x4F, 0x1F},
+	{500, 48000, 24000000, 0x18, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{512, 8000, 4096000, 0x60, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{512, 16000, 8192000, 0x20, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{512, 44100, 22579200, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{512, 48000, 24576000, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{768, 8000, 6144000, 0x60, 0x02, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{768, 16000, 12288000, 0x20, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{800, 48000, 38400000, 0x00, 0x18, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{1024, 8000, 8192000, 0x60, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{1024, 16000, 16384000, 0x20, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{1152, 16000, 18432000, 0x20, 0x08, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{1536, 8000, 12288000, 0x60, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+
+	{1536, 16000, 24576000, 0x20, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{1625, 8000, 13000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{1625, 16000, 26000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{2048, 8000, 16384000, 0x60, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{2304, 8000, 18432000, 0x40, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x5F},
+	{3072, 8000, 24576000, 0x60, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{3250, 8000, 26000000, 0x0C, 0x18, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static unsigned int es8326_rates[] = {
+	8000, 12000, 16000, 24000, 32000, 48000, 96000
+};
+
+static struct snd_pcm_hw_constraint_list es8326_constraints = {
+	.count = ARRAY_SIZE(es8326_rates),
+	.list = es8326_rates,
+};
+
+static int es8326_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *codec = codec_dai->component;
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec);
+
+	es8326->sysclk = freq;
+
+	if (freq == 0) {
+		es8326->sysclk_constraints->list = NULL;
+		es8326->sysclk_constraints->count = 0;
+		return 0;
+	}
+
+	es8326->sysclk_constraints = &es8326_constraints;
+	return 0;
+}
+
+static int es8326_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u8 iface = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+	case SND_SOC_DAIFMT_CBP_CFP:
+		snd_soc_component_update_bits(component, ES8326_RESET_00,
+					      ES8326_MASTER_MODE_EN, ES8326_MASTER_MODE_EN);
+		break;
+	case SND_SOC_DAIFMT_CBC_CFC:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		dev_err(component->dev, "Codec driver does not support right justified\n");
+		return -EINVAL;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= ES8326_DAIFMT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= ES8326_DAIFMT_DSP_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= ES8326_DAIFMT_DSP_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, ES8326_FMT_13, ES8326_DAIFMT_MASK, iface);
+
+	return 0;
+}
+
+static int es8326_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *codec = dai->component;
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec);
+	u8 srate = 0;
+	int coeff;
+
+	coeff = get_coeff(es8326->sysclk, params_rate(params));
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		srate |= ES8326_S16_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		srate |= ES8326_S20_3_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S18_3LE:
+		srate |= ES8326_S18_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		srate |= ES8326_S24_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		srate |= ES8326_S32_LE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface & srate */
+	snd_soc_component_update_bits(codec, ES8326_FMT_13, ES8326_DATA_LEN_MASK, srate);
+
+	if (coeff >= 0) {
+		regmap_write(es8326->regmap,  ES8326_CLK_DIV1_04,
+			     coeff_div[coeff].reg4);
+		regmap_write(es8326->regmap,  ES8326_CLK_DIV2_05,
+			     coeff_div[coeff].reg5);
+		regmap_write(es8326->regmap,  ES8326_CLK_DLL_06,
+			     coeff_div[coeff].reg6);
+		regmap_write(es8326->regmap,  ES8326_CLK_MUX_07,
+			     coeff_div[coeff].reg7);
+		regmap_write(es8326->regmap,  ES8326_CLK_ADC_SEL_08,
+			     coeff_div[coeff].reg8);
+		regmap_write(es8326->regmap,  ES8326_CLK_DAC_SEL_09,
+			     coeff_div[coeff].reg9);
+		regmap_write(es8326->regmap,  ES8326_CLK_ADC_OSR_0A,
+			     coeff_div[coeff].rega);
+		regmap_write(es8326->regmap,  ES8326_CLK_DAC_OSR_0B,
+			     coeff_div[coeff].regb);
+	}
+
+	return 0;
+}
+
+static int es8326_set_bias_level(struct snd_soc_component *codec,
+				 enum snd_soc_bias_level level)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		if (!IS_ERR(es8326->mclk)) {
+			ret = clk_prepare_enable(es8326->mclk);
+			if (ret)
+				return ret;
+		}
+		regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_PWRUP_SEQ_EN);
+		regmap_write(es8326->regmap, ES8326_INTOUT_IO_59, 0x45);
+		regmap_write(es8326->regmap, ES8326_SDINOUT1_IO_5A,
+			    (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT));
+		regmap_write(es8326->regmap, ES8326_SDINOUT23_IO_5B, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE_03, 0x05);
+		regmap_write(es8326->regmap, ES8326_VMIDSEL_18, 0x02);
+		regmap_write(es8326->regmap, ES8326_PGA_PDN_17, 0x40);
+		regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0xAA);
+		regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_ON);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		break;
+	case SND_SOC_BIAS_OFF:
+		if (es8326->mclk)
+			clk_disable_unprepare(es8326->mclk);
+		regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0x11);
+		regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_OFF);
+		regmap_write(es8326->regmap, ES8326_PGA_PDN_17, 0xF8);
+		regmap_write(es8326->regmap, ES8326_VMIDSEL_18, 0x00);
+		regmap_write(es8326->regmap, ES8326_INT_SOURCE_58, 0x08);
+		regmap_write(es8326->regmap, ES8326_SDINOUT1_IO_5A, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_SDINOUT23_IO_5B, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_RESET_00,
+			     ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN);
+		break;
+	}
+
+	return 0;
+}
+
+#define es8326_RATES SNDRV_PCM_RATE_8000_96000
+
+#define es8326_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops es8326_ops = {
+	.hw_params = es8326_pcm_hw_params,
+	.set_fmt = es8326_set_dai_fmt,
+	.set_sysclk = es8326_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver es8326_dai = {
+	.name = "ES8326 HiFi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = es8326_RATES,
+		.formats = es8326_FORMATS,
+		},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = es8326_RATES,
+		.formats = es8326_FORMATS,
+		},
+	.ops = &es8326_ops,
+	.symmetric_rate = 1,
+};
+
+static void es8326_enable_micbias(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_dapm_mutex_lock(dapm);
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1");
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS2");
+	snd_soc_dapm_sync_unlocked(dapm);
+	snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static void es8326_disable_micbias(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_dapm_mutex_lock(dapm);
+	snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1");
+	snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS2");
+	snd_soc_dapm_sync_unlocked(dapm);
+	snd_soc_dapm_mutex_unlock(dapm);
+}
+static void es8326_jack_detect_handler(struct work_struct *work)
+{
+	struct es8326_priv *es8326 =
+		container_of(work, struct es8326_priv, jack_detect_work.work);
+	struct snd_soc_component *comp = es8326->component;
+	unsigned int iface;
+
+	iface = snd_soc_component_read(comp, ES8326_HP_DETECT_FB);
+	dev_dbg(comp->dev, "gpio flag %#04x", iface);
+	if ((iface & ES8326_HPINSERT_FLAG) == 0) {
+		dev_dbg(comp->dev, "No headset detected");
+		snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
+		snd_soc_component_write(comp, ES8326_ADC1_SRC_2A, es8326->mic2_src);
+		es8326_disable_micbias(comp);
+	} else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) {
+		if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) {
+			dev_dbg(comp->dev, "Headset detected");
+			snd_soc_jack_report(es8326->jack, SND_JACK_HEADSET, SND_JACK_HEADSET);
+			snd_soc_component_write(comp, ES8326_ADC1_SRC_2A, es8326->mic1_src);
+		} else {
+			dev_dbg(comp->dev, "Headphone detected");
+			snd_soc_jack_report(es8326->jack, SND_JACK_HEADPHONE, SND_JACK_HEADSET);
+		}
+	}
+}
+
+static irqreturn_t es8326_irq(int irq, void *dev_id)
+{
+	struct es8326_priv *es8326 = dev_id;
+	struct snd_soc_component *comp = es8326->component;
+
+	if(!es8326->jack)
+		goto out;
+	es8326_enable_micbias(comp);
+
+	queue_delayed_work(system_wq, &es8326->jack_detect_work,
+			   msecs_to_jiffies(300));
+
+out:
+	return IRQ_HANDLED;
+}
+
+static int es8326_resume(struct snd_soc_component *component)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	regmap_write(es8326->regmap, ES8326_CLK_CTL_01, ES8326_CLK_ON);
+	/* Two channel ADC */
+	regmap_write(es8326->regmap, ES8326_PULLUP_CTL_F9, 0x02);
+	regmap_write(es8326->regmap, ES8326_CLK_INV_02, 0x00);
+	regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC_0C, 0x1F);
+	regmap_write(es8326->regmap, ES8326_CLK_VMIDS1_10, 0xC8);
+	regmap_write(es8326->regmap, ES8326_CLK_VMIDS2_11, 0x88);
+	regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME_12, 0x20);
+	regmap_write(es8326->regmap, ES8326_SYS_BIAS_1D, 0x08);
+	regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0x22);
+	regmap_write(es8326->regmap, ES8326_ADC1_SRC_2A, es8326->mic1_src);
+	regmap_write(es8326->regmap, ES8326_ADC2_SRC_2B, es8326->mic2_src);
+	regmap_write(es8326->regmap, ES8326_HPJACK_TIMER_56, 0x88);
+	regmap_write(es8326->regmap, ES8326_HP_DET_57,
+		     ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol);
+	regmap_write(es8326->regmap, ES8326_INT_SOURCE_58, 0x08);
+	regmap_write(es8326->regmap, ES8326_INTOUT_IO_59, 0x45);
+	regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_ON);
+	snd_soc_component_update_bits(component, ES8326_PGAGAIN_23,
+				      ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL);
+
+	es8326_irq(es8326->irq, es8326);
+	return 0;
+}
+
+static int es8326_suspend(struct snd_soc_component *component)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	regmap_write(es8326->regmap, ES8326_CLK_CTL_01, ES8326_CLK_OFF);
+	return 0;
+}
+
+static int es8326_probe(struct snd_soc_component *component)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	es8326->component = component;
+	es8326->jd_inverted = device_property_read_bool(component->dev,
+							"everest,jack-detect-inverted");
+
+	ret = device_property_read_u8(component->dev, "everest,mic1-src", &es8326->mic1_src);
+	if (ret != 0) {
+		dev_dbg(component->dev, "mic1-src return %d", ret);
+		es8326->mic1_src = ES8326_ADC_AMIC;
+	}
+	dev_dbg(component->dev, "mic1-src %x", es8326->mic1_src);
+
+	ret = device_property_read_u8(component->dev, "everest,mic2-src", &es8326->mic2_src);
+	if (ret != 0) {
+		dev_dbg(component->dev, "mic2-src return %d", ret);
+		es8326->mic2_src = ES8326_ADC_DMIC;
+	}
+	dev_dbg(component->dev, "mic2-src %x", es8326->mic2_src);
+
+	ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol);
+	if (ret != 0) {
+		dev_dbg(component->dev, "jack-pol return %d", ret);
+		es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP;
+	}
+	dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol);
+
+	es8326_resume(component);
+	return 0;
+}
+
+static void es8326_enable_jack_detect(struct snd_soc_component *component,
+				struct snd_soc_jack *jack)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	mutex_lock(&es8326->lock);
+	if (es8326->jd_inverted)
+		snd_soc_component_update_bits(component, ES8326_HP_DET_57,
+					      ES8326_HP_DET_JACK_POL, ~es8326->jack_pol);
+	es8326->jack = jack;
+
+	mutex_unlock(&es8326->lock);
+	es8326_irq(es8326->irq, es8326);
+}
+
+static void es8326_disable_jack_detect(struct snd_soc_component *component)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "Enter into %s\n", __func__);
+	if (!es8326->jack)
+		return; /* Already disabled (or never enabled) */
+
+	cancel_delayed_work_sync(&es8326->jack_detect_work);
+
+	mutex_lock(&es8326->lock);
+	if (es8326->jack->status & SND_JACK_MICROPHONE)
+		snd_soc_jack_report(es8326->jack, 0, SND_JACK_BTN_0);
+
+	es8326->jack = NULL;
+	mutex_unlock(&es8326->lock);
+}
+
+static int es8326_set_jack(struct snd_soc_component *component,
+			struct snd_soc_jack *jack, void *data)
+{
+	if (jack)
+		es8326_enable_jack_detect(component, jack);
+	else
+		es8326_disable_jack_detect(component);
+
+	return 0;
+}
+
+static void es8326_remove(struct snd_soc_component *component)
+{
+	es8326_disable_jack_detect(component);
+	es8326_set_bias_level(component, SND_SOC_BIAS_OFF);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_es8326 = {
+	.probe = es8326_probe,
+	.remove = es8326_remove,
+	.resume = es8326_resume,
+	.suspend = es8326_suspend,
+	.set_bias_level = es8326_set_bias_level,
+	.set_jack = es8326_set_jack,
+
+	.dapm_widgets = es8326_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(es8326_dapm_widgets),
+	.dapm_routes = es8326_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(es8326_dapm_routes),
+	.controls = es8326_snd_controls,
+	.num_controls = ARRAY_SIZE(es8326_snd_controls),
+};
+
+static int es8326_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct es8326_priv *es8326;
+	int ret;
+
+	es8326 = devm_kzalloc(&i2c->dev, sizeof(struct es8326_priv), GFP_KERNEL);
+	if (!es8326)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, es8326);
+	es8326->i2c = i2c;
+	mutex_init(&es8326->lock);
+	es8326->regmap = devm_regmap_init_i2c(i2c, &es8326_regmap_config);
+	if (IS_ERR(es8326->regmap)) {
+		ret = PTR_ERR(es8326->regmap);
+		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
+	es8326->irq = i2c->irq;
+	/* ES8316 is level-based while ES8326 is edge-based */
+	ret = devm_request_threaded_irq(&i2c->dev, es8326->irq, NULL, es8326_irq,
+					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					"es8326", es8326);
+	if (ret)
+		dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+	INIT_DELAYED_WORK(&es8326->jack_detect_work,
+			  es8326_jack_detect_handler);
+
+	es8326->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+	if (IS_ERR(es8326->mclk)) {
+		dev_err(&i2c->dev, "unable to get mclk\n");
+		return PTR_ERR(es8326->mclk);
+	}
+	if (!es8326->mclk)
+		dev_warn(&i2c->dev, "assuming static mclk\n");
+
+	ret = clk_prepare_enable(es8326->mclk);
+	if (ret) {
+		dev_err(&i2c->dev, "unable to enable mclk\n");
+		return ret;
+	}
+	return devm_snd_soc_register_component(&i2c->dev,
+					&soc_component_dev_es8326,
+					&es8326_dai, 1);
+}
+
+static const struct i2c_device_id es8326_i2c_id[] = {
+	{"es8326", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, es8326_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id es8326_of_match[] = {
+	{ .compatible = "everest,es8326", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, es8326_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id es8326_acpi_match[] = {
+	{"ESSX8326", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, es8326_acpi_match);
+#endif
+
+static struct i2c_driver es8326_i2c_driver = {
+	.driver = {
+		.name = "es8326",
+		.acpi_match_table = ACPI_PTR(es8326_acpi_match),
+		.of_match_table = of_match_ptr(es8326_of_match),
+	},
+	.probe = es8326_i2c_probe,
+};
+module_i2c_driver(es8326_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC es8326 driver");
+MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h
new file mode 100755
index 000000000000..9affd5c14407
--- /dev/null
+++ b/sound/soc/codecs/es8326.h
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * es8326.c -- es8326 ALSA SoC audio driver
+ * Copyright Everest Semiconductor Co.,Ltd
+ *
+ * Authors: David Yang <yangxiaohua@everest-semi.com>
+ */
+
+#ifndef _ES8326_H
+#define _ES8326_H
+
+#define CONFIG_HHTECH_MINIPMP	1
+
+/* ES8326 register space */
+
+#define ES8326_RESET_00         0x00
+#define ES8326_CLK_CTL_01         0x01
+#define ES8326_CLK_INV_02        0x02
+#define ES8326_CLK_RESAMPLE_03         0x03
+#define ES8326_CLK_DIV1_04        0x04
+#define ES8326_CLK_DIV2_05       0x05
+#define ES8326_CLK_DLL_06       0x06
+#define ES8326_CLK_MUX_07      0x07
+#define ES8326_CLK_ADC_SEL_08       0x08
+#define ES8326_CLK_DAC_SEL_09      0x09
+#define ES8326_CLK_ADC_OSR_0A      0x0a
+#define ES8326_CLK_DAC_OSR_0B      0x0b
+#define ES8326_CLK_DIV_CPC_0C      0x0c
+#define ES8326_CLK_DIV_BCLK_0D      0x0d
+#define ES8326_CLK_TRI_0E      0x0e
+#define ES8326_CLK_DIV_LRCK_0F      0x0f
+#define ES8326_CLK_VMIDS1_10      0x10
+#define ES8326_CLK_VMIDS2_11      0x11
+#define ES8326_CLK_CAL_TIME_12     0x12
+#define ES8326_FMT_13     0x13
+
+#define ES8326_DAC_MUTE_14     0x14
+#define ES8326_ADC_MUTE_15     0x15
+#define ES8326_ANA_PDN_16     0x16
+#define ES8326_PGA_PDN_17      0x17
+#define ES8326_VMIDSEL_18      0x18
+#define ES8326_ANA_LOWPOWER_19      0x19
+#define ES8326_ANA_DMS_1A      0x1a
+#define ES8326_ANA_MICBIAS_1B      0x1b
+#define ES8326_ANA_VSEL_1C      0x1c
+#define ES8326_SYS_BIAS_1D      0x1d
+#define ES8326_BIAS_SW1_1E      0x1e
+#define ES8326_BIAS_SW2_1F      0x1f
+#define ES8326_BIAS_SW3_20     0x20
+#define ES8326_BIAS_SW4_21     0x21
+#define ES8326_VMIDLOW_22     0x22
+
+#define ES8326_PGAGAIN_23     0x23
+#define ES8326_HP_DRIVER_24     0x24
+#define ES8326_DAC2HPMIX_25     0x25
+#define ES8326_HP_VOL_26     0x26
+#define ES8326_HP_CAL_27     0x27
+#define ES8326_HP_DRIVER_REF_28     0x28
+#define ES8326_ADC_SCALE_29     0x29
+#define ES8326_ADC1_SRC_2A     0x2a
+#define ES8326_ADC2_SRC_2B     0x2b
+#define ES8326_ADC1_VOL_2C     0x2c
+#define ES8326_ADC2_VOL_2D     0x2d
+#define ES8326_ADC_RAMPRATE_2E     0x2e
+#define ES8326_2F     0x2f
+#define ES8326_30     0x30
+#define ES8326_31     0x31
+#define ES8326_ALC_RECOVERY_32     0x32
+#define ES8326_ALC_LEVEL_33     0x33
+#define ES8326_ADC_HPFS1_34     0x34
+#define ES8326_ADC_HPFS2_35     0x35
+#define ES8326_ADC_EQ_36		0x36
+#define ES8326_HP_CAL_4A		0x4A
+#define ES8326_HPL_OFFSET_INI_4B		0x4B
+#define ES8326_HPR_OFFSET_INI_4C		0x4C
+#define ES8326_DAC_DSM_4D		0x4D
+#define ES8326_DAC_RAMPRATE_4E		0x4E
+#define ES8326_DAC_VPPSCALE_4F		0x4F
+#define ES8326_DAC_VOL_50		0x50
+#define ES8326_DRC_RECOVERY_53		0x53
+#define ES8326_DRC_WINSIZE_54		0x54
+#define ES8326_HPJACK_TIMER_56		0x56
+#define ES8326_HP_DET_57	0x57
+#define ES8326_INT_SOURCE_58	0x58
+#define ES8326_INTOUT_IO_59	0x59
+#define ES8326_SDINOUT1_IO_5A	0x5A
+#define ES8326_SDINOUT23_IO_5B	0x5B
+#define ES8326_JACK_PULSE_5C	0x5C
+
+#define ES8326_PULLUP_CTL_F9	0xF9
+#define ES8326_HP_DETECT_FB	0xFB
+#define ES8326_CHIP_ID1_FD	0xFD
+#define ES8326_CHIP_ID2_FE	0xFE
+#define ES8326_CHIP_VERSION_FF	0xFF
+
+/* ES8326_RESET_00 */
+#define ES8326_CSM_ON (1 << 7)
+#define ES8326_MASTER_MODE_EN	(1 << 6)
+#define	ES8326_PWRUP_SEQ_EN	(1 << 5)
+#define ES8326_CODEC_RESET (0x0f << 0)
+#define ES8326_CSM_OFF (0 << 7)
+
+/* ES8326_CLK_CTL_01 */
+#define ES8326_CLK_ON (0x7f << 0)
+#define ES8326_CLK_OFF (0 << 0)
+
+/* ES8326_CLK_INV_02 */
+#define ES8326_BCLK_AS_MCLK (1 << 3)
+
+/* ES8326_FMT_13 */
+#define ES8326_S24_LE	(0 << 2)
+#define ES8326_S20_3_LE	(1 << 2)
+#define ES8326_S18_LE	(2 << 2)
+#define ES8326_S16_LE	(3 << 2)
+#define ES8326_S32_LE	(4 << 2)
+#define ES8326_DATA_LEN_MASK	(7 << 2)
+
+#define ES8326_DAIFMT_MASK	((1 << 5) | (3 << 0))
+#define ES8326_DAIFMT_I2S	0
+#define ES8326_DAIFMT_LEFT_J	(1 << 0)
+#define ES8326_DAIFMT_DSP_A		(3 << 0)
+#define ES8326_DAIFMT_DSP_B		((1 << 5) | (3 << 0))
+
+/* ES8326_PGAGAIN_23 */
+#define ES8326_MIC_SEL_MASK (3 << 4)
+#define ES8326_MIC1_SEL	(1 << 4)
+#define ES8326_MIC2_SEL (1 << 5)
+
+/* ES8326_HP_CAL_27 */
+#define ES8326_HPOR_SHIFT 4
+
+/* ES8326_ADC1_SRC_2A */
+#define ES8326_ADC1_SHIFT 0
+#define ES8326_ADC2_SHIFT 4
+#define ES8326_ADC_SRC_ANA 0
+#define ES8326_ADC_SRC_ANA_INV_SW0 1
+#define ES8326_ADC_SRC_ANA_INV_SW1 2
+#define ES8326_ADC_SRC_DMIC_MCLK 3
+#define ES8326_ADC_SRC_DMIC_SDIN2 4
+#define ES8326_ADC_SRC_DMIC_SDIN2_INV 5
+#define ES8326_ADC_SRC_DMIC_SDIN3 6
+#define ES8326_ADC_SRC_DMIC_SDIN3_INV 7
+
+#define ES8326_ADC_AMIC	((ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC2_SHIFT) \
+		| (ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC1_SHIFT))
+#define ES8326_ADC_DMIC	((ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC2_SHIFT) \
+		| (ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC1_SHIFT))
+/* ES8326_ADC2_SRC_2B */
+#define ES8326_ADC3_SHIFT 0
+#define ES8326_ADC4_SHIFT 3
+
+/* ES8326_HP_DET_57 */
+#define ES8326_HP_DET_SRC_PIN27 (1 << 5)
+#define ES8326_HP_DET_SRC_PIN9 (1 << 4)
+#define ES8326_HP_DET_JACK_POL (1 << 3)
+#define ES8326_HP_DET_BUTTON_POL (1 << 2)
+#define ES8326_HP_TYPE_OMTP	(3 << 0)
+#define ES8326_HP_TYPE_CTIA	(2 << 0)
+#define ES8326_HP_TYPE_AUTO	(1 << 0)
+#define ES8326_HP_TYPE_AUTO_INV	(0 << 0)
+
+/* ES8326_SDINOUT1_IO_5A */
+#define ES8326_IO_INPUT	(0 << 0)
+#define ES8326_IO_SDIN_SLOT0 (1 << 0)
+#define ES8326_IO_SDIN_SLOT1 (2 << 0)
+#define ES8326_IO_SDIN_SLOT2 (3 << 0)
+#define ES8326_IO_SDIN_SLOT7 (8 << 0)
+#define ES8326_IO_DMIC_CLK (9 << 0)
+#define ES8326_IO_DMIC_CLK_INV (0x0a << 0)
+#define ES8326_IO_SDOUT2 (0x0b << 0)
+#define ES8326_IO_LOW (0x0e << 0)
+#define ES8326_IO_HIGH (0x0f << 0)
+#define ES8326_ADC2DAC (1 << 3)
+#define ES8326_SDINOUT1_SHIFT 4
+
+/* ES8326_SDINOUT23_IO_5B */
+#define ES8326_SDINOUT2_SHIFT 4
+#define ES8326_SDINOUT3_SHIFT 0
+
+/* ES8326_HP_DETECT_FB */
+#define ES8326_HPINSERT_FLAG (1 << 1)
+#define ES8326_HPBUTTON_FLAG (1 << 0)
+
+/* ES8326_CHIP_VERSION_FF 0xFF */
+#define ES8326_VERSION_B (1 << 0)
+
+#endif
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH] ASoC: codecs: add support for ES8326
@ 2022-07-15  5:41 Zhu Ning
  2022-07-15 13:05 ` Pierre-Louis Bossart
  2022-07-15 19:04 ` Mark Brown
  0 siblings, 2 replies; 11+ messages in thread
From: Zhu Ning @ 2022-07-15  5:41 UTC (permalink / raw)
  To: alsa-devel
  Cc: devicetree, Zhu Ning, pierre-louis.bossart, tiwai, broonie,
	Zhu Ning, David Yang

The ES8326 codec is not compatible with ES8316 and requires a dedicated driver.

Signed-off-by: David Yang <yangxiaohua@everest-semi.com>
Signed-off-by: Zhu Ning <zhuning@everest-semi.com>
---
 sound/soc/codecs/Kconfig  |   5 +
 sound/soc/codecs/Makefile |   2 +
 sound/soc/codecs/es8326.c | 794 ++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/es8326.h | 187 +++++++++
 4 files changed, 988 insertions(+)
 mode change 100644 => 100755 sound/soc/codecs/Kconfig
 mode change 100644 => 100755 sound/soc/codecs/Makefile
 create mode 100755 sound/soc/codecs/es8326.c
 create mode 100755 sound/soc/codecs/es8326.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
old mode 100644
new mode 100755
index 6165db92a629..b0a15cce416d
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -98,6 +98,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_DA9055
 	imply SND_SOC_DMIC
 	imply SND_SOC_ES8316
+	imply SND_SOC_ES8326
 	imply SND_SOC_ES8328_SPI
 	imply SND_SOC_ES8328_I2C
 	imply SND_SOC_ES7134
@@ -911,6 +912,10 @@ config SND_SOC_ES8316
 	tristate "Everest Semi ES8316 CODEC"
 	depends on I2C
 
+config SND_SOC_ES8326
+	tristate "Everest Semi ES8326 CODEC"
+	depends on I2C
+
 config SND_SOC_ES8328
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
old mode 100644
new mode 100755
index 28dc4edfd01f..ae9d789b5381
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -100,6 +100,7 @@ snd-soc-dmic-objs := dmic.o
 snd-soc-es7134-objs := es7134.o
 snd-soc-es7241-objs := es7241.o
 snd-soc-es8316-objs := es8316.o
+snd-soc-es8326-objs := es8326.o
 snd-soc-es8328-objs := es8328.o
 snd-soc-es8328-i2c-objs := es8328-i2c.o
 snd-soc-es8328-spi-objs := es8328-spi.o
@@ -452,6 +453,7 @@ obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_ES7134)	+= snd-soc-es7134.o
 obj-$(CONFIG_SND_SOC_ES7241)	+= snd-soc-es7241.o
 obj-$(CONFIG_SND_SOC_ES8316)    += snd-soc-es8316.o
+obj-$(CONFIG_SND_SOC_ES8326)    += snd-soc-es8326.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
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
new file mode 100755
index 000000000000..d62c596ac878
--- /dev/null
+++ b/sound/soc/codecs/es8326.c
@@ -0,0 +1,794 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// es8326.c -- es8326 ALSA SoC audio driver
+// Copyright Everest Semiconductor Co., Ltd
+//
+// Authors: David Yang <yangxiaohua@everest-semi.com>
+//
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "es8326.h"
+
+struct es8326_priv {
+	struct clk *mclk;
+	struct snd_pcm_hw_constraint_list *sysclk_constraints;
+	struct i2c_client *i2c;
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct delayed_work jack_detect_work;
+	struct snd_soc_jack *jack;
+	int irq;
+	/* The lock protects the situation that an irq is generated
+	 * while enabling or disabling irq.
+	 */
+	struct mutex lock;
+	u8 mic1_src;
+	u8 mic2_src;
+	u8 jack_pol;
+	bool jd_inverted;
+	unsigned int sysclk;
+};
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9550, 50, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_analog_pga_tlv, 0, 300, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_pga_tlv, 0, 600, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(softramp_rate, 0, 100, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(drc_target_tlv, -3200, 200, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(drc_recovery_tlv, -125, 250, 0);
+
+static const char *const winsize[] = {
+	"0.25db/2  LRCK",
+	"0.25db/4  LRCK",
+	"0.25db/8  LRCK",
+	"0.25db/16  LRCK",
+	"0.25db/32  LRCK",
+	"0.25db/64  LRCK",
+	"0.25db/128  LRCK",
+	"0.25db/256  LRCK",
+	"0.25db/512  LRCK",
+	"0.25db/1024  LRCK",
+	"0.25db/2048  LRCK",
+	"0.25db/4096  LRCK",
+	"0.25db/8192  LRCK",
+	"0.25db/16384  LRCK",
+	"0.25db/32768  LRCK",
+	"0.25db/65536  LRCK",
+};
+
+static const char *const dacpol_txt[] =	{
+	"Normal", "R Invert", "L Invert", "L + R Invert" };
+
+static const struct soc_enum dacpol =
+	SOC_ENUM_SINGLE(ES8326_DAC_DSM_4D, 4, 4, dacpol_txt);
+static const struct soc_enum alc_winsize =
+	SOC_ENUM_SINGLE(ES8326_ADC_RAMPRATE_2E, 4, 16, winsize);
+static const struct soc_enum drc_winsize =
+	SOC_ENUM_SINGLE(ES8326_DRC_WINSIZE_54, 4, 16, winsize);
+
+static const struct snd_kcontrol_new es8326_snd_controls[] = {
+	SOC_SINGLE_TLV("DAC Playback Volume", ES8326_DAC_VOL_50, 0, 0xbf, 0, dac_vol_tlv),
+	SOC_ENUM("Playback Polarity", dacpol),
+	SOC_SINGLE_TLV("DAC Ramp Rate", ES8326_DAC_RAMPRATE_4E, 0, 0x0f, 0, softramp_rate),
+	SOC_SINGLE_TLV("DRC Recovery Level", ES8326_DRC_RECOVERY_53, 0, 4, 0, drc_recovery_tlv),
+	SOC_ENUM("DRC Winsize", drc_winsize),
+	SOC_SINGLE_TLV("DRC Target Level", ES8326_DRC_WINSIZE_54, 0, 0x0f, 0, drc_target_tlv),
+
+	SOC_DOUBLE_R_TLV("ADC Capture Volume", ES8326_ADC1_VOL_2C, ES8326_ADC2_VOL_2D, 0, 0xff, 0,
+			 adc_vol_tlv),
+	SOC_DOUBLE_TLV("ADC PGA Volume", ES8326_ADC_SCALE_29, 4, 0, 5, 0, adc_pga_tlv),
+	SOC_SINGLE_TLV("ADC PGA Gain Volume", ES8326_PGAGAIN_23, 0, 10, 0, adc_analog_pga_tlv),
+	SOC_SINGLE_TLV("ADC Ramp Rate", ES8326_ADC_RAMPRATE_2E, 0, 0x0f, 0, softramp_rate),
+	SOC_SINGLE("ALC Capture Switch", ES8326_ALC_RECOVERY_32, 3, 1, 0),
+	SOC_SINGLE_TLV("ALC Capture Recovery Level", ES8326_ALC_LEVEL_33,
+			0, 4, 0, drc_recovery_tlv),
+	SOC_ENUM("ALC Capture Winsize", alc_winsize),
+	SOC_SINGLE_TLV("ALC Capture Target Level", ES8326_ALC_LEVEL_33,
+			0, 0x0f, 0, drc_target_tlv),
+
+};
+
+static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("MIC3"),
+	SND_SOC_DAPM_INPUT("MIC4"),
+
+	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* ADC Digital Mute */
+	SND_SOC_DAPM_PGA("ADC L1", ES8326_ADC_MUTE_15, 0, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC R1", ES8326_ADC_MUTE_15, 1, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC L2", ES8326_ADC_MUTE_15, 2, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC R2", ES8326_ADC_MUTE_15, 3, 1, NULL, 0),
+
+	/* Analog Power Supply*/
+	SND_SOC_DAPM_DAC("Right DAC", NULL, ES8326_ANA_PDN_16, 0, 1),
+	SND_SOC_DAPM_DAC("Left DAC", NULL, ES8326_ANA_PDN_16, 1, 1),
+	SND_SOC_DAPM_SUPPLY("Analog Power", ES8326_ANA_PDN_16, 7, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("IBias Power", ES8326_ANA_PDN_16, 6, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Vref", ES8326_ANA_PDN_16, 5, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Vref", ES8326_ANA_PDN_16, 4, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Vref Power", ES8326_ANA_PDN_16, 3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", ES8326_ANA_MICBIAS_1B, 2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", ES8326_ANA_MICBIAS_1B, 3, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX_25, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX_25, 3, 0, NULL, 0),
+
+	/* Headphone Charge Pump and Output */
+	SND_SOC_DAPM_SUPPLY("HPOR Cal", ES8326_HP_CAL_27, 7, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HPOL Cal", ES8326_HP_CAL_27, 3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8326_HP_DRIVER_24,
+			    3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Driver Bias", ES8326_HP_DRIVER_24,
+			    2, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone LDO", ES8326_HP_DRIVER_24,
+			    1, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Reference", ES8326_HP_DRIVER_24,
+			    0, 1, NULL, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL_27,
+			 ES8326_HPOR_SHIFT, 7, 7, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL_27,
+			 0, 7, 7, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_route es8326_dapm_routes[] = {
+	{"ADC L1", NULL, "MIC1"},
+	{"ADC R1", NULL, "MIC2"},
+	{"ADC L2", NULL, "MIC3"},
+	{"ADC R2", NULL, "MIC4"},
+
+
+	{"ADC L", NULL, "ADC L1"},
+	{"ADC R", NULL, "ADC R1"},
+	{"ADC L", NULL, "ADC L2"},
+	{"ADC R", NULL, "ADC R2"},
+
+	{"I2S OUT", NULL, "ADC L"},
+	{"I2S OUT", NULL, "ADC R"},
+
+	{"I2S OUT", NULL, "Analog Power"},
+	{"I2S OUT", NULL, "ADC Vref"},
+	{"I2S OUT", NULL, "Vref Power"},
+	{"I2S OUT", NULL, "IBias Power"},
+	{"I2S IN", NULL, "Analog Power"},
+	{"I2S IN", NULL, "DAC Vref"},
+	{"I2S IN", NULL, "Vref Power"},
+	{"I2S IN", NULL, "IBias Power"},
+
+	{"Right DAC", NULL, "I2S IN"},
+	{"Left DAC", NULL, "I2S IN"},
+
+	{"LHPMIX", NULL, "Left DAC"},
+	{"RHPMIX", NULL, "Right DAC"},
+
+	{"HPOR", NULL, "HPOR Cal"},
+	{"HPOL", NULL, "HPOL Cal"},
+	{"HPOR", NULL, "HPOR Supply"},
+	{"HPOL", NULL, "HPOL Supply"},
+	{"HPOL", NULL, "Headphone Charge Pump"},
+	{"HPOR", NULL, "Headphone Charge Pump"},
+	{"HPOL", NULL, "Headphone Driver Bias"},
+	{"HPOR", NULL, "Headphone Driver Bias"},
+	{"HPOL", NULL, "Headphone LDO"},
+	{"HPOR", NULL, "Headphone LDO"},
+	{"HPOL", NULL, "Headphone Reference"},
+	{"HPOR", NULL, "Headphone Reference"},
+
+	{"HPOL", NULL, "LHPMIX"},
+	{"HPOR", NULL, "RHPMIX"},
+};
+
+static const struct regmap_range es8326_volatile_ranges[] = {
+	regmap_reg_range(ES8326_HP_DETECT_FB, ES8326_HP_DETECT_FB),
+};
+
+static const struct regmap_access_table es8326_volatile_table = {
+	.yes_ranges = es8326_volatile_ranges,
+	.n_yes_ranges = ARRAY_SIZE(es8326_volatile_ranges),
+};
+
+const struct regmap_config es8326_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = 0xff,
+	.volatile_table = &es8326_volatile_table,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+struct _coeff_div {
+	u16 fs;
+	u32 rate;
+	u32 mclk;
+	u8 reg4;
+	u8 reg5;
+	u8 reg6;
+	u8 reg7;
+	u8 reg8;
+	u8 reg9;
+	u8 rega;
+	u8 regb;
+};
+
+/* codec hifi mclk clock divider coefficients */
+/* {ratio, LRCK, MCLK, REG04, REG05, REG06, REG07, REG08, REG09, REG10, REG11} */
+static const struct _coeff_div coeff_div[] = {
+	{32, 8000, 256000, 0x60, 0x00, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{32, 16000, 512000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{32, 44100, 1411200, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{32, 48000, 1536000, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{36, 8000, 288000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+	{36, 16000, 576000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+	{48, 8000, 384000, 0x60, 0x02, 0x1F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{48, 16000, 768000, 0x20, 0x02, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{48, 48000, 2304000, 0x00, 0x02, 0x0D, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{64, 8000, 512000, 0x60, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{64, 16000, 1024000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{64, 44100, 2822400, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{64, 48000, 3072000, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{72, 8000, 576000, 0x20, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{72, 16000, 1152000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+	{96, 8000, 768000, 0x60, 0x02, 0x1D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{96, 16000, 1536000, 0x20, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{100, 48000, 4800000, 0x04, 0x04, 0x3F, 0x6D, 0x38, 0x08, 0x4f, 0x1f},
+	{125, 48000, 6000000, 0x04, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{128, 8000, 1024000, 0x60, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{128, 16000, 2048000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{128, 44100, 5644800, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{128, 48000, 6144000, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{144, 8000, 1152000, 0x20, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{144, 16000, 2304000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{192, 8000, 1536000, 0x60, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{192, 16000, 3072000, 0x20, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+	{200, 48000, 9600000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{250, 48000, 12000000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{256, 8000, 2048000, 0x60, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{256, 16000, 4096000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{256, 44100, 11289600, 0x00, 0x00, 0x10, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{256, 48000, 12288000, 0x00, 0x00, 0x30, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{288, 8000, 2304000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+	{384, 8000, 3072000, 0x60, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+	{384, 16000, 6144000, 0x20, 0x02, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{384, 48000, 18432000, 0x00, 0x02, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{400, 48000, 19200000, 0x09, 0x04, 0x0f, 0x6d, 0x3a, 0x0A, 0x4F, 0x1F},
+	{500, 48000, 24000000, 0x18, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{512, 8000, 4096000, 0x60, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{512, 16000, 8192000, 0x20, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+	{512, 44100, 22579200, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{512, 48000, 24576000, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{768, 8000, 6144000, 0x60, 0x02, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{768, 16000, 12288000, 0x20, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{800, 48000, 38400000, 0x00, 0x18, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+	{1024, 8000, 8192000, 0x60, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{1024, 16000, 16384000, 0x20, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{1152, 16000, 18432000, 0x20, 0x08, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{1536, 8000, 12288000, 0x60, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+
+	{1536, 16000, 24576000, 0x20, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+	{1625, 8000, 13000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{1625, 16000, 26000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+	{2048, 8000, 16384000, 0x60, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{2304, 8000, 18432000, 0x40, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x5F},
+	{3072, 8000, 24576000, 0x60, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+	{3250, 8000, 26000000, 0x0C, 0x18, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static unsigned int es8326_rates[] = {
+	8000, 12000, 16000, 24000, 32000, 48000, 96000
+};
+
+static struct snd_pcm_hw_constraint_list es8326_constraints = {
+	.count = ARRAY_SIZE(es8326_rates),
+	.list = es8326_rates,
+};
+
+static int es8326_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *codec = codec_dai->component;
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec);
+
+	es8326->sysclk = freq;
+
+	if (freq == 0) {
+		es8326->sysclk_constraints->list = NULL;
+		es8326->sysclk_constraints->count = 0;
+		return 0;
+	}
+
+	es8326->sysclk_constraints = &es8326_constraints;
+	return 0;
+}
+
+static int es8326_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u8 iface = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+	case SND_SOC_DAIFMT_CBP_CFP:
+		snd_soc_component_update_bits(component, ES8326_RESET_00,
+					      ES8326_MASTER_MODE_EN, ES8326_MASTER_MODE_EN);
+		break;
+	case SND_SOC_DAIFMT_CBC_CFC:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		dev_err(component->dev, "Codec driver does not support right justified\n");
+		return -EINVAL;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= ES8326_DAIFMT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= ES8326_DAIFMT_DSP_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= ES8326_DAIFMT_DSP_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, ES8326_FMT_13, ES8326_DAIFMT_MASK, iface);
+
+	return 0;
+}
+
+static int es8326_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *codec = dai->component;
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec);
+	u8 srate = 0;
+	int coeff;
+
+	coeff = get_coeff(es8326->sysclk, params_rate(params));
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		srate |= ES8326_S16_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		srate |= ES8326_S20_3_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S18_3LE:
+		srate |= ES8326_S18_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		srate |= ES8326_S24_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		srate |= ES8326_S32_LE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface & srate */
+	snd_soc_component_update_bits(codec, ES8326_FMT_13, ES8326_DATA_LEN_MASK, srate);
+
+	if (coeff >= 0) {
+		regmap_write(es8326->regmap,  ES8326_CLK_DIV1_04,
+			     coeff_div[coeff].reg4);
+		regmap_write(es8326->regmap,  ES8326_CLK_DIV2_05,
+			     coeff_div[coeff].reg5);
+		regmap_write(es8326->regmap,  ES8326_CLK_DLL_06,
+			     coeff_div[coeff].reg6);
+		regmap_write(es8326->regmap,  ES8326_CLK_MUX_07,
+			     coeff_div[coeff].reg7);
+		regmap_write(es8326->regmap,  ES8326_CLK_ADC_SEL_08,
+			     coeff_div[coeff].reg8);
+		regmap_write(es8326->regmap,  ES8326_CLK_DAC_SEL_09,
+			     coeff_div[coeff].reg9);
+		regmap_write(es8326->regmap,  ES8326_CLK_ADC_OSR_0A,
+			     coeff_div[coeff].rega);
+		regmap_write(es8326->regmap,  ES8326_CLK_DAC_OSR_0B,
+			     coeff_div[coeff].regb);
+	}
+
+	return 0;
+}
+
+static int es8326_set_bias_level(struct snd_soc_component *codec,
+				 enum snd_soc_bias_level level)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		if (!IS_ERR(es8326->mclk)) {
+			ret = clk_prepare_enable(es8326->mclk);
+			if (ret)
+				return ret;
+		}
+		regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_PWRUP_SEQ_EN);
+		regmap_write(es8326->regmap, ES8326_INTOUT_IO_59, 0x45);
+		regmap_write(es8326->regmap, ES8326_SDINOUT1_IO_5A,
+			    (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT));
+		regmap_write(es8326->regmap, ES8326_SDINOUT23_IO_5B, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE_03, 0x05);
+		regmap_write(es8326->regmap, ES8326_VMIDSEL_18, 0x02);
+		regmap_write(es8326->regmap, ES8326_PGA_PDN_17, 0x40);
+		regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0xAA);
+		regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_ON);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		break;
+	case SND_SOC_BIAS_OFF:
+		if (es8326->mclk)
+			clk_disable_unprepare(es8326->mclk);
+		regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0x11);
+		regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_OFF);
+		regmap_write(es8326->regmap, ES8326_PGA_PDN_17, 0xF8);
+		regmap_write(es8326->regmap, ES8326_VMIDSEL_18, 0x00);
+		regmap_write(es8326->regmap, ES8326_INT_SOURCE_58, 0x08);
+		regmap_write(es8326->regmap, ES8326_SDINOUT1_IO_5A, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_SDINOUT23_IO_5B, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_RESET_00,
+			     ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN);
+		break;
+	}
+
+	return 0;
+}
+
+#define es8326_RATES SNDRV_PCM_RATE_8000_96000
+
+#define es8326_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops es8326_ops = {
+	.hw_params = es8326_pcm_hw_params,
+	.set_fmt = es8326_set_dai_fmt,
+	.set_sysclk = es8326_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver es8326_dai = {
+	.name = "ES8326 HiFi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = es8326_RATES,
+		.formats = es8326_FORMATS,
+		},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = es8326_RATES,
+		.formats = es8326_FORMATS,
+		},
+	.ops = &es8326_ops,
+	.symmetric_rate = 1,
+};
+
+static void es8326_enable_micbias(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_dapm_mutex_lock(dapm);
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1");
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS2");
+	snd_soc_dapm_sync_unlocked(dapm);
+	snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static void es8326_disable_micbias(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_dapm_mutex_lock(dapm);
+	snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1");
+	snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS2");
+	snd_soc_dapm_sync_unlocked(dapm);
+	snd_soc_dapm_mutex_unlock(dapm);
+}
+static void es8326_jack_detect_handler(struct work_struct *work)
+{
+	struct es8326_priv *es8326 =
+		container_of(work, struct es8326_priv, jack_detect_work.work);
+	struct snd_soc_component *comp = es8326->component;
+	unsigned int iface;
+
+	iface = snd_soc_component_read(comp, ES8326_HP_DETECT_FB);
+	dev_dbg(comp->dev, "gpio flag %#04x", iface);
+	if ((iface & ES8326_HPINSERT_FLAG) == 0) {
+		dev_dbg(comp->dev, "No headset detected");
+		snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
+		snd_soc_component_write(comp, ES8326_ADC1_SRC_2A, es8326->mic2_src);
+		es8326_disable_micbias(comp);
+	} else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) {
+		if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) {
+			dev_dbg(comp->dev, "Headset detected");
+			snd_soc_jack_report(es8326->jack, SND_JACK_HEADSET, SND_JACK_HEADSET);
+			snd_soc_component_write(comp, ES8326_ADC1_SRC_2A, es8326->mic1_src);
+		} else {
+			dev_dbg(comp->dev, "Headphone detected");
+			snd_soc_jack_report(es8326->jack, SND_JACK_HEADPHONE, SND_JACK_HEADSET);
+		}
+	}
+}
+
+static irqreturn_t es8326_irq(int irq, void *dev_id)
+{
+	struct es8326_priv *es8326 = dev_id;
+	struct snd_soc_component *comp = es8326->component;
+
+	if(!es8326->jack)
+		goto out;
+	es8326_enable_micbias(comp);
+
+	queue_delayed_work(system_wq, &es8326->jack_detect_work,
+			   msecs_to_jiffies(300));
+
+out:
+	return IRQ_HANDLED;
+}
+
+static int es8326_resume(struct snd_soc_component *component)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	regmap_write(es8326->regmap, ES8326_CLK_CTL_01, ES8326_CLK_ON);
+	/* Two channel ADC */
+	regmap_write(es8326->regmap, ES8326_PULLUP_CTL_F9, 0x02);
+	regmap_write(es8326->regmap, ES8326_CLK_INV_02, 0x00);
+	regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC_0C, 0x1F);
+	regmap_write(es8326->regmap, ES8326_CLK_VMIDS1_10, 0xC8);
+	regmap_write(es8326->regmap, ES8326_CLK_VMIDS2_11, 0x88);
+	regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME_12, 0x20);
+	regmap_write(es8326->regmap, ES8326_SYS_BIAS_1D, 0x08);
+	regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0x22);
+	regmap_write(es8326->regmap, ES8326_ADC1_SRC_2A, es8326->mic1_src);
+	regmap_write(es8326->regmap, ES8326_ADC2_SRC_2B, es8326->mic2_src);
+	regmap_write(es8326->regmap, ES8326_HPJACK_TIMER_56, 0x88);
+	regmap_write(es8326->regmap, ES8326_HP_DET_57,
+		     ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol);
+	regmap_write(es8326->regmap, ES8326_INT_SOURCE_58, 0x08);
+	regmap_write(es8326->regmap, ES8326_INTOUT_IO_59, 0x45);
+	regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_ON);
+	snd_soc_component_update_bits(component, ES8326_PGAGAIN_23,
+				      ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL);
+
+	es8326_irq(es8326->irq, es8326);
+	return 0;
+}
+
+static int es8326_suspend(struct snd_soc_component *component)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	regmap_write(es8326->regmap, ES8326_CLK_CTL_01, ES8326_CLK_OFF);
+	return 0;
+}
+
+static int es8326_probe(struct snd_soc_component *component)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	es8326->component = component;
+	es8326->jd_inverted = device_property_read_bool(component->dev,
+							"everest,jack-detect-inverted");
+
+	ret = device_property_read_u8(component->dev, "everest,mic1-src", &es8326->mic1_src);
+	if (ret != 0) {
+		dev_dbg(component->dev, "mic1-src return %d", ret);
+		es8326->mic1_src = ES8326_ADC_AMIC;
+	}
+	dev_dbg(component->dev, "mic1-src %x", es8326->mic1_src);
+
+	ret = device_property_read_u8(component->dev, "everest,mic2-src", &es8326->mic2_src);
+	if (ret != 0) {
+		dev_dbg(component->dev, "mic2-src return %d", ret);
+		es8326->mic2_src = ES8326_ADC_DMIC;
+	}
+	dev_dbg(component->dev, "mic2-src %x", es8326->mic2_src);
+
+	ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol);
+	if (ret != 0) {
+		dev_dbg(component->dev, "jack-pol return %d", ret);
+		es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP;
+	}
+	dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol);
+
+	es8326_resume(component);
+	return 0;
+}
+
+static void es8326_enable_jack_detect(struct snd_soc_component *component,
+				struct snd_soc_jack *jack)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	mutex_lock(&es8326->lock);
+	if (es8326->jd_inverted)
+		snd_soc_component_update_bits(component, ES8326_HP_DET_57,
+					      ES8326_HP_DET_JACK_POL, ~es8326->jack_pol);
+	es8326->jack = jack;
+
+	mutex_unlock(&es8326->lock);
+	es8326_irq(es8326->irq, es8326);
+}
+
+static void es8326_disable_jack_detect(struct snd_soc_component *component)
+{
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "Enter into %s\n", __func__);
+	if (!es8326->jack)
+		return; /* Already disabled (or never enabled) */
+
+	cancel_delayed_work_sync(&es8326->jack_detect_work);
+
+	mutex_lock(&es8326->lock);
+	if (es8326->jack->status & SND_JACK_MICROPHONE)
+		snd_soc_jack_report(es8326->jack, 0, SND_JACK_BTN_0);
+
+	es8326->jack = NULL;
+	mutex_unlock(&es8326->lock);
+}
+
+static int es8326_set_jack(struct snd_soc_component *component,
+			struct snd_soc_jack *jack, void *data)
+{
+	if (jack)
+		es8326_enable_jack_detect(component, jack);
+	else
+		es8326_disable_jack_detect(component);
+
+	return 0;
+}
+
+static void es8326_remove(struct snd_soc_component *component)
+{
+	es8326_disable_jack_detect(component);
+	es8326_set_bias_level(component, SND_SOC_BIAS_OFF);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_es8326 = {
+	.probe = es8326_probe,
+	.remove = es8326_remove,
+	.resume = es8326_resume,
+	.suspend = es8326_suspend,
+	.set_bias_level = es8326_set_bias_level,
+	.set_jack = es8326_set_jack,
+
+	.dapm_widgets = es8326_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(es8326_dapm_widgets),
+	.dapm_routes = es8326_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(es8326_dapm_routes),
+	.controls = es8326_snd_controls,
+	.num_controls = ARRAY_SIZE(es8326_snd_controls),
+};
+
+static int es8326_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct es8326_priv *es8326;
+	int ret;
+
+	es8326 = devm_kzalloc(&i2c->dev, sizeof(struct es8326_priv), GFP_KERNEL);
+	if (!es8326)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, es8326);
+	es8326->i2c = i2c;
+	mutex_init(&es8326->lock);
+	es8326->regmap = devm_regmap_init_i2c(i2c, &es8326_regmap_config);
+	if (IS_ERR(es8326->regmap)) {
+		ret = PTR_ERR(es8326->regmap);
+		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
+	es8326->irq = i2c->irq;
+	/* ES8316 is level-based while ES8326 is edge-based */
+	ret = devm_request_threaded_irq(&i2c->dev, es8326->irq, NULL, es8326_irq,
+					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					"es8326", es8326);
+	if (ret)
+		dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+	INIT_DELAYED_WORK(&es8326->jack_detect_work,
+			  es8326_jack_detect_handler);
+
+	es8326->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+	if (IS_ERR(es8326->mclk)) {
+		dev_err(&i2c->dev, "unable to get mclk\n");
+		return PTR_ERR(es8326->mclk);
+	}
+	if (!es8326->mclk)
+		dev_warn(&i2c->dev, "assuming static mclk\n");
+
+	ret = clk_prepare_enable(es8326->mclk);
+	if (ret) {
+		dev_err(&i2c->dev, "unable to enable mclk\n");
+		return ret;
+	}
+	return devm_snd_soc_register_component(&i2c->dev,
+					&soc_component_dev_es8326,
+					&es8326_dai, 1);
+}
+
+static const struct i2c_device_id es8326_i2c_id[] = {
+	{"es8326", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, es8326_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id es8326_of_match[] = {
+	{ .compatible = "everest,es8326", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, es8326_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id es8326_acpi_match[] = {
+	{"ESSX8326", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, es8326_acpi_match);
+#endif
+
+static struct i2c_driver es8326_i2c_driver = {
+	.driver = {
+		.name = "es8326",
+		.acpi_match_table = ACPI_PTR(es8326_acpi_match),
+		.of_match_table = of_match_ptr(es8326_of_match),
+	},
+	.probe = es8326_i2c_probe,
+};
+module_i2c_driver(es8326_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC es8326 driver");
+MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h
new file mode 100755
index 000000000000..9affd5c14407
--- /dev/null
+++ b/sound/soc/codecs/es8326.h
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * es8326.c -- es8326 ALSA SoC audio driver
+ * Copyright Everest Semiconductor Co.,Ltd
+ *
+ * Authors: David Yang <yangxiaohua@everest-semi.com>
+ */
+
+#ifndef _ES8326_H
+#define _ES8326_H
+
+#define CONFIG_HHTECH_MINIPMP	1
+
+/* ES8326 register space */
+
+#define ES8326_RESET_00         0x00
+#define ES8326_CLK_CTL_01         0x01
+#define ES8326_CLK_INV_02        0x02
+#define ES8326_CLK_RESAMPLE_03         0x03
+#define ES8326_CLK_DIV1_04        0x04
+#define ES8326_CLK_DIV2_05       0x05
+#define ES8326_CLK_DLL_06       0x06
+#define ES8326_CLK_MUX_07      0x07
+#define ES8326_CLK_ADC_SEL_08       0x08
+#define ES8326_CLK_DAC_SEL_09      0x09
+#define ES8326_CLK_ADC_OSR_0A      0x0a
+#define ES8326_CLK_DAC_OSR_0B      0x0b
+#define ES8326_CLK_DIV_CPC_0C      0x0c
+#define ES8326_CLK_DIV_BCLK_0D      0x0d
+#define ES8326_CLK_TRI_0E      0x0e
+#define ES8326_CLK_DIV_LRCK_0F      0x0f
+#define ES8326_CLK_VMIDS1_10      0x10
+#define ES8326_CLK_VMIDS2_11      0x11
+#define ES8326_CLK_CAL_TIME_12     0x12
+#define ES8326_FMT_13     0x13
+
+#define ES8326_DAC_MUTE_14     0x14
+#define ES8326_ADC_MUTE_15     0x15
+#define ES8326_ANA_PDN_16     0x16
+#define ES8326_PGA_PDN_17      0x17
+#define ES8326_VMIDSEL_18      0x18
+#define ES8326_ANA_LOWPOWER_19      0x19
+#define ES8326_ANA_DMS_1A      0x1a
+#define ES8326_ANA_MICBIAS_1B      0x1b
+#define ES8326_ANA_VSEL_1C      0x1c
+#define ES8326_SYS_BIAS_1D      0x1d
+#define ES8326_BIAS_SW1_1E      0x1e
+#define ES8326_BIAS_SW2_1F      0x1f
+#define ES8326_BIAS_SW3_20     0x20
+#define ES8326_BIAS_SW4_21     0x21
+#define ES8326_VMIDLOW_22     0x22
+
+#define ES8326_PGAGAIN_23     0x23
+#define ES8326_HP_DRIVER_24     0x24
+#define ES8326_DAC2HPMIX_25     0x25
+#define ES8326_HP_VOL_26     0x26
+#define ES8326_HP_CAL_27     0x27
+#define ES8326_HP_DRIVER_REF_28     0x28
+#define ES8326_ADC_SCALE_29     0x29
+#define ES8326_ADC1_SRC_2A     0x2a
+#define ES8326_ADC2_SRC_2B     0x2b
+#define ES8326_ADC1_VOL_2C     0x2c
+#define ES8326_ADC2_VOL_2D     0x2d
+#define ES8326_ADC_RAMPRATE_2E     0x2e
+#define ES8326_2F     0x2f
+#define ES8326_30     0x30
+#define ES8326_31     0x31
+#define ES8326_ALC_RECOVERY_32     0x32
+#define ES8326_ALC_LEVEL_33     0x33
+#define ES8326_ADC_HPFS1_34     0x34
+#define ES8326_ADC_HPFS2_35     0x35
+#define ES8326_ADC_EQ_36		0x36
+#define ES8326_HP_CAL_4A		0x4A
+#define ES8326_HPL_OFFSET_INI_4B		0x4B
+#define ES8326_HPR_OFFSET_INI_4C		0x4C
+#define ES8326_DAC_DSM_4D		0x4D
+#define ES8326_DAC_RAMPRATE_4E		0x4E
+#define ES8326_DAC_VPPSCALE_4F		0x4F
+#define ES8326_DAC_VOL_50		0x50
+#define ES8326_DRC_RECOVERY_53		0x53
+#define ES8326_DRC_WINSIZE_54		0x54
+#define ES8326_HPJACK_TIMER_56		0x56
+#define ES8326_HP_DET_57	0x57
+#define ES8326_INT_SOURCE_58	0x58
+#define ES8326_INTOUT_IO_59	0x59
+#define ES8326_SDINOUT1_IO_5A	0x5A
+#define ES8326_SDINOUT23_IO_5B	0x5B
+#define ES8326_JACK_PULSE_5C	0x5C
+
+#define ES8326_PULLUP_CTL_F9	0xF9
+#define ES8326_HP_DETECT_FB	0xFB
+#define ES8326_CHIP_ID1_FD	0xFD
+#define ES8326_CHIP_ID2_FE	0xFE
+#define ES8326_CHIP_VERSION_FF	0xFF
+
+/* ES8326_RESET_00 */
+#define ES8326_CSM_ON (1 << 7)
+#define ES8326_MASTER_MODE_EN	(1 << 6)
+#define	ES8326_PWRUP_SEQ_EN	(1 << 5)
+#define ES8326_CODEC_RESET (0x0f << 0)
+#define ES8326_CSM_OFF (0 << 7)
+
+/* ES8326_CLK_CTL_01 */
+#define ES8326_CLK_ON (0x7f << 0)
+#define ES8326_CLK_OFF (0 << 0)
+
+/* ES8326_CLK_INV_02 */
+#define ES8326_BCLK_AS_MCLK (1 << 3)
+
+/* ES8326_FMT_13 */
+#define ES8326_S24_LE	(0 << 2)
+#define ES8326_S20_3_LE	(1 << 2)
+#define ES8326_S18_LE	(2 << 2)
+#define ES8326_S16_LE	(3 << 2)
+#define ES8326_S32_LE	(4 << 2)
+#define ES8326_DATA_LEN_MASK	(7 << 2)
+
+#define ES8326_DAIFMT_MASK	((1 << 5) | (3 << 0))
+#define ES8326_DAIFMT_I2S	0
+#define ES8326_DAIFMT_LEFT_J	(1 << 0)
+#define ES8326_DAIFMT_DSP_A		(3 << 0)
+#define ES8326_DAIFMT_DSP_B		((1 << 5) | (3 << 0))
+
+/* ES8326_PGAGAIN_23 */
+#define ES8326_MIC_SEL_MASK (3 << 4)
+#define ES8326_MIC1_SEL	(1 << 4)
+#define ES8326_MIC2_SEL (1 << 5)
+
+/* ES8326_HP_CAL_27 */
+#define ES8326_HPOR_SHIFT 4
+
+/* ES8326_ADC1_SRC_2A */
+#define ES8326_ADC1_SHIFT 0
+#define ES8326_ADC2_SHIFT 4
+#define ES8326_ADC_SRC_ANA 0
+#define ES8326_ADC_SRC_ANA_INV_SW0 1
+#define ES8326_ADC_SRC_ANA_INV_SW1 2
+#define ES8326_ADC_SRC_DMIC_MCLK 3
+#define ES8326_ADC_SRC_DMIC_SDIN2 4
+#define ES8326_ADC_SRC_DMIC_SDIN2_INV 5
+#define ES8326_ADC_SRC_DMIC_SDIN3 6
+#define ES8326_ADC_SRC_DMIC_SDIN3_INV 7
+
+#define ES8326_ADC_AMIC	((ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC2_SHIFT) \
+		| (ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC1_SHIFT))
+#define ES8326_ADC_DMIC	((ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC2_SHIFT) \
+		| (ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC1_SHIFT))
+/* ES8326_ADC2_SRC_2B */
+#define ES8326_ADC3_SHIFT 0
+#define ES8326_ADC4_SHIFT 3
+
+/* ES8326_HP_DET_57 */
+#define ES8326_HP_DET_SRC_PIN27 (1 << 5)
+#define ES8326_HP_DET_SRC_PIN9 (1 << 4)
+#define ES8326_HP_DET_JACK_POL (1 << 3)
+#define ES8326_HP_DET_BUTTON_POL (1 << 2)
+#define ES8326_HP_TYPE_OMTP	(3 << 0)
+#define ES8326_HP_TYPE_CTIA	(2 << 0)
+#define ES8326_HP_TYPE_AUTO	(1 << 0)
+#define ES8326_HP_TYPE_AUTO_INV	(0 << 0)
+
+/* ES8326_SDINOUT1_IO_5A */
+#define ES8326_IO_INPUT	(0 << 0)
+#define ES8326_IO_SDIN_SLOT0 (1 << 0)
+#define ES8326_IO_SDIN_SLOT1 (2 << 0)
+#define ES8326_IO_SDIN_SLOT2 (3 << 0)
+#define ES8326_IO_SDIN_SLOT7 (8 << 0)
+#define ES8326_IO_DMIC_CLK (9 << 0)
+#define ES8326_IO_DMIC_CLK_INV (0x0a << 0)
+#define ES8326_IO_SDOUT2 (0x0b << 0)
+#define ES8326_IO_LOW (0x0e << 0)
+#define ES8326_IO_HIGH (0x0f << 0)
+#define ES8326_ADC2DAC (1 << 3)
+#define ES8326_SDINOUT1_SHIFT 4
+
+/* ES8326_SDINOUT23_IO_5B */
+#define ES8326_SDINOUT2_SHIFT 4
+#define ES8326_SDINOUT3_SHIFT 0
+
+/* ES8326_HP_DETECT_FB */
+#define ES8326_HPINSERT_FLAG (1 << 1)
+#define ES8326_HPBUTTON_FLAG (1 << 0)
+
+/* ES8326_CHIP_VERSION_FF 0xFF */
+#define ES8326_VERSION_B (1 << 0)
+
+#endif
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] ASoC: codecs: add support for ES8326
  2022-07-15  5:41 Zhu Ning
@ 2022-07-15 13:05 ` Pierre-Louis Bossart
  2022-07-15 19:04 ` Mark Brown
  1 sibling, 0 replies; 11+ messages in thread
From: Pierre-Louis Bossart @ 2022-07-15 13:05 UTC (permalink / raw)
  To: Zhu Ning, alsa-devel; +Cc: devicetree, broonie, tiwai, David Yang, Zhu Ning



On 7/15/22 00:41, Zhu Ning wrote:
> The ES8326 codec is not compatible with ES8316 and requires a dedicated driver.
> 
> Signed-off-by: David Yang <yangxiaohua@everest-semi.com>
> Signed-off-by: Zhu Ning <zhuning@everest-semi.com>
> ---

It's helpful for reviewers when you use the -v option in git
format-patch, and a change history below the --- mark also helps
understand what has been modified between versions. Thanks!

>  sound/soc/codecs/Kconfig  |   5 +
>  sound/soc/codecs/Makefile |   2 +
>  sound/soc/codecs/es8326.c | 794 ++++++++++++++++++++++++++++++++++++++
>  sound/soc/codecs/es8326.h | 187 +++++++++
>  4 files changed, 988 insertions(+)
>  mode change 100644 => 100755 sound/soc/codecs/Kconfig
>  mode change 100644 => 100755 sound/soc/codecs/Makefile
>  create mode 100755 sound/soc/codecs/es8326.c
>  create mode 100755 sound/soc/codecs/es8326.h

> +#define es8326_RATES SNDRV_PCM_RATE_8000_96000

this definition omits 24 kHz, you may want to add it explicitly.

> +
> +#define es8326_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
> +	SNDRV_PCM_FMTBIT_S24_LE)
> +
> +static const struct snd_soc_dai_ops es8326_ops = {
> +	.hw_params = es8326_pcm_hw_params,
> +	.set_fmt = es8326_set_dai_fmt,
> +	.set_sysclk = es8326_set_dai_sysclk,
> +};
> +
> +static struct snd_soc_dai_driver es8326_dai = {
> +	.name = "ES8326 HiFi",
> +	.playback = {
> +		.stream_name = "Playback",
> +		.channels_min = 1,
> +		.channels_max = 2,
> +		.rates = es8326_RATES,
> +		.formats = es8326_FORMATS,
> +		},
> +	.capture = {
> +		.stream_name = "Capture",
> +		.channels_min = 1,
> +		.channels_max = 2,
> +		.rates = es8326_RATES,
> +		.formats = es8326_FORMATS,
> +		},
> +	.ops = &es8326_ops,
> +	.symmetric_rate = 1,
> +};
> +
> +static void es8326_enable_micbias(struct snd_soc_component *component)
> +{
> +	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
> +
> +	snd_soc_dapm_mutex_lock(dapm);
> +	snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1");
> +	snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS2");
> +	snd_soc_dapm_sync_unlocked(dapm);
> +	snd_soc_dapm_mutex_unlock(dapm);
> +}
> +
> +static void es8326_disable_micbias(struct snd_soc_component *component)
> +{
> +	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
> +
> +	snd_soc_dapm_mutex_lock(dapm);
> +	snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1");
> +	snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS2");
> +	snd_soc_dapm_sync_unlocked(dapm);
> +	snd_soc_dapm_mutex_unlock(dapm);
> +}
> +static void es8326_jack_detect_handler(struct work_struct *work)
> +{
> +	struct es8326_priv *es8326 =
> +		container_of(work, struct es8326_priv, jack_detect_work.work);
> +	struct snd_soc_component *comp = es8326->component;
> +	unsigned int iface;
> +
> +	iface = snd_soc_component_read(comp, ES8326_HP_DETECT_FB);
> +	dev_dbg(comp->dev, "gpio flag %#04x", iface);
> +	if ((iface & ES8326_HPINSERT_FLAG) == 0) {
> +		dev_dbg(comp->dev, "No headset detected");
> +		snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
> +		snd_soc_component_write(comp, ES8326_ADC1_SRC_2A, es8326->mic2_src);
> +		es8326_disable_micbias(comp);
> +	} else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) {
> +		if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) {
> +			dev_dbg(comp->dev, "Headset detected");
> +			snd_soc_jack_report(es8326->jack, SND_JACK_HEADSET, SND_JACK_HEADSET);
> +			snd_soc_component_write(comp, ES8326_ADC1_SRC_2A, es8326->mic1_src);
> +		} else {
> +			dev_dbg(comp->dev, "Headphone detected");
> +			snd_soc_jack_report(es8326->jack, SND_JACK_HEADPHONE, SND_JACK_HEADSET);
> +		}
> +	}
> +}
> +
> +static irqreturn_t es8326_irq(int irq, void *dev_id)
> +{
> +	struct es8326_priv *es8326 = dev_id;
> +	struct snd_soc_component *comp = es8326->component;
> +
> +	if(!es8326->jack)
> +		goto out;
> +	es8326_enable_micbias(comp);
> +
> +	queue_delayed_work(system_wq, &es8326->jack_detect_work,
> +			   msecs_to_jiffies(300));
> +
> +out:
> +	return IRQ_HANDLED;
> +}
> +
> +static int es8326_resume(struct snd_soc_component *component)
> +{
> +	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
> +
> +	regmap_write(es8326->regmap, ES8326_CLK_CTL_01, ES8326_CLK_ON);
> +	/* Two channel ADC */
> +	regmap_write(es8326->regmap, ES8326_PULLUP_CTL_F9, 0x02);
> +	regmap_write(es8326->regmap, ES8326_CLK_INV_02, 0x00);
> +	regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC_0C, 0x1F);
> +	regmap_write(es8326->regmap, ES8326_CLK_VMIDS1_10, 0xC8);
> +	regmap_write(es8326->regmap, ES8326_CLK_VMIDS2_11, 0x88);
> +	regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME_12, 0x20);
> +	regmap_write(es8326->regmap, ES8326_SYS_BIAS_1D, 0x08);
> +	regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0x22);
> +	regmap_write(es8326->regmap, ES8326_ADC1_SRC_2A, es8326->mic1_src);
> +	regmap_write(es8326->regmap, ES8326_ADC2_SRC_2B, es8326->mic2_src);
> +	regmap_write(es8326->regmap, ES8326_HPJACK_TIMER_56, 0x88);
> +	regmap_write(es8326->regmap, ES8326_HP_DET_57,
> +		     ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol);
> +	regmap_write(es8326->regmap, ES8326_INT_SOURCE_58, 0x08);
> +	regmap_write(es8326->regmap, ES8326_INTOUT_IO_59, 0x45);
> +	regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_ON);
> +	snd_soc_component_update_bits(component, ES8326_PGAGAIN_23,
> +				      ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL);
> +
> +	es8326_irq(es8326->irq, es8326);
> +	return 0;
> +}
> +
> +static int es8326_suspend(struct snd_soc_component *component)
> +{
> +	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
> +
> +	regmap_write(es8326->regmap, ES8326_CLK_CTL_01, ES8326_CLK_OFF);


For symmetry with the resume case, aren't you missing

es8326_disable_micbias(comp);

cancel_delayed_work_sync(&es8326->jack_detect_work);

> +	return 0;
> +}
> +

> +static void es8326_enable_jack_detect(struct snd_soc_component *component,
> +				struct snd_soc_jack *jack)
> +{
> +	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
> +
> +	mutex_lock(&es8326->lock);
> +	if (es8326->jd_inverted)
> +		snd_soc_component_update_bits(component, ES8326_HP_DET_57,
> +					      ES8326_HP_DET_JACK_POL, ~es8326->jack_pol);
> +	es8326->jack = jack;
> +
> +	mutex_unlock(&es8326->lock);
> +	es8326_irq(es8326->irq, es8326);
> +}
> +
> +static void es8326_disable_jack_detect(struct snd_soc_component *component)
> +{
> +	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
> +
> +	dev_dbg(component->dev, "Enter into %s\n", __func__);
> +	if (!es8326->jack)
> +		return; /* Already disabled (or never enabled) */
> +
> +	cancel_delayed_work_sync(&es8326->jack_detect_work);
> +
> +	mutex_lock(&es8326->lock);
> +	if (es8326->jack->status & SND_JACK_MICROPHONE)
> +		snd_soc_jack_report(es8326->jack, 0, SND_JACK_BTN_0);

This one is odd, you don't handle buttons anywhere in this patch but here?

> +
> +	es8326->jack = NULL;
> +	mutex_unlock(&es8326->lock);
> +}
> +

> +static int es8326_i2c_probe(struct i2c_client *i2c,
> +			    const struct i2c_device_id *id)
> +{
> +	struct es8326_priv *es8326;
> +	int ret;
> +
> +	es8326 = devm_kzalloc(&i2c->dev, sizeof(struct es8326_priv), GFP_KERNEL);
> +	if (!es8326)
> +		return -ENOMEM;
> +
> +	i2c_set_clientdata(i2c, es8326);
> +	es8326->i2c = i2c;
> +	mutex_init(&es8326->lock);
> +	es8326->regmap = devm_regmap_init_i2c(i2c, &es8326_regmap_config);
> +	if (IS_ERR(es8326->regmap)) {
> +		ret = PTR_ERR(es8326->regmap);
> +		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
> +		return ret;
> +	}
> +
> +	es8326->irq = i2c->irq;
> +	/* ES8316 is level-based while ES8326 is edge-based */
> +	ret = devm_request_threaded_irq(&i2c->dev, es8326->irq, NULL, es8326_irq,
> +					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> +					"es8326", es8326);
> +	if (ret)
> +		dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
> +	INIT_DELAYED_WORK(&es8326->jack_detect_work,
> +			  es8326_jack_detect_handler);

Something's weird here, either you are missing a return ret;, a newline
or both. This doesn't seem right.

> +
> +	es8326->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
> +	if (IS_ERR(es8326->mclk)) {
> +		dev_err(&i2c->dev, "unable to get mclk\n");
> +		return PTR_ERR(es8326->mclk);
> +	}
> +	if (!es8326->mclk)
> +		dev_warn(&i2c->dev, "assuming static mclk\n");
> +
> +	ret = clk_prepare_enable(es8326->mclk);
> +	if (ret) {
> +		dev_err(&i2c->dev, "unable to enable mclk\n");
> +		return ret;
> +	}
> +	return devm_snd_soc_register_component(&i2c->dev,
> +					&soc_component_dev_es8326,
> +					&es8326_dai, 1);
> +}

I am also wondering if on remove you'd need to do the same thing as on
suspend (disable the mic bias and cancel the workqueue)?

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] ASoC: codecs: add support for ES8326
  2022-07-15  5:41 Zhu Ning
  2022-07-15 13:05 ` Pierre-Louis Bossart
@ 2022-07-15 19:04 ` Mark Brown
  1 sibling, 0 replies; 11+ messages in thread
From: Mark Brown @ 2022-07-15 19:04 UTC (permalink / raw)
  To: Zhu Ning
  Cc: devicetree, alsa-devel, pierre-louis.bossart, tiwai, Zhu Ning,
	David Yang

[-- Attachment #1: Type: text/plain, Size: 1711 bytes --]

On Fri, Jul 15, 2022 at 01:41:00PM +0800, Zhu Ning wrote:

Looks mostly good but there's still some issues here, plus the ones
Pierre found.  Only one or two are substantial though, some of the
things below are really minor:

Please check the coding style matches the kernel coding style -
checkpatch will probably help here.

> +	snd_soc_dapm_mutex_unlock(dapm);
> +}
> +static void es8326_jack_detect_handler(struct work_struct *work)

Blank line missing between functions.

> +	if(!es8326->jack)
> +		goto out;

Missing space after the if.

> +static int es8326_resume(struct snd_soc_component *component)
> +{

I'm not seeing anything in here to resync the register map with the
device - the driver is using a register cache so that's going to break
if the device looses power over suspend.  TBH it's not clear to me that
the driver isn't hard coding a specific set of paths...

> +	regmap_write(es8326->regmap, ES8326_INT_SOURCE_58, 0x08);
> +	regmap_write(es8326->regmap, ES8326_INTOUT_IO_59, 0x45);

Some of the hard coded register write sequences in here look a lot like
they're assuming a specific board layout and might need more device tree
configurability - what if the board doesn't use an interrupt or uses a
different one?

> +	ret = device_property_read_u8(component->dev, "everest,mic1-src", &es8326->mic1_src);
> +	if (ret != 0) {

This is adding a DT binding but there's no DT binding document.
Previous versions of this driver did have one, please include it with
every submission.

> --- /dev/null
> +++ b/sound/soc/codecs/es8326.h
> @@ -0,0 +1,187 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * es8326.c -- es8326 ALSA SoC audio driver

Commend has the wrong filename here.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2022-07-15 19:05 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-07-07  1:18 [PATCH] ASoC: codecs: add support for ES8326 Zhu Ning
2022-07-07  9:38 ` kernel test robot
2022-07-07 12:35 ` kernel test robot
2022-07-07 21:39 ` kernel test robot
2022-07-08 17:40 ` Mark Brown
  -- strict thread matches above, loose matches on Subject: below --
2022-07-15  5:41 Zhu Ning
2022-07-15 13:05 ` Pierre-Louis Bossart
2022-07-15 19:04 ` Mark Brown
2022-07-15  5:25 Zhu Ning
2022-04-05 13:12 Zhu Ning
2022-04-05 14:02 ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox