All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 1/2] ASoC: dt-bindings: Add Everest ES8326 audio CODEC
@ 2022-08-16  2:44 Zhu Ning
  2022-08-16  2:44   ` Zhu Ning
  2022-08-16 13:48   ` Mark Brown
  0 siblings, 2 replies; 5+ messages in thread
From: Zhu Ning @ 2022-08-16  2:44 UTC (permalink / raw)
  To: alsa-devel
  Cc: amadeusz.slawinski, pierre-louis.bossart, tiwai, broonie,
	devicetree, robh, Zhu Ning, David Yang, Zhu Ning

Add device tree binding documentation for Everest ES8326

Signed-off-by: David Yang <yangxiaohua@everest-semi.com>
Signed-off-by: Zhu Ning <zhuning@everest-semi.com>
----
v5 tested by dtschema
---
 .../bindings/sound/everest,es8326.yaml        | 116 ++++++++++++++++++
 1 file changed, 116 insertions(+)
 create mode 100755 Documentation/devicetree/bindings/sound/everest,es8326.yaml

diff --git a/Documentation/devicetree/bindings/sound/everest,es8326.yaml b/Documentation/devicetree/bindings/sound/everest,es8326.yaml
new file mode 100755
index 000000000000..07781408e788
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/everest,es8326.yaml
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/everest,es8326.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Everest ES8326 audio CODEC
+
+maintainers:
+  - David Yang <yangxiaohua@everest-semi.com>
+
+properties:
+  compatible:
+    const: everest,es8326
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: clock for master clock (MCLK)
+
+  clock-names:
+    items:
+      - const: mclk
+
+  "#sound-dai-cells":
+    const: 0
+
+  everest,jack-pol:
+    $ref: /schemas/types.yaml#/definitions/uint8
+    description: |
+      just the value of reg 57. Bit(3) decides whether the jack polarity is inverted.
+      Bit(2) decides whether the button on the headset is inverted.
+      Bit(1)/(0) decides the mic properity to be OMTP/CTIA or auto.
+    minimum: 0x00
+    maximum: 0x0f
+    default: 0x0f
+
+  everest,mic1-src:
+    $ref: /schemas/types.yaml#/definitions/uint8
+    description:
+      the value of reg 2A when headset plugged.
+    minimum: 0x00
+    maximum: 0x77
+    default: 0x22
+
+  everest,mic2-src:
+    $ref: /schemas/types.yaml#/definitions/uint8
+    description:
+      the value of reg 2A when headset unplugged.
+    minimum: 0x00
+    maximum: 0x77
+    default: 0x44
+
+  everest,jack-detect-inverted:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Defined to invert the jack detection.
+
+  everest,interrupt-src:
+    $ref: /schemas/types.yaml#/definitions/uint8
+    description: |
+      value of reg 0x58, Defines the interrupt source.
+      Bit(2) 1 means button press triggers irq, 0 means not.
+      Bit(3) 1 means PIN9 is the irq source for jack detection. When set to 0,
+      bias change on PIN9 do not triggers irq.
+      Bit(4) 1 means PIN27 is the irq source for jack detection.
+      Bit(5) 1 means PIN9 is the irq source after MIC detect.
+      Bit(6) 1 means PIN27 is the irq source after MIC detect.
+    minimum: 0
+    maximum: 0x3c
+    default: 0x08
+
+  everest,interrupt-clk:
+    $ref: /schemas/types.yaml#/definitions/uint8
+    description: |
+     value of reg 0x59, Defines the interrupt output behavior.
+     Bit(0-3) 0 means irq pulse equals 512*internal clock
+       1 means irq pulse equals 1024*internal clock
+       2 means ...
+       7 means irq pulse equals 65536*internal clock
+       8 means irq mutes PA
+       9 means irq mutes PA and DAC output
+     Bit(4) 1 means we invert the interrupt output.
+     Bit(6) 1 means the chip do not detect jack type after button released.
+       0 means the chip detect jack type again after button released.
+    minimum: 0
+    maximum: 0x7f
+    default: 0x45
+
+required:
+  - compatible
+  - reg
+  - "#sound-dai-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      es8326: codec@19 {
+        compatible = "everest,es8326";
+        reg = <0x19>;
+        clocks = <&clks 10>;
+        clock-names = "mclk";
+        #sound-dai-cells = <0>;
+        everest,mic1-src = [22];
+        everest,mic2-src = [44];
+        everest,jack-pol = [0e];
+        everest,interrupt-src = [08];
+        everest,interrupt-clk = [45];
+      };
+    };
-- 
2.36.1


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

* [PATCH v6 2/2] ASoC: codecs: add support for ES8326
  2022-08-16  2:44 [PATCH v6 1/2] ASoC: dt-bindings: Add Everest ES8326 audio CODEC Zhu Ning
@ 2022-08-16  2:44   ` Zhu Ning
  2022-08-16 13:48   ` Mark Brown
  1 sibling, 0 replies; 5+ messages in thread
From: Zhu Ning @ 2022-08-16  2:44 UTC (permalink / raw)
  To: alsa-devel
  Cc: robh, Zhu Ning, devicetree, tiwai, amadeusz.slawinski, broonie,
	Zhu Ning, pierre-louis.bossart, 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>
------
v6 remove rate 96000 remove HEX suffix
---
 sound/soc/codecs/Kconfig  |   5 +
 sound/soc/codecs/Makefile |   2 +
 sound/soc/codecs/es8326.c | 905 ++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/es8326.h | 182 ++++++++
 4 files changed, 1094 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 d16b4efb88a7..9465992c2d68 100644
--- 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
@@ -913,6 +914,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 92fd441d426a..81e00863d992 100644
--- 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
@@ -455,6 +456,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..975302b2a61d
--- /dev/null
+++ b/sound/soc/codecs/es8326.c
@@ -0,0 +1,905 @@
+// 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 i2c_client *i2c;
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct delayed_work jack_detect_work;
+	struct delayed_work button_press_work;
+	struct snd_soc_jack *jack;
+	int irq;
+	/* The lock protects the situation that an irq is generated
+	 * while enabling or disabling or during an irq.
+	 */
+	struct mutex lock;
+	u8 mic1_src;
+	u8 mic2_src;
+	u8 jack_pol;
+	u8 interrupt_src;
+	u8 interrupt_clk;
+	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, 4, 4, dacpol_txt);
+static const struct soc_enum alc_winsize =
+	SOC_ENUM_SINGLE(ES8326_ADC_RAMPRATE, 4, 16, winsize);
+static const struct soc_enum drc_winsize =
+	SOC_ENUM_SINGLE(ES8326_DRC_WINSIZE, 4, 16, winsize);
+
+static const struct snd_kcontrol_new es8326_snd_controls[] = {
+	SOC_SINGLE_TLV("DAC Playback Volume", ES8326_DAC_VOL, 0, 0xbf, 0, dac_vol_tlv),
+	SOC_ENUM("Playback Polarity", dacpol),
+	SOC_SINGLE_TLV("DAC Ramp Rate", ES8326_DAC_RAMPRATE, 0, 0x0f, 0, softramp_rate),
+	SOC_SINGLE_TLV("DRC Recovery Level", ES8326_DRC_RECOVERY, 0, 4, 0, drc_recovery_tlv),
+	SOC_ENUM("DRC Winsize", drc_winsize),
+	SOC_SINGLE_TLV("DRC Target Level", ES8326_DRC_WINSIZE, 0, 0x0f, 0, drc_target_tlv),
+
+	SOC_DOUBLE_R_TLV("ADC Capture Volume", ES8326_ADC1_VOL, ES8326_ADC2_VOL, 0, 0xff, 0,
+			 adc_vol_tlv),
+	SOC_DOUBLE_TLV("ADC PGA Volume", ES8326_ADC_SCALE, 4, 0, 5, 0, adc_pga_tlv),
+	SOC_SINGLE_TLV("ADC PGA Gain Volume", ES8326_PGAGAIN, 0, 10, 0, adc_analog_pga_tlv),
+	SOC_SINGLE_TLV("ADC Ramp Rate", ES8326_ADC_RAMPRATE, 0, 0x0f, 0, softramp_rate),
+	SOC_SINGLE("ALC Capture Switch", ES8326_ALC_RECOVERY, 3, 1, 0),
+	SOC_SINGLE_TLV("ALC Capture Recovery Level", ES8326_ALC_LEVEL,
+			0, 4, 0, drc_recovery_tlv),
+	SOC_ENUM("ALC Capture Winsize", alc_winsize),
+	SOC_SINGLE_TLV("ALC Capture Target Level", ES8326_ALC_LEVEL,
+			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, 0, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC R1", ES8326_ADC_MUTE, 1, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC L2", ES8326_ADC_MUTE, 2, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC R2", ES8326_ADC_MUTE, 3, 1, NULL, 0),
+
+	/* Analog Power Supply*/
+	SND_SOC_DAPM_DAC("Right DAC", NULL, ES8326_ANA_PDN, 0, 1),
+	SND_SOC_DAPM_DAC("Left DAC", NULL, ES8326_ANA_PDN, 1, 1),
+	SND_SOC_DAPM_SUPPLY("Analog Power", ES8326_ANA_PDN, 7, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("IBias Power", ES8326_ANA_PDN, 6, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Vref", ES8326_ANA_PDN, 5, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Vref", ES8326_ANA_PDN, 4, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Vref Power", ES8326_ANA_PDN, 3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", ES8326_ANA_MICBIAS, 2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", ES8326_ANA_MICBIAS, 3, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX, 3, 0, NULL, 0),
+
+	/* Headphone Charge Pump and Output */
+	SND_SOC_DAPM_SUPPLY("HPOR Cal", ES8326_HP_CAL, 7, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HPOL Cal", ES8326_HP_CAL, 3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8326_HP_DRIVER,
+			    3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Driver Bias", ES8326_HP_DRIVER,
+			    2, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone LDO", ES8326_HP_DRIVER,
+			    1, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Reference", ES8326_HP_DRIVER,
+			    0, 1, NULL, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL,
+			 ES8326_HPOR_SHIFT, 7, 7, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL,
+			 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, ES8326_HP_DETECT),
+};
+
+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 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;
+
+	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_CBC_CFP:
+		snd_soc_component_update_bits(component, ES8326_RESET,
+					      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, 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 *component = dai->component;
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+	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(component, ES8326_FMT, ES8326_DATA_LEN_MASK, srate);
+
+	if (coeff >= 0) {
+		regmap_write(es8326->regmap,  ES8326_CLK_DIV1,
+			     coeff_div[coeff].reg4);
+		regmap_write(es8326->regmap,  ES8326_CLK_DIV2,
+			     coeff_div[coeff].reg5);
+		regmap_write(es8326->regmap,  ES8326_CLK_DLL,
+			     coeff_div[coeff].reg6);
+		regmap_write(es8326->regmap,  ES8326_CLK_MUX,
+			     coeff_div[coeff].reg7);
+		regmap_write(es8326->regmap,  ES8326_CLK_ADC_SEL,
+			     coeff_div[coeff].reg8);
+		regmap_write(es8326->regmap,  ES8326_CLK_DAC_SEL,
+			     coeff_div[coeff].reg9);
+		regmap_write(es8326->regmap,  ES8326_CLK_ADC_OSR,
+			     coeff_div[coeff].rega);
+		regmap_write(es8326->regmap,  ES8326_CLK_DAC_OSR,
+			     coeff_div[coeff].regb);
+	} else {
+		dev_warn(component->dev, "Clock coefficients do not match");
+	}
+
+	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:
+		ret = clk_prepare_enable(es8326->mclk);
+		if (ret)
+			return ret;
+		regmap_write(es8326->regmap, ES8326_RESET, ES8326_PWRUP_SEQ_EN);
+		regmap_write(es8326->regmap, ES8326_INTOUT_IO, 0x45);
+		regmap_write(es8326->regmap, ES8326_SDINOUT1_IO,
+			    (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT));
+		regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05);
+		regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x02);
+		regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x40);
+		regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0xAA);
+		regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		break;
+	case SND_SOC_BIAS_OFF:
+		clk_disable_unprepare(es8326->mclk);
+		regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x11);
+		regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_OFF);
+		regmap_write(es8326->regmap, ES8326_PGA_PDN, 0xF8);
+		regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x00);
+		regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x08);
+		regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_RESET,
+			     ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN);
+		break;
+	}
+
+	return 0;
+}
+
+#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 = SNDRV_PCM_RATE_8000_48000,
+		.formats = es8326_FORMATS,
+		},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.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);
+}
+
+/*
+ *	For button detection, set the following in soundcard
+ *	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ *	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+ *	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+ */
+static void es8326_jack_button_handler(struct work_struct *work)
+{
+	struct es8326_priv *es8326 =
+		container_of(work, struct es8326_priv, button_press_work.work);
+	struct snd_soc_component *comp = es8326->component;
+	unsigned int iface;
+	static int button_to_report, press_count;
+	static int prev_button, cur_button;
+
+	if (!(es8326->jack->status & SND_JACK_HEADSET)) /* Jack unplugged */
+		return;
+
+	mutex_lock(&es8326->lock);
+	iface = snd_soc_component_read(comp, ES8326_HP_DETECT);
+	switch (iface) {
+	case 0x93:
+		/* pause button detected */
+		cur_button = SND_JACK_BTN_0;
+		break;
+	case 0x6f:
+		/* button volume up */
+		cur_button = SND_JACK_BTN_1;
+		break;
+	case 0x27:
+		/* button volume down */
+		cur_button = SND_JACK_BTN_2;
+		break;
+	case 0x1e:
+		/* button released or not pressed */
+		cur_button = 0;
+		break;
+	default:
+		break;
+	}
+
+	if ((prev_button == cur_button) && (cur_button != 0)) {
+		press_count++;
+		if (press_count > 10) {
+			/* report a press every 500ms */
+			snd_soc_jack_report(es8326->jack, cur_button,
+					SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
+			press_count = 0;
+		}
+		button_to_report = cur_button;
+		queue_delayed_work(system_wq, &es8326->button_press_work,
+				   msecs_to_jiffies(50));
+	} else if (prev_button != cur_button) {
+		/* mismatch, detect again */
+		prev_button = cur_button;
+		queue_delayed_work(system_wq, &es8326->button_press_work,
+				   msecs_to_jiffies(50));
+	} else {
+		/* released or no pressed */
+		if (button_to_report != 0) {
+			snd_soc_jack_report(es8326->jack, button_to_report,
+				    SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
+			snd_soc_jack_report(es8326->jack, 0,
+				    SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
+			button_to_report = 0;
+		}
+	}
+	mutex_unlock(&es8326->lock);
+}
+
+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;
+
+	mutex_lock(&es8326->lock);
+	iface = snd_soc_component_read(comp, ES8326_HP_DETECT);
+	dev_dbg(comp->dev, "gpio flag %#04x", iface);
+	if ((iface & ES8326_HPINSERT_FLAG) == 0) {
+		/* Jack unplugged or spurious IRQ */
+		dev_dbg(comp->dev, "No headset detected");
+		if (es8326->jack->status & SND_JACK_HEADPHONE) {
+			snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
+			snd_soc_component_write(comp, ES8326_ADC1_SRC, es8326->mic2_src);
+			es8326_disable_micbias(comp);
+		}
+	} else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) {
+		if (es8326->jack->status & SND_JACK_HEADSET) {
+			/* detect button */
+			queue_delayed_work(system_wq, &es8326->button_press_work, 10);
+		} else {
+			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, es8326->mic1_src);
+			} else {
+				dev_dbg(comp->dev, "Headphone detected");
+				snd_soc_jack_report(es8326->jack,
+						    SND_JACK_HEADPHONE, SND_JACK_HEADSET);
+			}
+		}
+	}
+	mutex_unlock(&es8326->lock);
+}
+
+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);
+
+	if (es8326->jack->status & SND_JACK_HEADSET)
+		queue_delayed_work(system_wq, &es8326->jack_detect_work,
+				   msecs_to_jiffies(10));
+	else
+		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);
+	unsigned int reg;
+
+	regcache_cache_only(es8326->regmap, false);
+	regcache_sync(es8326->regmap);
+
+	regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON);
+	/* Two channel ADC */
+	regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x02);
+	regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00);
+	regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x1F);
+	regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xC8);
+	regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x88);
+	regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x20);
+	regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x08);
+	regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x22);
+	regmap_write(es8326->regmap, ES8326_ADC1_SRC, es8326->mic1_src);
+	regmap_write(es8326->regmap, ES8326_ADC2_SRC, es8326->mic2_src);
+	regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88);
+	regmap_write(es8326->regmap, ES8326_HP_DET,
+		     ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol);
+	regmap_write(es8326->regmap, ES8326_INT_SOURCE, es8326->interrupt_src);
+	regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk);
+	regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON);
+	snd_soc_component_update_bits(component, ES8326_PGAGAIN,
+				      ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL);
+
+	regmap_read(es8326->regmap, ES8326_CHIP_VERSION, &reg);
+	if ((reg & ES8326_VERSION_B) == 1) {
+		regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0xDD);
+		regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F);
+		regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x0F);
+		/* enable button detect */
+		regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xA0);
+	}
+
+	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);
+
+	cancel_delayed_work_sync(&es8326->jack_detect_work);
+	es8326_disable_micbias(component);
+
+	regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_OFF);
+	regcache_cache_only(es8326->regmap, true);
+	regcache_mark_dirty(es8326->regmap);
+
+	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);
+
+	ret = device_property_read_u8(component->dev, "everest,interrupt-src", &es8326->jack_pol);
+	if (ret != 0) {
+		dev_dbg(component->dev, "interrupt-src return %d", ret);
+		es8326->interrupt_src = ES8326_HP_DET_SRC_PIN9;
+	}
+	dev_dbg(component->dev, "interrupt-src %x", es8326->interrupt_src);
+
+	ret = device_property_read_u8(component->dev, "everest,interrupt-clk", &es8326->jack_pol);
+	if (ret != 0) {
+		dev_dbg(component->dev, "interrupt-clk return %d", ret);
+		es8326->interrupt_clk = 0x45;
+	}
+	dev_dbg(component->dev, "interrupt-clk %x", es8326->interrupt_clk);
+
+	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,
+					      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) {
+		es8326_disable_micbias(component);
+		snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
+	}
+	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),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+};
+
+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;
+	INIT_DELAYED_WORK(&es8326->jack_detect_work,
+			  es8326_jack_detect_handler);
+	INIT_DELAYED_WORK(&es8326->button_press_work,
+			  es8326_jack_button_handler);
+	/* 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_warn(&i2c->dev, "Failed to request IRQ: %d: %d\n",
+		es8326->irq, ret);
+		es8326->irq = -ENXIO;
+	}
+
+	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,
+	.id_table = es8326_i2c_id,
+};
+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..8e5ffe5ee10d
--- /dev/null
+++ b/sound/soc/codecs/es8326.h
@@ -0,0 +1,182 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * es8326.h -- 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		0x00
+#define ES8326_CLK_CTL		0x01
+#define ES8326_CLK_INV		0x02
+#define ES8326_CLK_RESAMPLE	0x03
+#define ES8326_CLK_DIV1		0x04
+#define ES8326_CLK_DIV2		0x05
+#define ES8326_CLK_DLL		0x06
+#define ES8326_CLK_MUX		0x07
+#define ES8326_CLK_ADC_SEL	0x08
+#define ES8326_CLK_DAC_SEL	0x09
+#define ES8326_CLK_ADC_OSR	0x0a
+#define ES8326_CLK_DAC_OSR	0x0b
+#define ES8326_CLK_DIV_CPC	0x0c
+#define ES8326_CLK_DIV_BCLK	0x0d
+#define ES8326_CLK_TRI		0x0e
+#define ES8326_CLK_DIV_LRCK	0x0f
+#define ES8326_CLK_VMIDS1	0x10
+#define ES8326_CLK_VMIDS2	0x11
+#define ES8326_CLK_CAL_TIME	0x12
+#define ES8326_FMT		0x13
+
+#define ES8326_DAC_MUTE		0x14
+#define ES8326_ADC_MUTE		0x15
+#define ES8326_ANA_PDN		0x16
+#define ES8326_PGA_PDN		0x17
+#define ES8326_VMIDSEL		0x18
+#define ES8326_ANA_LP		0x19
+#define ES8326_ANA_DMS		0x1a
+#define ES8326_ANA_MICBIAS	0x1b
+#define ES8326_ANA_VSEL		0x1c
+#define ES8326_SYS_BIAS		0x1d
+#define ES8326_BIAS_SW1		0x1e
+#define ES8326_BIAS_SW2		0x1f
+#define ES8326_BIAS_SW3		0x20
+#define ES8326_BIAS_SW4		0x21
+#define ES8326_VMIDLOW		0x22
+#define ES8326_PGAGAIN		0x23
+#define ES8326_HP_DRIVER	0x24
+#define ES8326_DAC2HPMIX	0x25
+#define ES8326_HP_VOL		0x26
+#define ES8326_HP_CAL		0x27
+#define ES8326_HP_DRIVER_REF	0x28
+#define ES8326_ADC_SCALE	0x29
+#define ES8326_ADC1_SRC		0x2a
+#define ES8326_ADC2_SRC		0x2b
+#define ES8326_ADC1_VOL		0x2c
+#define ES8326_ADC2_VOL		0x2d
+#define ES8326_ADC_RAMPRATE	0x2e
+#define ES8326_ALC_RECOVERY	0x32
+#define ES8326_ALC_LEVEL	0x33
+#define ES8326_ADC_HPFS1	0x34
+#define ES8326_ADC_HPFS2	0x35
+#define ES8326_ADC_EQ		0x36
+#define ES8326_HP_OFFSET_CAL	0x4A
+#define ES8326_HPL_OFFSET_INI	0x4B
+#define ES8326_HPR_OFFSET_INI	0x4C
+#define ES8326_DAC_DSM		0x4D
+#define ES8326_DAC_RAMPRATE	0x4E
+#define ES8326_DAC_VPPSCALE	0x4F
+#define ES8326_DAC_VOL		0x50
+#define ES8326_DRC_RECOVERY	0x53
+#define ES8326_DRC_WINSIZE	0x54
+#define ES8326_HPJACK_TIMER	0x56
+#define ES8326_HP_DET		0x57
+#define ES8326_INT_SOURCE	0x58
+#define ES8326_INTOUT_IO	0x59
+#define ES8326_SDINOUT1_IO	0x5A
+#define ES8326_SDINOUT23_IO	0x5B
+#define ES8326_JACK_PULSE	0x5C
+
+#define ES8326_PULLUP_CTL	0xF9
+#define ES8326_HP_DETECT	0xFB
+#define ES8326_CHIP_ID1		0xFD
+#define ES8326_CHIP_ID2		0xFE
+#define ES8326_CHIP_VERSION	0xFF
+
+/* ES8326_RESET */
+#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 */
+#define ES8326_CLK_ON (0x7f << 0)
+#define ES8326_CLK_OFF (0 << 0)
+
+/* ES8326_CLK_INV */
+#define ES8326_BCLK_AS_MCLK (1 << 3)
+
+/* ES8326_FMT */
+#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 */
+#define ES8326_MIC_SEL_MASK (3 << 4)
+#define ES8326_MIC1_SEL	(1 << 4)
+#define ES8326_MIC2_SEL (1 << 5)
+
+/* ES8326_HP_CAL */
+#define ES8326_HPOR_SHIFT 4
+
+/* ES8326_ADC1_SRC */
+#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 */
+#define ES8326_ADC3_SHIFT 0
+#define ES8326_ADC4_SHIFT 3
+
+/* ES8326_HP_DET */
+#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 */
+#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 */
+#define ES8326_SDINOUT2_SHIFT 4
+#define ES8326_SDINOUT3_SHIFT 0
+
+/* ES8326_HP_DETECT */
+#define ES8326_HPINSERT_FLAG (1 << 1)
+#define ES8326_HPBUTTON_FLAG (1 << 0)
+
+/* ES8326_CHIP_VERSION 0xFF */
+#define ES8326_VERSION_B (1 << 0)
+
+#endif
-- 
2.36.1


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

* [PATCH v6 2/2] ASoC: codecs: add support for ES8326
@ 2022-08-16  2:44   ` Zhu Ning
  0 siblings, 0 replies; 5+ messages in thread
From: Zhu Ning @ 2022-08-16  2:44 UTC (permalink / raw)
  To: alsa-devel
  Cc: amadeusz.slawinski, pierre-louis.bossart, tiwai, broonie,
	devicetree, robh, Zhu Ning, David Yang, Zhu Ning

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>
------
v6 remove rate 96000 remove HEX suffix
---
 sound/soc/codecs/Kconfig  |   5 +
 sound/soc/codecs/Makefile |   2 +
 sound/soc/codecs/es8326.c | 905 ++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/es8326.h | 182 ++++++++
 4 files changed, 1094 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 d16b4efb88a7..9465992c2d68 100644
--- 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
@@ -913,6 +914,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 92fd441d426a..81e00863d992 100644
--- 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
@@ -455,6 +456,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..975302b2a61d
--- /dev/null
+++ b/sound/soc/codecs/es8326.c
@@ -0,0 +1,905 @@
+// 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 i2c_client *i2c;
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct delayed_work jack_detect_work;
+	struct delayed_work button_press_work;
+	struct snd_soc_jack *jack;
+	int irq;
+	/* The lock protects the situation that an irq is generated
+	 * while enabling or disabling or during an irq.
+	 */
+	struct mutex lock;
+	u8 mic1_src;
+	u8 mic2_src;
+	u8 jack_pol;
+	u8 interrupt_src;
+	u8 interrupt_clk;
+	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, 4, 4, dacpol_txt);
+static const struct soc_enum alc_winsize =
+	SOC_ENUM_SINGLE(ES8326_ADC_RAMPRATE, 4, 16, winsize);
+static const struct soc_enum drc_winsize =
+	SOC_ENUM_SINGLE(ES8326_DRC_WINSIZE, 4, 16, winsize);
+
+static const struct snd_kcontrol_new es8326_snd_controls[] = {
+	SOC_SINGLE_TLV("DAC Playback Volume", ES8326_DAC_VOL, 0, 0xbf, 0, dac_vol_tlv),
+	SOC_ENUM("Playback Polarity", dacpol),
+	SOC_SINGLE_TLV("DAC Ramp Rate", ES8326_DAC_RAMPRATE, 0, 0x0f, 0, softramp_rate),
+	SOC_SINGLE_TLV("DRC Recovery Level", ES8326_DRC_RECOVERY, 0, 4, 0, drc_recovery_tlv),
+	SOC_ENUM("DRC Winsize", drc_winsize),
+	SOC_SINGLE_TLV("DRC Target Level", ES8326_DRC_WINSIZE, 0, 0x0f, 0, drc_target_tlv),
+
+	SOC_DOUBLE_R_TLV("ADC Capture Volume", ES8326_ADC1_VOL, ES8326_ADC2_VOL, 0, 0xff, 0,
+			 adc_vol_tlv),
+	SOC_DOUBLE_TLV("ADC PGA Volume", ES8326_ADC_SCALE, 4, 0, 5, 0, adc_pga_tlv),
+	SOC_SINGLE_TLV("ADC PGA Gain Volume", ES8326_PGAGAIN, 0, 10, 0, adc_analog_pga_tlv),
+	SOC_SINGLE_TLV("ADC Ramp Rate", ES8326_ADC_RAMPRATE, 0, 0x0f, 0, softramp_rate),
+	SOC_SINGLE("ALC Capture Switch", ES8326_ALC_RECOVERY, 3, 1, 0),
+	SOC_SINGLE_TLV("ALC Capture Recovery Level", ES8326_ALC_LEVEL,
+			0, 4, 0, drc_recovery_tlv),
+	SOC_ENUM("ALC Capture Winsize", alc_winsize),
+	SOC_SINGLE_TLV("ALC Capture Target Level", ES8326_ALC_LEVEL,
+			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, 0, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC R1", ES8326_ADC_MUTE, 1, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC L2", ES8326_ADC_MUTE, 2, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC R2", ES8326_ADC_MUTE, 3, 1, NULL, 0),
+
+	/* Analog Power Supply*/
+	SND_SOC_DAPM_DAC("Right DAC", NULL, ES8326_ANA_PDN, 0, 1),
+	SND_SOC_DAPM_DAC("Left DAC", NULL, ES8326_ANA_PDN, 1, 1),
+	SND_SOC_DAPM_SUPPLY("Analog Power", ES8326_ANA_PDN, 7, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("IBias Power", ES8326_ANA_PDN, 6, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Vref", ES8326_ANA_PDN, 5, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Vref", ES8326_ANA_PDN, 4, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Vref Power", ES8326_ANA_PDN, 3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", ES8326_ANA_MICBIAS, 2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", ES8326_ANA_MICBIAS, 3, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX, 3, 0, NULL, 0),
+
+	/* Headphone Charge Pump and Output */
+	SND_SOC_DAPM_SUPPLY("HPOR Cal", ES8326_HP_CAL, 7, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HPOL Cal", ES8326_HP_CAL, 3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8326_HP_DRIVER,
+			    3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Driver Bias", ES8326_HP_DRIVER,
+			    2, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone LDO", ES8326_HP_DRIVER,
+			    1, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Reference", ES8326_HP_DRIVER,
+			    0, 1, NULL, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL,
+			 ES8326_HPOR_SHIFT, 7, 7, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL,
+			 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, ES8326_HP_DETECT),
+};
+
+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 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;
+
+	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_CBC_CFP:
+		snd_soc_component_update_bits(component, ES8326_RESET,
+					      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, 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 *component = dai->component;
+	struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+	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(component, ES8326_FMT, ES8326_DATA_LEN_MASK, srate);
+
+	if (coeff >= 0) {
+		regmap_write(es8326->regmap,  ES8326_CLK_DIV1,
+			     coeff_div[coeff].reg4);
+		regmap_write(es8326->regmap,  ES8326_CLK_DIV2,
+			     coeff_div[coeff].reg5);
+		regmap_write(es8326->regmap,  ES8326_CLK_DLL,
+			     coeff_div[coeff].reg6);
+		regmap_write(es8326->regmap,  ES8326_CLK_MUX,
+			     coeff_div[coeff].reg7);
+		regmap_write(es8326->regmap,  ES8326_CLK_ADC_SEL,
+			     coeff_div[coeff].reg8);
+		regmap_write(es8326->regmap,  ES8326_CLK_DAC_SEL,
+			     coeff_div[coeff].reg9);
+		regmap_write(es8326->regmap,  ES8326_CLK_ADC_OSR,
+			     coeff_div[coeff].rega);
+		regmap_write(es8326->regmap,  ES8326_CLK_DAC_OSR,
+			     coeff_div[coeff].regb);
+	} else {
+		dev_warn(component->dev, "Clock coefficients do not match");
+	}
+
+	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:
+		ret = clk_prepare_enable(es8326->mclk);
+		if (ret)
+			return ret;
+		regmap_write(es8326->regmap, ES8326_RESET, ES8326_PWRUP_SEQ_EN);
+		regmap_write(es8326->regmap, ES8326_INTOUT_IO, 0x45);
+		regmap_write(es8326->regmap, ES8326_SDINOUT1_IO,
+			    (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT));
+		regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05);
+		regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x02);
+		regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x40);
+		regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0xAA);
+		regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		break;
+	case SND_SOC_BIAS_OFF:
+		clk_disable_unprepare(es8326->mclk);
+		regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x11);
+		regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_OFF);
+		regmap_write(es8326->regmap, ES8326_PGA_PDN, 0xF8);
+		regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x00);
+		regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x08);
+		regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
+		regmap_write(es8326->regmap, ES8326_RESET,
+			     ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN);
+		break;
+	}
+
+	return 0;
+}
+
+#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 = SNDRV_PCM_RATE_8000_48000,
+		.formats = es8326_FORMATS,
+		},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.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);
+}
+
+/*
+ *	For button detection, set the following in soundcard
+ *	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ *	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+ *	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+ */
+static void es8326_jack_button_handler(struct work_struct *work)
+{
+	struct es8326_priv *es8326 =
+		container_of(work, struct es8326_priv, button_press_work.work);
+	struct snd_soc_component *comp = es8326->component;
+	unsigned int iface;
+	static int button_to_report, press_count;
+	static int prev_button, cur_button;
+
+	if (!(es8326->jack->status & SND_JACK_HEADSET)) /* Jack unplugged */
+		return;
+
+	mutex_lock(&es8326->lock);
+	iface = snd_soc_component_read(comp, ES8326_HP_DETECT);
+	switch (iface) {
+	case 0x93:
+		/* pause button detected */
+		cur_button = SND_JACK_BTN_0;
+		break;
+	case 0x6f:
+		/* button volume up */
+		cur_button = SND_JACK_BTN_1;
+		break;
+	case 0x27:
+		/* button volume down */
+		cur_button = SND_JACK_BTN_2;
+		break;
+	case 0x1e:
+		/* button released or not pressed */
+		cur_button = 0;
+		break;
+	default:
+		break;
+	}
+
+	if ((prev_button == cur_button) && (cur_button != 0)) {
+		press_count++;
+		if (press_count > 10) {
+			/* report a press every 500ms */
+			snd_soc_jack_report(es8326->jack, cur_button,
+					SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
+			press_count = 0;
+		}
+		button_to_report = cur_button;
+		queue_delayed_work(system_wq, &es8326->button_press_work,
+				   msecs_to_jiffies(50));
+	} else if (prev_button != cur_button) {
+		/* mismatch, detect again */
+		prev_button = cur_button;
+		queue_delayed_work(system_wq, &es8326->button_press_work,
+				   msecs_to_jiffies(50));
+	} else {
+		/* released or no pressed */
+		if (button_to_report != 0) {
+			snd_soc_jack_report(es8326->jack, button_to_report,
+				    SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
+			snd_soc_jack_report(es8326->jack, 0,
+				    SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
+			button_to_report = 0;
+		}
+	}
+	mutex_unlock(&es8326->lock);
+}
+
+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;
+
+	mutex_lock(&es8326->lock);
+	iface = snd_soc_component_read(comp, ES8326_HP_DETECT);
+	dev_dbg(comp->dev, "gpio flag %#04x", iface);
+	if ((iface & ES8326_HPINSERT_FLAG) == 0) {
+		/* Jack unplugged or spurious IRQ */
+		dev_dbg(comp->dev, "No headset detected");
+		if (es8326->jack->status & SND_JACK_HEADPHONE) {
+			snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
+			snd_soc_component_write(comp, ES8326_ADC1_SRC, es8326->mic2_src);
+			es8326_disable_micbias(comp);
+		}
+	} else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) {
+		if (es8326->jack->status & SND_JACK_HEADSET) {
+			/* detect button */
+			queue_delayed_work(system_wq, &es8326->button_press_work, 10);
+		} else {
+			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, es8326->mic1_src);
+			} else {
+				dev_dbg(comp->dev, "Headphone detected");
+				snd_soc_jack_report(es8326->jack,
+						    SND_JACK_HEADPHONE, SND_JACK_HEADSET);
+			}
+		}
+	}
+	mutex_unlock(&es8326->lock);
+}
+
+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);
+
+	if (es8326->jack->status & SND_JACK_HEADSET)
+		queue_delayed_work(system_wq, &es8326->jack_detect_work,
+				   msecs_to_jiffies(10));
+	else
+		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);
+	unsigned int reg;
+
+	regcache_cache_only(es8326->regmap, false);
+	regcache_sync(es8326->regmap);
+
+	regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON);
+	/* Two channel ADC */
+	regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x02);
+	regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00);
+	regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x1F);
+	regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xC8);
+	regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x88);
+	regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x20);
+	regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x08);
+	regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x22);
+	regmap_write(es8326->regmap, ES8326_ADC1_SRC, es8326->mic1_src);
+	regmap_write(es8326->regmap, ES8326_ADC2_SRC, es8326->mic2_src);
+	regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88);
+	regmap_write(es8326->regmap, ES8326_HP_DET,
+		     ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol);
+	regmap_write(es8326->regmap, ES8326_INT_SOURCE, es8326->interrupt_src);
+	regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk);
+	regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON);
+	snd_soc_component_update_bits(component, ES8326_PGAGAIN,
+				      ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL);
+
+	regmap_read(es8326->regmap, ES8326_CHIP_VERSION, &reg);
+	if ((reg & ES8326_VERSION_B) == 1) {
+		regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0xDD);
+		regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F);
+		regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x0F);
+		/* enable button detect */
+		regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xA0);
+	}
+
+	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);
+
+	cancel_delayed_work_sync(&es8326->jack_detect_work);
+	es8326_disable_micbias(component);
+
+	regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_OFF);
+	regcache_cache_only(es8326->regmap, true);
+	regcache_mark_dirty(es8326->regmap);
+
+	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);
+
+	ret = device_property_read_u8(component->dev, "everest,interrupt-src", &es8326->jack_pol);
+	if (ret != 0) {
+		dev_dbg(component->dev, "interrupt-src return %d", ret);
+		es8326->interrupt_src = ES8326_HP_DET_SRC_PIN9;
+	}
+	dev_dbg(component->dev, "interrupt-src %x", es8326->interrupt_src);
+
+	ret = device_property_read_u8(component->dev, "everest,interrupt-clk", &es8326->jack_pol);
+	if (ret != 0) {
+		dev_dbg(component->dev, "interrupt-clk return %d", ret);
+		es8326->interrupt_clk = 0x45;
+	}
+	dev_dbg(component->dev, "interrupt-clk %x", es8326->interrupt_clk);
+
+	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,
+					      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) {
+		es8326_disable_micbias(component);
+		snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
+	}
+	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),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+};
+
+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;
+	INIT_DELAYED_WORK(&es8326->jack_detect_work,
+			  es8326_jack_detect_handler);
+	INIT_DELAYED_WORK(&es8326->button_press_work,
+			  es8326_jack_button_handler);
+	/* 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_warn(&i2c->dev, "Failed to request IRQ: %d: %d\n",
+		es8326->irq, ret);
+		es8326->irq = -ENXIO;
+	}
+
+	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,
+	.id_table = es8326_i2c_id,
+};
+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..8e5ffe5ee10d
--- /dev/null
+++ b/sound/soc/codecs/es8326.h
@@ -0,0 +1,182 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * es8326.h -- 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		0x00
+#define ES8326_CLK_CTL		0x01
+#define ES8326_CLK_INV		0x02
+#define ES8326_CLK_RESAMPLE	0x03
+#define ES8326_CLK_DIV1		0x04
+#define ES8326_CLK_DIV2		0x05
+#define ES8326_CLK_DLL		0x06
+#define ES8326_CLK_MUX		0x07
+#define ES8326_CLK_ADC_SEL	0x08
+#define ES8326_CLK_DAC_SEL	0x09
+#define ES8326_CLK_ADC_OSR	0x0a
+#define ES8326_CLK_DAC_OSR	0x0b
+#define ES8326_CLK_DIV_CPC	0x0c
+#define ES8326_CLK_DIV_BCLK	0x0d
+#define ES8326_CLK_TRI		0x0e
+#define ES8326_CLK_DIV_LRCK	0x0f
+#define ES8326_CLK_VMIDS1	0x10
+#define ES8326_CLK_VMIDS2	0x11
+#define ES8326_CLK_CAL_TIME	0x12
+#define ES8326_FMT		0x13
+
+#define ES8326_DAC_MUTE		0x14
+#define ES8326_ADC_MUTE		0x15
+#define ES8326_ANA_PDN		0x16
+#define ES8326_PGA_PDN		0x17
+#define ES8326_VMIDSEL		0x18
+#define ES8326_ANA_LP		0x19
+#define ES8326_ANA_DMS		0x1a
+#define ES8326_ANA_MICBIAS	0x1b
+#define ES8326_ANA_VSEL		0x1c
+#define ES8326_SYS_BIAS		0x1d
+#define ES8326_BIAS_SW1		0x1e
+#define ES8326_BIAS_SW2		0x1f
+#define ES8326_BIAS_SW3		0x20
+#define ES8326_BIAS_SW4		0x21
+#define ES8326_VMIDLOW		0x22
+#define ES8326_PGAGAIN		0x23
+#define ES8326_HP_DRIVER	0x24
+#define ES8326_DAC2HPMIX	0x25
+#define ES8326_HP_VOL		0x26
+#define ES8326_HP_CAL		0x27
+#define ES8326_HP_DRIVER_REF	0x28
+#define ES8326_ADC_SCALE	0x29
+#define ES8326_ADC1_SRC		0x2a
+#define ES8326_ADC2_SRC		0x2b
+#define ES8326_ADC1_VOL		0x2c
+#define ES8326_ADC2_VOL		0x2d
+#define ES8326_ADC_RAMPRATE	0x2e
+#define ES8326_ALC_RECOVERY	0x32
+#define ES8326_ALC_LEVEL	0x33
+#define ES8326_ADC_HPFS1	0x34
+#define ES8326_ADC_HPFS2	0x35
+#define ES8326_ADC_EQ		0x36
+#define ES8326_HP_OFFSET_CAL	0x4A
+#define ES8326_HPL_OFFSET_INI	0x4B
+#define ES8326_HPR_OFFSET_INI	0x4C
+#define ES8326_DAC_DSM		0x4D
+#define ES8326_DAC_RAMPRATE	0x4E
+#define ES8326_DAC_VPPSCALE	0x4F
+#define ES8326_DAC_VOL		0x50
+#define ES8326_DRC_RECOVERY	0x53
+#define ES8326_DRC_WINSIZE	0x54
+#define ES8326_HPJACK_TIMER	0x56
+#define ES8326_HP_DET		0x57
+#define ES8326_INT_SOURCE	0x58
+#define ES8326_INTOUT_IO	0x59
+#define ES8326_SDINOUT1_IO	0x5A
+#define ES8326_SDINOUT23_IO	0x5B
+#define ES8326_JACK_PULSE	0x5C
+
+#define ES8326_PULLUP_CTL	0xF9
+#define ES8326_HP_DETECT	0xFB
+#define ES8326_CHIP_ID1		0xFD
+#define ES8326_CHIP_ID2		0xFE
+#define ES8326_CHIP_VERSION	0xFF
+
+/* ES8326_RESET */
+#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 */
+#define ES8326_CLK_ON (0x7f << 0)
+#define ES8326_CLK_OFF (0 << 0)
+
+/* ES8326_CLK_INV */
+#define ES8326_BCLK_AS_MCLK (1 << 3)
+
+/* ES8326_FMT */
+#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 */
+#define ES8326_MIC_SEL_MASK (3 << 4)
+#define ES8326_MIC1_SEL	(1 << 4)
+#define ES8326_MIC2_SEL (1 << 5)
+
+/* ES8326_HP_CAL */
+#define ES8326_HPOR_SHIFT 4
+
+/* ES8326_ADC1_SRC */
+#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 */
+#define ES8326_ADC3_SHIFT 0
+#define ES8326_ADC4_SHIFT 3
+
+/* ES8326_HP_DET */
+#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 */
+#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 */
+#define ES8326_SDINOUT2_SHIFT 4
+#define ES8326_SDINOUT3_SHIFT 0
+
+/* ES8326_HP_DETECT */
+#define ES8326_HPINSERT_FLAG (1 << 1)
+#define ES8326_HPBUTTON_FLAG (1 << 0)
+
+/* ES8326_CHIP_VERSION 0xFF */
+#define ES8326_VERSION_B (1 << 0)
+
+#endif
-- 
2.36.1


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

* Re: [PATCH v6 1/2] ASoC: dt-bindings: Add Everest ES8326 audio CODEC
  2022-08-16  2:44 [PATCH v6 1/2] ASoC: dt-bindings: Add Everest ES8326 audio CODEC Zhu Ning
@ 2022-08-16 13:48   ` Mark Brown
  2022-08-16 13:48   ` Mark Brown
  1 sibling, 0 replies; 5+ messages in thread
From: Mark Brown @ 2022-08-16 13:48 UTC (permalink / raw)
  To: Zhu Ning, alsa-devel
  Cc: Zhu Ning, robh, devicetree, amadeusz.slawinski, tiwai,
	David Yang, pierre-louis.bossart

On Tue, 16 Aug 2022 10:44:55 +0800, Zhu Ning wrote:
> Add device tree binding documentation for Everest ES8326
> 
> ----
> v5 tested by dtschema
> 
> 

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[1/2] ASoC: dt-bindings: Add Everest ES8326 audio CODEC
      commit: 8c6789f4e2d4ee7d6c8c60daa88ea7a4c4cf6779
[2/2] ASoC: codecs: add support for ES8326
      commit: 5c439937775d77a334696a98fb2a25dee72ffa2d

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

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

* Re: [PATCH v6 1/2] ASoC: dt-bindings: Add Everest ES8326 audio CODEC
@ 2022-08-16 13:48   ` Mark Brown
  0 siblings, 0 replies; 5+ messages in thread
From: Mark Brown @ 2022-08-16 13:48 UTC (permalink / raw)
  To: Zhu Ning, alsa-devel
  Cc: devicetree, robh, tiwai, amadeusz.slawinski, Zhu Ning,
	pierre-louis.bossart, David Yang

On Tue, 16 Aug 2022 10:44:55 +0800, Zhu Ning wrote:
> Add device tree binding documentation for Everest ES8326
> 
> ----
> v5 tested by dtschema
> 
> 

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[1/2] ASoC: dt-bindings: Add Everest ES8326 audio CODEC
      commit: 8c6789f4e2d4ee7d6c8c60daa88ea7a4c4cf6779
[2/2] ASoC: codecs: add support for ES8326
      commit: 5c439937775d77a334696a98fb2a25dee72ffa2d

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

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

end of thread, other threads:[~2022-08-16 13:49 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-16  2:44 [PATCH v6 1/2] ASoC: dt-bindings: Add Everest ES8326 audio CODEC Zhu Ning
2022-08-16  2:44 ` [PATCH v6 2/2] ASoC: codecs: add support for ES8326 Zhu Ning
2022-08-16  2:44   ` Zhu Ning
2022-08-16 13:48 ` [PATCH v6 1/2] ASoC: dt-bindings: Add Everest ES8326 audio CODEC Mark Brown
2022-08-16 13:48   ` Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.