All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jun Yan <jerrysteve1101@gmail.com>
To: lgirdwood@gmail.com, broonie@kernel.org, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org, perex@perex.cz,
	tiwai@suse.com, heiko@sntech.de
Cc: linux-sound@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-rockchip@lists.infradead.org,
	Jun Yan <jerrysteve1101@gmail.com>
Subject: [PATCH 2/2] ASoC: codecs: add support for Everest ES7202 PDM ADC
Date: Tue, 20 Oct 2026 22:31:32 +0800	[thread overview]
Message-ID: <20261020143135.623897-3-jerrysteve1101@gmail.com> (raw)
In-Reply-To: <20261020143135.623897-1-jerrysteve1101@gmail.com>

Add support for the Everest ES7202, a 2-channel PDM analog-to-digital
converter controlled over I2C. The device outputs PDM data to the SoC
PDM controller and is configured through registers for supply voltage,
analog front-end and per-channel PGA gain.

Based on the Rockchip BSP driver[1] by Binyuan Lan <lby@rock-chips.com>
(committed by Tao Huang <huangtao@rock-chips.com>), originally written
by David Yang <yangxiaohua@everest-semi.com>.

[1] https://github.com/rockchip-linux/kernel/blob/develop-6.1/sound/soc/codecs/es7202.c

Link: https://archive.org/details/es-7202-ds
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
 sound/soc/codecs/Kconfig  |  10 +
 sound/soc/codecs/Makefile |   2 +
 sound/soc/codecs/es7202.c | 372 ++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/es7202.h | 133 ++++++++++++++
 4 files changed, 517 insertions(+)
 create mode 100644 sound/soc/codecs/es7202.c
 create mode 100644 sound/soc/codecs/es7202.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index ba59dabeeccd..c1eeebd12cf0 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1274,6 +1274,16 @@ config SND_SOC_HDMI_CODEC
 config SND_SOC_ES7134
 	tristate "Everest Semi ES7134 CODEC"
 
+config SND_SOC_ES7202
+	tristate "Everest Semi ES7202 CODEC"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  Enable support for the Everest Semiconductor ES7202, a 2-channel
+	  PDM analog-to-digital converter controlled over I2C. The device
+	  outputs PDM data to a SoC PDM controller and is configured through
+	  registers for supply voltage, analog front-end and PGA gain.
+
 config SND_SOC_ES7241
 	tristate "Everest Semi ES7241 CODEC"
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 3826f9e4fce8..2a56fad9073a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -129,6 +129,7 @@ snd-soc-da732x-y := da732x.o
 snd-soc-da9055-y := da9055.o
 snd-soc-dmic-y := dmic.o
 snd-soc-es7134-y := es7134.o
+snd-soc-es7202-y := es7202.o
 snd-soc-es7241-y := es7241.o
 snd-soc-es83xx-dsm-common-y := es83xx-dsm-common.o
 snd-soc-es8311-y := es8311.o
@@ -577,6 +578,7 @@ obj-$(CONFIG_SND_SOC_DA732X)	+= snd-soc-da732x.o
 obj-$(CONFIG_SND_SOC_DA9055)	+= snd-soc-da9055.o
 obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_ES7134)	+= snd-soc-es7134.o
+obj-$(CONFIG_SND_SOC_ES7202)	+= snd-soc-es7202.o
 obj-$(CONFIG_SND_SOC_ES7241)	+= snd-soc-es7241.o
 obj-$(CONFIG_SND_SOC_ES83XX_DSM_COMMON)    += snd-soc-es83xx-dsm-common.o
 obj-$(CONFIG_SND_SOC_ES8311)    += snd-soc-es8311.o
diff --git a/sound/soc/codecs/es7202.c b/sound/soc/codecs/es7202.c
new file mode 100644
index 000000000000..c30b0123c91f
--- /dev/null
+++ b/sound/soc/codecs/es7202.c
@@ -0,0 +1,372 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright Everest Semiconductor Co., Ltd.
+ *
+ * Author: David Yang <yangxiaohua@everest-semi.com>
+ * Author: Jun Yan <jerrysteve1101@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "es7202.h"
+
+/*
+ * The main supply voltage selects the analog front-end configuration:
+ * below this threshold the device is configured for 1.8 V, otherwise 3.3 V.
+ */
+#define ES7202_SUPPLY_1V8_MAX_UV	1980000
+#define ES7202_SUPPLY_3V3_DEFAULT_UV	3300000
+
+struct es7202_priv {
+	struct regmap *regmap;
+	struct regulator *supply;
+	struct gpio_desc *reset_gpio;
+	unsigned int supply_uv;
+};
+
+static bool es7202_volatile_reg(struct device *dev, unsigned int reg)
+{
+	/* status and device-id registers are read-only, never cached */
+	return reg == ES7202_CHIP_STA ||
+	       reg == ES7202_DEV_ID1 ||
+	       reg == ES7202_DEV_ID0;
+}
+
+static const struct reg_default es7202_reg_defaults[] = {
+	{ ES7202_RESET,		0x10 },
+	{ ES7202_SOFT_MODE,	0x00 },
+	{ ES7202_CLK_DIV,	0x04 },
+	{ ES7202_CLK_EN,	0x00 },
+	{ ES7202_T1_VMID,	0x01 },
+	{ ES7202_T2_VMID,	0x18 },
+	{ ES7202_PDM_INF_CTL,	0x30 },
+	{ ES7202_MISC_CTL,	0x02 },
+	{ ES7202_ANALOG_EN,	0xff },
+	{ ES7202_BIAS_VMID,	0x0c },
+	{ ES7202_PGA1_BIAS,	0x55 },
+	{ ES7202_PGA2_BIAS,	0x55 },
+	{ ES7202_MOD1_BIAS,	0x8c },
+	{ ES7202_MOD2_BIAS,	0x33 },
+	{ ES7202_VREFP_BIAS,	0x33 },
+	{ ES7202_VMMOD_BIAS,	0x33 },
+	{ ES7202_MODS_BIAS,	0x44 },
+	{ ES7202_ANALOG_LP1,	0x00 },
+	{ ES7202_ANALOG_LP2,	0x00 },
+	{ ES7202_ANALOG_MISC1,	0x00 },
+	{ ES7202_ANALOG_MISC2,	0xf8 },
+	{ ES7202_PGA1,		0x18 },
+	{ ES7202_PGA2,		0x18 },
+};
+
+static const struct regmap_config es7202_regmap = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= ES7202_DEV_ID0,
+	.reg_defaults	= es7202_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(es7202_reg_defaults),
+	.volatile_reg	= es7202_volatile_reg,
+	.cache_type	= REGCACHE_MAPLE,
+};
+
+/*
+ * PGA gain per the datasheet: code 0 is 0 dB, codes 1..10 step +3 dB from
+ * 2.25 dB, and codes 11 and 12 are 30.75 dB and 32.25 dB respectively.  As
+ * the steps are not uniform, a linear TLV (the vendor driver's
+ * DECLARE_TLV_DB_SCALE(mic_boost_tlv, 0, 300, 0)) would misreport the gain,
+ * so use a piecewise range matching the datasheet instead.
+ */
+static const DECLARE_TLV_DB_RANGE(mic_boost_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 10, TLV_DB_SCALE_ITEM(225, 300, 0),
+	11, 11, TLV_DB_SCALE_ITEM(3075, 0, 0),
+	12, 12, TLV_DB_SCALE_ITEM(3225, 0, 0),
+);
+
+static const struct snd_kcontrol_new es7202_controls[] = {
+	SOC_SINGLE_TLV("PGA1 Capture Volume", ES7202_PGA1, 0, 0x0c, 0,
+		       mic_boost_tlv),
+	SOC_SINGLE_TLV("PGA2 Capture Volume", ES7202_PGA2, 0, 0x0c, 0,
+		       mic_boost_tlv),
+};
+
+static const struct snd_soc_dapm_widget es7202_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route es7202_dapm_routes[] = {
+	{ "ADC", NULL, "MIC1" },
+	{ "ADC", NULL, "MIC2" },
+};
+
+static int es7202_mute_pdm(struct es7202_priv *es7202, bool mute)
+{
+	return regmap_update_bits(es7202->regmap, ES7202_PDM_INF_CTL,
+				  ES7202_PDM_INF_CTL_MUTE,
+				  mute ? ES7202_PDM_INF_CTL_MUTE : 0);
+}
+
+static int es7202_hw_init(struct es7202_priv *es7202)
+{
+	struct regmap *regmap = es7202->regmap;
+	bool is_1v8 = es7202->supply_uv > 0 &&
+		      es7202->supply_uv <= ES7202_SUPPLY_1V8_MAX_UV;
+	/*
+	 * Power-up sequence from the vendor driver.
+	 * The analog front-end is configured for the actual supply voltage
+	 * (1.8 V vs 3.3 V) and the analog blocks are ramped out of
+	 * power-down in stages.
+	 */
+	const struct reg_sequence init_seq[] = {
+		{ ES7202_SOFT_MODE,	ES7202_MODE_SOFT_MODE_SEL },
+		{ ES7202_ANALOG_MISC1,	ES7202_ANALOG_MISC1_OFFSETSEL1 |
+					(is_1v8 ? 0 : ES7202_ANALOG_MISC1_SUPPLYSEL) },
+
+		/* 30.75 dB gain */
+		{ ES7202_PGA1,		ES7202_PGA_SELMIC1 |
+					FIELD_PREP(ES7202_PGA_MIC1_GAIN, 11) },
+		{ ES7202_PGA2,		ES7202_PGA_SELMIC2 |
+					FIELD_PREP(ES7202_PGA_MIC2_GAIN, 11) },
+
+		/* analog on, rest powered down */
+		{ ES7202_ANALOG_EN,	ES7202_ANALOG_EN_PDN_ADCVREFGEN |
+					ES7202_ANALOG_EN_MODTOP1_RST |
+					ES7202_ANALOG_EN_MODTOP2_RST |
+					ES7202_ANALOG_EN_PDN_MOD1 |
+					ES7202_ANALOG_EN_PDN_MOD2 |
+					ES7202_ANALOG_EN_PDN_PGA1 |
+					ES7202_ANALOG_EN_PDN_PGA2 },
+
+		{ ES7202_BIAS_VMID,	FIELD_PREP(ES7202_BIAS_ADCBIAS_SWH1, 3) |
+					ES7202_BIAS_ENDITHER |
+					FIELD_PREP(ES7202_BIAS_VMIDSEL, 3) },
+
+		/* VREFGEN on; 3.3 V also drops MODTOP reset */
+		{ ES7202_ANALOG_EN,	is_1v8 ?
+					(ES7202_ANALOG_EN_MODTOP1_RST |
+					 ES7202_ANALOG_EN_MODTOP2_RST |
+					 ES7202_ANALOG_EN_PDN_MOD1 |
+					 ES7202_ANALOG_EN_PDN_MOD2 |
+					 ES7202_ANALOG_EN_PDN_PGA1 |
+					 ES7202_ANALOG_EN_PDN_PGA2) :
+					(ES7202_ANALOG_EN_PDN_MOD1 |
+					 ES7202_ANALOG_EN_PDN_MOD2 |
+					 ES7202_ANALOG_EN_PDN_PGA1 |
+					 ES7202_ANALOG_EN_PDN_PGA2) },
+
+		{ ES7202_ANALOG_EN,	0 },
+		{ ES7202_MOD1_BIAS,	FIELD_PREP(ES7202_MOD1_BIAS_SW0, 5) |
+					FIELD_PREP(ES7202_MOD1_BIAS_SW1, 8) },
+		{ ES7202_CLK_DIV,	FIELD_PREP(ES7202_CLK_DIV_MCLK_DIV, 1) },
+		{ ES7202_T2_VMID,	0x01 },
+		{ ES7202_MISC_CTL,	ES7202_MISC_DSM_DITHER_ON },
+		{ ES7202_RESET,		ES7202_RESET_CSM_ON },
+		{ ES7202_CLK_EN,	ES7202_CLK_ANA_CLK_ON | ES7202_CLK_MCLK_ON },
+		{ ES7202_BIAS_VMID,	FIELD_PREP(ES7202_BIAS_ADCBIAS_SWH1, 3) |
+					ES7202_BIAS_ENDITHER |
+					FIELD_PREP(ES7202_BIAS_VMIDSEL, 2) },
+	};
+	int ret;
+
+	ret = regmap_multi_reg_write(regmap, init_seq, ARRAY_SIZE(init_seq));
+	if (ret)
+		return ret;
+
+	return es7202_mute_pdm(es7202, false);
+}
+
+static int es7202_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+	struct es7202_priv *es7202 = snd_soc_component_get_drvdata(component);
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return 0;
+
+	return es7202_mute_pdm(es7202, mute);
+}
+
+static const struct snd_soc_dai_ops es7202_dai_ops = {
+	.mute_stream = es7202_mute_stream,
+};
+
+static struct snd_soc_dai_driver es7202_dai = {
+	.name = "es7202-hifi",
+	.capture = {
+		.stream_name	= "Capture",
+		.channels_min	= 1,
+		.channels_max	= 2,
+		.rates		= SNDRV_PCM_RATE_8000_96000,
+		.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &es7202_dai_ops,
+};
+
+static int es7202_suspend(struct snd_soc_component *component)
+{
+	struct es7202_priv *es7202 = snd_soc_component_get_drvdata(component);
+
+	return es7202_mute_pdm(es7202, true);
+}
+
+static int es7202_resume(struct snd_soc_component *component)
+{
+	struct es7202_priv *es7202 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	regcache_mark_dirty(es7202->regmap);
+	ret = regcache_sync(es7202->regmap);
+	if (ret)
+		return ret;
+
+	return es7202_mute_pdm(es7202, false);
+}
+
+static const struct snd_soc_component_driver es7202_component_driver = {
+	.controls		= es7202_controls,
+	.num_controls		= ARRAY_SIZE(es7202_controls),
+	.dapm_widgets		= es7202_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(es7202_dapm_widgets),
+	.dapm_routes		= es7202_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(es7202_dapm_routes),
+	.suspend		= es7202_suspend,
+	.resume			= es7202_resume,
+	.idle_bias_on		= 1,
+	.endianness		= 1,
+};
+
+static void es7202_disable_supply(void *data)
+{
+	regulator_disable(data);
+}
+
+static int es7202_i2c_probe(struct i2c_client *i2c)
+{
+	struct device *dev = &i2c->dev;
+	struct es7202_priv *es7202;
+	unsigned int id1, id0, device_id;
+	int ret;
+
+	es7202 = devm_kzalloc(dev, sizeof(*es7202), GFP_KERNEL);
+	if (!es7202)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, es7202);
+
+	es7202->regmap = devm_regmap_init_i2c(i2c, &es7202_regmap);
+	if (IS_ERR(es7202->regmap))
+		return dev_err_probe(dev, PTR_ERR(es7202->regmap),
+				     "failed to init regmap\n");
+
+	es7202->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						     GPIOD_OUT_HIGH);
+	if (IS_ERR(es7202->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(es7202->reset_gpio),
+				     "failed to get reset gpio\n");
+
+	es7202->supply = devm_regulator_get_optional(dev, "vdd");
+	if (IS_ERR(es7202->supply)) {
+		if (PTR_ERR(es7202->supply) != -ENODEV)
+			return dev_err_probe(dev, PTR_ERR(es7202->supply),
+					     "failed to get supply\n");
+
+		es7202->supply = NULL;
+		es7202->supply_uv = ES7202_SUPPLY_3V3_DEFAULT_UV;
+	} else {
+		ret = regulator_enable(es7202->supply);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "failed to enable supply\n");
+
+		ret = devm_add_action_or_reset(dev, es7202_disable_supply,
+					       es7202->supply);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "failed to add supply disable action\n");
+
+		es7202->supply_uv = regulator_get_voltage(es7202->supply);
+		if (es7202->supply_uv < 0)
+			es7202->supply_uv = ES7202_SUPPLY_3V3_DEFAULT_UV;
+	}
+
+	/* take the device out of reset */
+	gpiod_set_value_cansleep(es7202->reset_gpio, 0);
+	usleep_range(1000, 2000);
+
+	/* verify the chip is present by reading its device id */
+	ret = regmap_read(es7202->regmap, ES7202_DEV_ID1, &id1);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to read device id\n");
+	ret = regmap_read(es7202->regmap, ES7202_DEV_ID0, &id0);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to read device id\n");
+
+	device_id = (id1 << 8) | id0;
+	if (device_id != ES7202_DEVICE_ID)
+		return dev_err_probe(dev, -ENODEV,
+				     "unexpected device id 0x%04x, expected 0x%04x\n",
+				     device_id, ES7202_DEVICE_ID);
+
+	ret = es7202_hw_init(es7202);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to init device\n");
+
+	return devm_snd_soc_register_component(dev, &es7202_component_driver,
+					       &es7202_dai, 1);
+}
+
+static void es7202_i2c_remove(struct i2c_client *i2c)
+{
+	struct es7202_priv *es7202 = i2c_get_clientdata(i2c);
+
+	es7202_mute_pdm(es7202, true);
+}
+
+static void es7202_i2c_shutdown(struct i2c_client *i2c)
+{
+	struct es7202_priv *es7202 = i2c_get_clientdata(i2c);
+
+	es7202_mute_pdm(es7202, true);
+}
+
+static const struct of_device_id es7202_of_match[] = {
+	{ .compatible = "everest,es7202" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, es7202_of_match);
+
+static const struct i2c_device_id es7202_i2c_id[] = {
+	{ "es7202" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, es7202_i2c_id);
+
+static struct i2c_driver es7202_i2c_driver = {
+	.driver = {
+		.name		= "es7202",
+		.of_match_table	= of_match_ptr(es7202_of_match),
+	},
+	.probe		= es7202_i2c_probe,
+	.remove		= es7202_i2c_remove,
+	.shutdown	= es7202_i2c_shutdown,
+	.id_table	= es7202_i2c_id,
+};
+module_i2c_driver(es7202_i2c_driver);
+
+MODULE_DESCRIPTION("Everest Semi ES7202 PDM ADC ALSA SoC Codec Driver");
+MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
+MODULE_AUTHOR("Jun Yan <jerrysteve1101@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es7202.h b/sound/soc/codecs/es7202.h
new file mode 100644
index 000000000000..15811b73c20a
--- /dev/null
+++ b/sound/soc/codecs/es7202.h
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright Everest Semiconductor Co., Ltd.
+ *
+ * Author: David Yang <yangxiaohua@everest-semi.com>
+ * Author: Jun Yan <jerrysteve1101@gmail.com>
+ */
+
+#ifndef _ES7202_H
+#define _ES7202_H
+
+#include <linux/bits.h>
+
+/* Register addresses */
+#define ES7202_RESET		0x00
+#define ES7202_SOFT_MODE	0x01
+#define ES7202_CLK_DIV		0x02
+#define ES7202_CLK_EN		0x03
+#define ES7202_T1_VMID		0x04
+#define ES7202_T2_VMID		0x05
+#define ES7202_CHIP_STA		0x06
+#define ES7202_PDM_INF_CTL	0x07
+#define ES7202_MISC_CTL		0x08
+#define ES7202_ANALOG_EN	0x10
+#define ES7202_BIAS_VMID	0x11
+#define ES7202_PGA1_BIAS	0x12
+#define ES7202_PGA2_BIAS	0x13
+#define ES7202_MOD1_BIAS	0x14
+#define ES7202_MOD2_BIAS	0x15
+#define ES7202_VREFP_BIAS	0x16
+#define ES7202_VMMOD_BIAS	0x17
+#define ES7202_MODS_BIAS	0x18
+#define ES7202_ANALOG_LP1	0x19
+#define ES7202_ANALOG_LP2	0x1a
+#define ES7202_ANALOG_MISC1	0x1b
+#define ES7202_ANALOG_MISC2	0x1c
+#define ES7202_PGA1		0x1d
+#define ES7202_PGA2		0x1e
+#define ES7202_DEV_ID1		0xfd
+#define ES7202_DEV_ID0		0xfe
+
+#define ES7202_DEVICE_ID		0x7201
+
+#define ES7202_RESET_RST_REGS		BIT(5)
+#define ES7202_RESET_RST_DIG		BIT(4)
+#define ES7202_RESET_SEQ_DIS		BIT(1)
+#define ES7202_RESET_CSM_ON		BIT(0)
+
+#define ES7202_MODE_SOFT_MODE_SEL	BIT(0)
+
+#define ES7202_CLK_DIV_MCLK_DIV		GENMASK(3, 0)	/* 0/1 = /16 ... 15 = /240 */
+
+#define ES7202_CLK_MCLK_INVERT		BIT(2)
+#define ES7202_CLK_ANA_CLK_ON		BIT(1)
+#define ES7202_CLK_MCLK_ON		BIT(0)
+
+#define ES7202_CHIP_STA_CSM_STATE	GENMASK(5, 4)
+#define ES7202_CHIP_STA_FORCE_CSM	GENMASK(2, 0)
+
+#define ES7202_PDM_NEG_DATA_VALID	BIT(5)
+#define ES7202_PDM_POS_DATA_VALID	BIT(4)
+#define ES7202_PDM_CHN_CROSS		BIT(3)
+#define ES7202_PDM_IF_DLY		BIT(2)
+#define ES7202_PDM_DATA2_MUTE		BIT(1)
+#define ES7202_PDM_DATA1_MUTE		BIT(0)
+#define ES7202_PDM_INF_CTL_MUTE		(ES7202_PDM_DATA2_MUTE | \
+					 ES7202_PDM_DATA1_MUTE)
+
+#define ES7202_MISC_CLKDET_RST_DIS	BIT(2)
+#define ES7202_MISC_DSM_DITHER_ON	BIT(1)
+#define ES7202_MISC_PDN_CLKDET		BIT(0)
+
+#define ES7202_ANALOG_EN_PDN_ANA	BIT(7)
+#define ES7202_ANALOG_EN_PDN_ADCVREFGEN	BIT(6)
+#define ES7202_ANALOG_EN_MODTOP1_RST	BIT(5)
+#define ES7202_ANALOG_EN_MODTOP2_RST	BIT(4)
+#define ES7202_ANALOG_EN_PDN_MOD1	BIT(3)
+#define ES7202_ANALOG_EN_PDN_MOD2	BIT(2)
+#define ES7202_ANALOG_EN_PDN_PGA1	BIT(1)
+#define ES7202_ANALOG_EN_PDN_PGA2	BIT(0)
+
+#define ES7202_BIAS_ADCBIAS_SWH0	GENMASK(7, 6)
+#define ES7202_BIAS_ENDITHER		BIT(5)
+#define ES7202_BIAS_ADCBIAS_SWH1	GENMASK(3, 2)
+#define ES7202_BIAS_VMIDSEL		GENMASK(1, 0)	/* 0 = off, 1 = 50k, 2 = 500k, 3 = 5k */
+
+/* bias levels 0x12-0x18 (SW0 for 1.8 V, SW1 for 3.3 V) */
+#define ES7202_PGA1_BIAS_SW0		GENMASK(7, 4)
+#define ES7202_PGA1_BIAS_SW1		GENMASK(3, 0)
+#define ES7202_PGA2_BIAS_SW0		GENMASK(7, 4)
+#define ES7202_PGA2_BIAS_SW1		GENMASK(3, 0)
+#define ES7202_MOD1_BIAS_SW0		GENMASK(7, 4)
+#define ES7202_MOD1_BIAS_SW1		GENMASK(3, 0)
+#define ES7202_MOD2_BIAS_SW0		GENMASK(7, 4)
+#define ES7202_MOD2_BIAS_SW1		GENMASK(3, 0)
+#define ES7202_VREFP_BIAS_SW0		GENMASK(7, 4)
+#define ES7202_VREFP_BIAS_SW1		GENMASK(3, 0)
+#define ES7202_VMMOD_BIAS_SW0		GENMASK(7, 4)
+#define ES7202_VMMOD_BIAS_SW1		GENMASK(3, 0)
+#define ES7202_MODS_BIAS_SW0		GENMASK(7, 4)
+#define ES7202_MODS_BIAS_SW1		GENMASK(3, 0)
+
+#define ES7202_LP1_LP_VRP		BIT(7)
+#define ES7202_LP1_LP_VRPOUT		BIT(6)
+#define ES7202_LP1_LP_VMMOD1		BIT(5)
+#define ES7202_LP1_LP_VMMOD2		BIT(4)
+#define ES7202_LP1_LP_MODS1		BIT(3)
+#define ES7202_LP1_LP_MODS2		BIT(2)
+#define ES7202_LP1_LP_MODI1		BIT(1)
+#define ES7202_LP1_LP_MODI2		BIT(0)
+
+#define ES7202_LP2_LP_PGA1		BIT(5)
+#define ES7202_LP2_LP_PGA2		BIT(4)
+#define ES7202_LP2_PDN_DETCT		BIT(3)
+
+#define ES7202_ANALOG_MISC1_OFFSETSEL1	BIT(6)
+#define ES7202_ANALOG_MISC1_OFFSETSEL0	BIT(5)
+#define ES7202_ANALOG_MISC1_SUPPLYSEL	BIT(4)	/* 0 = 1.8 V, 1 = 3.3 V */
+#define ES7202_ANALOG_MISC1_DITHERSEL	GENMASK(2, 0)
+
+#define ES7202_ANALOG_MISC2_VX2OFF_SW0	BIT(7)
+#define ES7202_ANALOG_MISC2_VX1SEL_SW0	BIT(6)
+#define ES7202_ANALOG_MISC2_VMIDLOW_SW0	GENMASK(5, 4)
+#define ES7202_ANALOG_MISC2_VX2OFF_SW1	BIT(3)
+#define ES7202_ANALOG_MISC2_VX1SEL_SW1	BIT(2)
+#define ES7202_ANALOG_MISC2_VMIDLOW_SW1	GENMASK(1, 0)
+
+#define ES7202_PGA_SELMIC1		BIT(4)
+#define ES7202_PGA_MIC1_GAIN		GENMASK(3, 0)
+#define ES7202_PGA_SELMIC2		BIT(4)
+#define ES7202_PGA_MIC2_GAIN		GENMASK(3, 0)
+
+#endif
-- 
2.56.0


WARNING: multiple messages have this Message-ID (diff)
From: Jun Yan <jerrysteve1101@gmail.com>
To: lgirdwood@gmail.com, broonie@kernel.org, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org, perex@perex.cz,
	tiwai@suse.com, heiko@sntech.de
Cc: linux-sound@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-rockchip@lists.infradead.org,
	Jun Yan <jerrysteve1101@gmail.com>
Subject: [PATCH 2/2] ASoC: codecs: add support for Everest ES7202 PDM ADC
Date: Tue, 20 Oct 2026 22:31:32 +0800	[thread overview]
Message-ID: <20261020143135.623897-3-jerrysteve1101@gmail.com> (raw)
In-Reply-To: <20261020143135.623897-1-jerrysteve1101@gmail.com>

Add support for the Everest ES7202, a 2-channel PDM analog-to-digital
converter controlled over I2C. The device outputs PDM data to the SoC
PDM controller and is configured through registers for supply voltage,
analog front-end and per-channel PGA gain.

Based on the Rockchip BSP driver[1] by Binyuan Lan <lby@rock-chips.com>
(committed by Tao Huang <huangtao@rock-chips.com>), originally written
by David Yang <yangxiaohua@everest-semi.com>.

[1] https://github.com/rockchip-linux/kernel/blob/develop-6.1/sound/soc/codecs/es7202.c

Link: https://archive.org/details/es-7202-ds
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
 sound/soc/codecs/Kconfig  |  10 +
 sound/soc/codecs/Makefile |   2 +
 sound/soc/codecs/es7202.c | 372 ++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/es7202.h | 133 ++++++++++++++
 4 files changed, 517 insertions(+)
 create mode 100644 sound/soc/codecs/es7202.c
 create mode 100644 sound/soc/codecs/es7202.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index ba59dabeeccd..c1eeebd12cf0 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1274,6 +1274,16 @@ config SND_SOC_HDMI_CODEC
 config SND_SOC_ES7134
 	tristate "Everest Semi ES7134 CODEC"
 
+config SND_SOC_ES7202
+	tristate "Everest Semi ES7202 CODEC"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  Enable support for the Everest Semiconductor ES7202, a 2-channel
+	  PDM analog-to-digital converter controlled over I2C. The device
+	  outputs PDM data to a SoC PDM controller and is configured through
+	  registers for supply voltage, analog front-end and PGA gain.
+
 config SND_SOC_ES7241
 	tristate "Everest Semi ES7241 CODEC"
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 3826f9e4fce8..2a56fad9073a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -129,6 +129,7 @@ snd-soc-da732x-y := da732x.o
 snd-soc-da9055-y := da9055.o
 snd-soc-dmic-y := dmic.o
 snd-soc-es7134-y := es7134.o
+snd-soc-es7202-y := es7202.o
 snd-soc-es7241-y := es7241.o
 snd-soc-es83xx-dsm-common-y := es83xx-dsm-common.o
 snd-soc-es8311-y := es8311.o
@@ -577,6 +578,7 @@ obj-$(CONFIG_SND_SOC_DA732X)	+= snd-soc-da732x.o
 obj-$(CONFIG_SND_SOC_DA9055)	+= snd-soc-da9055.o
 obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_ES7134)	+= snd-soc-es7134.o
+obj-$(CONFIG_SND_SOC_ES7202)	+= snd-soc-es7202.o
 obj-$(CONFIG_SND_SOC_ES7241)	+= snd-soc-es7241.o
 obj-$(CONFIG_SND_SOC_ES83XX_DSM_COMMON)    += snd-soc-es83xx-dsm-common.o
 obj-$(CONFIG_SND_SOC_ES8311)    += snd-soc-es8311.o
diff --git a/sound/soc/codecs/es7202.c b/sound/soc/codecs/es7202.c
new file mode 100644
index 000000000000..c30b0123c91f
--- /dev/null
+++ b/sound/soc/codecs/es7202.c
@@ -0,0 +1,372 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright Everest Semiconductor Co., Ltd.
+ *
+ * Author: David Yang <yangxiaohua@everest-semi.com>
+ * Author: Jun Yan <jerrysteve1101@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "es7202.h"
+
+/*
+ * The main supply voltage selects the analog front-end configuration:
+ * below this threshold the device is configured for 1.8 V, otherwise 3.3 V.
+ */
+#define ES7202_SUPPLY_1V8_MAX_UV	1980000
+#define ES7202_SUPPLY_3V3_DEFAULT_UV	3300000
+
+struct es7202_priv {
+	struct regmap *regmap;
+	struct regulator *supply;
+	struct gpio_desc *reset_gpio;
+	unsigned int supply_uv;
+};
+
+static bool es7202_volatile_reg(struct device *dev, unsigned int reg)
+{
+	/* status and device-id registers are read-only, never cached */
+	return reg == ES7202_CHIP_STA ||
+	       reg == ES7202_DEV_ID1 ||
+	       reg == ES7202_DEV_ID0;
+}
+
+static const struct reg_default es7202_reg_defaults[] = {
+	{ ES7202_RESET,		0x10 },
+	{ ES7202_SOFT_MODE,	0x00 },
+	{ ES7202_CLK_DIV,	0x04 },
+	{ ES7202_CLK_EN,	0x00 },
+	{ ES7202_T1_VMID,	0x01 },
+	{ ES7202_T2_VMID,	0x18 },
+	{ ES7202_PDM_INF_CTL,	0x30 },
+	{ ES7202_MISC_CTL,	0x02 },
+	{ ES7202_ANALOG_EN,	0xff },
+	{ ES7202_BIAS_VMID,	0x0c },
+	{ ES7202_PGA1_BIAS,	0x55 },
+	{ ES7202_PGA2_BIAS,	0x55 },
+	{ ES7202_MOD1_BIAS,	0x8c },
+	{ ES7202_MOD2_BIAS,	0x33 },
+	{ ES7202_VREFP_BIAS,	0x33 },
+	{ ES7202_VMMOD_BIAS,	0x33 },
+	{ ES7202_MODS_BIAS,	0x44 },
+	{ ES7202_ANALOG_LP1,	0x00 },
+	{ ES7202_ANALOG_LP2,	0x00 },
+	{ ES7202_ANALOG_MISC1,	0x00 },
+	{ ES7202_ANALOG_MISC2,	0xf8 },
+	{ ES7202_PGA1,		0x18 },
+	{ ES7202_PGA2,		0x18 },
+};
+
+static const struct regmap_config es7202_regmap = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= ES7202_DEV_ID0,
+	.reg_defaults	= es7202_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(es7202_reg_defaults),
+	.volatile_reg	= es7202_volatile_reg,
+	.cache_type	= REGCACHE_MAPLE,
+};
+
+/*
+ * PGA gain per the datasheet: code 0 is 0 dB, codes 1..10 step +3 dB from
+ * 2.25 dB, and codes 11 and 12 are 30.75 dB and 32.25 dB respectively.  As
+ * the steps are not uniform, a linear TLV (the vendor driver's
+ * DECLARE_TLV_DB_SCALE(mic_boost_tlv, 0, 300, 0)) would misreport the gain,
+ * so use a piecewise range matching the datasheet instead.
+ */
+static const DECLARE_TLV_DB_RANGE(mic_boost_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 10, TLV_DB_SCALE_ITEM(225, 300, 0),
+	11, 11, TLV_DB_SCALE_ITEM(3075, 0, 0),
+	12, 12, TLV_DB_SCALE_ITEM(3225, 0, 0),
+);
+
+static const struct snd_kcontrol_new es7202_controls[] = {
+	SOC_SINGLE_TLV("PGA1 Capture Volume", ES7202_PGA1, 0, 0x0c, 0,
+		       mic_boost_tlv),
+	SOC_SINGLE_TLV("PGA2 Capture Volume", ES7202_PGA2, 0, 0x0c, 0,
+		       mic_boost_tlv),
+};
+
+static const struct snd_soc_dapm_widget es7202_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route es7202_dapm_routes[] = {
+	{ "ADC", NULL, "MIC1" },
+	{ "ADC", NULL, "MIC2" },
+};
+
+static int es7202_mute_pdm(struct es7202_priv *es7202, bool mute)
+{
+	return regmap_update_bits(es7202->regmap, ES7202_PDM_INF_CTL,
+				  ES7202_PDM_INF_CTL_MUTE,
+				  mute ? ES7202_PDM_INF_CTL_MUTE : 0);
+}
+
+static int es7202_hw_init(struct es7202_priv *es7202)
+{
+	struct regmap *regmap = es7202->regmap;
+	bool is_1v8 = es7202->supply_uv > 0 &&
+		      es7202->supply_uv <= ES7202_SUPPLY_1V8_MAX_UV;
+	/*
+	 * Power-up sequence from the vendor driver.
+	 * The analog front-end is configured for the actual supply voltage
+	 * (1.8 V vs 3.3 V) and the analog blocks are ramped out of
+	 * power-down in stages.
+	 */
+	const struct reg_sequence init_seq[] = {
+		{ ES7202_SOFT_MODE,	ES7202_MODE_SOFT_MODE_SEL },
+		{ ES7202_ANALOG_MISC1,	ES7202_ANALOG_MISC1_OFFSETSEL1 |
+					(is_1v8 ? 0 : ES7202_ANALOG_MISC1_SUPPLYSEL) },
+
+		/* 30.75 dB gain */
+		{ ES7202_PGA1,		ES7202_PGA_SELMIC1 |
+					FIELD_PREP(ES7202_PGA_MIC1_GAIN, 11) },
+		{ ES7202_PGA2,		ES7202_PGA_SELMIC2 |
+					FIELD_PREP(ES7202_PGA_MIC2_GAIN, 11) },
+
+		/* analog on, rest powered down */
+		{ ES7202_ANALOG_EN,	ES7202_ANALOG_EN_PDN_ADCVREFGEN |
+					ES7202_ANALOG_EN_MODTOP1_RST |
+					ES7202_ANALOG_EN_MODTOP2_RST |
+					ES7202_ANALOG_EN_PDN_MOD1 |
+					ES7202_ANALOG_EN_PDN_MOD2 |
+					ES7202_ANALOG_EN_PDN_PGA1 |
+					ES7202_ANALOG_EN_PDN_PGA2 },
+
+		{ ES7202_BIAS_VMID,	FIELD_PREP(ES7202_BIAS_ADCBIAS_SWH1, 3) |
+					ES7202_BIAS_ENDITHER |
+					FIELD_PREP(ES7202_BIAS_VMIDSEL, 3) },
+
+		/* VREFGEN on; 3.3 V also drops MODTOP reset */
+		{ ES7202_ANALOG_EN,	is_1v8 ?
+					(ES7202_ANALOG_EN_MODTOP1_RST |
+					 ES7202_ANALOG_EN_MODTOP2_RST |
+					 ES7202_ANALOG_EN_PDN_MOD1 |
+					 ES7202_ANALOG_EN_PDN_MOD2 |
+					 ES7202_ANALOG_EN_PDN_PGA1 |
+					 ES7202_ANALOG_EN_PDN_PGA2) :
+					(ES7202_ANALOG_EN_PDN_MOD1 |
+					 ES7202_ANALOG_EN_PDN_MOD2 |
+					 ES7202_ANALOG_EN_PDN_PGA1 |
+					 ES7202_ANALOG_EN_PDN_PGA2) },
+
+		{ ES7202_ANALOG_EN,	0 },
+		{ ES7202_MOD1_BIAS,	FIELD_PREP(ES7202_MOD1_BIAS_SW0, 5) |
+					FIELD_PREP(ES7202_MOD1_BIAS_SW1, 8) },
+		{ ES7202_CLK_DIV,	FIELD_PREP(ES7202_CLK_DIV_MCLK_DIV, 1) },
+		{ ES7202_T2_VMID,	0x01 },
+		{ ES7202_MISC_CTL,	ES7202_MISC_DSM_DITHER_ON },
+		{ ES7202_RESET,		ES7202_RESET_CSM_ON },
+		{ ES7202_CLK_EN,	ES7202_CLK_ANA_CLK_ON | ES7202_CLK_MCLK_ON },
+		{ ES7202_BIAS_VMID,	FIELD_PREP(ES7202_BIAS_ADCBIAS_SWH1, 3) |
+					ES7202_BIAS_ENDITHER |
+					FIELD_PREP(ES7202_BIAS_VMIDSEL, 2) },
+	};
+	int ret;
+
+	ret = regmap_multi_reg_write(regmap, init_seq, ARRAY_SIZE(init_seq));
+	if (ret)
+		return ret;
+
+	return es7202_mute_pdm(es7202, false);
+}
+
+static int es7202_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+	struct es7202_priv *es7202 = snd_soc_component_get_drvdata(component);
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return 0;
+
+	return es7202_mute_pdm(es7202, mute);
+}
+
+static const struct snd_soc_dai_ops es7202_dai_ops = {
+	.mute_stream = es7202_mute_stream,
+};
+
+static struct snd_soc_dai_driver es7202_dai = {
+	.name = "es7202-hifi",
+	.capture = {
+		.stream_name	= "Capture",
+		.channels_min	= 1,
+		.channels_max	= 2,
+		.rates		= SNDRV_PCM_RATE_8000_96000,
+		.formats	= SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &es7202_dai_ops,
+};
+
+static int es7202_suspend(struct snd_soc_component *component)
+{
+	struct es7202_priv *es7202 = snd_soc_component_get_drvdata(component);
+
+	return es7202_mute_pdm(es7202, true);
+}
+
+static int es7202_resume(struct snd_soc_component *component)
+{
+	struct es7202_priv *es7202 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	regcache_mark_dirty(es7202->regmap);
+	ret = regcache_sync(es7202->regmap);
+	if (ret)
+		return ret;
+
+	return es7202_mute_pdm(es7202, false);
+}
+
+static const struct snd_soc_component_driver es7202_component_driver = {
+	.controls		= es7202_controls,
+	.num_controls		= ARRAY_SIZE(es7202_controls),
+	.dapm_widgets		= es7202_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(es7202_dapm_widgets),
+	.dapm_routes		= es7202_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(es7202_dapm_routes),
+	.suspend		= es7202_suspend,
+	.resume			= es7202_resume,
+	.idle_bias_on		= 1,
+	.endianness		= 1,
+};
+
+static void es7202_disable_supply(void *data)
+{
+	regulator_disable(data);
+}
+
+static int es7202_i2c_probe(struct i2c_client *i2c)
+{
+	struct device *dev = &i2c->dev;
+	struct es7202_priv *es7202;
+	unsigned int id1, id0, device_id;
+	int ret;
+
+	es7202 = devm_kzalloc(dev, sizeof(*es7202), GFP_KERNEL);
+	if (!es7202)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, es7202);
+
+	es7202->regmap = devm_regmap_init_i2c(i2c, &es7202_regmap);
+	if (IS_ERR(es7202->regmap))
+		return dev_err_probe(dev, PTR_ERR(es7202->regmap),
+				     "failed to init regmap\n");
+
+	es7202->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						     GPIOD_OUT_HIGH);
+	if (IS_ERR(es7202->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(es7202->reset_gpio),
+				     "failed to get reset gpio\n");
+
+	es7202->supply = devm_regulator_get_optional(dev, "vdd");
+	if (IS_ERR(es7202->supply)) {
+		if (PTR_ERR(es7202->supply) != -ENODEV)
+			return dev_err_probe(dev, PTR_ERR(es7202->supply),
+					     "failed to get supply\n");
+
+		es7202->supply = NULL;
+		es7202->supply_uv = ES7202_SUPPLY_3V3_DEFAULT_UV;
+	} else {
+		ret = regulator_enable(es7202->supply);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "failed to enable supply\n");
+
+		ret = devm_add_action_or_reset(dev, es7202_disable_supply,
+					       es7202->supply);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "failed to add supply disable action\n");
+
+		es7202->supply_uv = regulator_get_voltage(es7202->supply);
+		if (es7202->supply_uv < 0)
+			es7202->supply_uv = ES7202_SUPPLY_3V3_DEFAULT_UV;
+	}
+
+	/* take the device out of reset */
+	gpiod_set_value_cansleep(es7202->reset_gpio, 0);
+	usleep_range(1000, 2000);
+
+	/* verify the chip is present by reading its device id */
+	ret = regmap_read(es7202->regmap, ES7202_DEV_ID1, &id1);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to read device id\n");
+	ret = regmap_read(es7202->regmap, ES7202_DEV_ID0, &id0);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to read device id\n");
+
+	device_id = (id1 << 8) | id0;
+	if (device_id != ES7202_DEVICE_ID)
+		return dev_err_probe(dev, -ENODEV,
+				     "unexpected device id 0x%04x, expected 0x%04x\n",
+				     device_id, ES7202_DEVICE_ID);
+
+	ret = es7202_hw_init(es7202);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to init device\n");
+
+	return devm_snd_soc_register_component(dev, &es7202_component_driver,
+					       &es7202_dai, 1);
+}
+
+static void es7202_i2c_remove(struct i2c_client *i2c)
+{
+	struct es7202_priv *es7202 = i2c_get_clientdata(i2c);
+
+	es7202_mute_pdm(es7202, true);
+}
+
+static void es7202_i2c_shutdown(struct i2c_client *i2c)
+{
+	struct es7202_priv *es7202 = i2c_get_clientdata(i2c);
+
+	es7202_mute_pdm(es7202, true);
+}
+
+static const struct of_device_id es7202_of_match[] = {
+	{ .compatible = "everest,es7202" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, es7202_of_match);
+
+static const struct i2c_device_id es7202_i2c_id[] = {
+	{ "es7202" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, es7202_i2c_id);
+
+static struct i2c_driver es7202_i2c_driver = {
+	.driver = {
+		.name		= "es7202",
+		.of_match_table	= of_match_ptr(es7202_of_match),
+	},
+	.probe		= es7202_i2c_probe,
+	.remove		= es7202_i2c_remove,
+	.shutdown	= es7202_i2c_shutdown,
+	.id_table	= es7202_i2c_id,
+};
+module_i2c_driver(es7202_i2c_driver);
+
+MODULE_DESCRIPTION("Everest Semi ES7202 PDM ADC ALSA SoC Codec Driver");
+MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
+MODULE_AUTHOR("Jun Yan <jerrysteve1101@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es7202.h b/sound/soc/codecs/es7202.h
new file mode 100644
index 000000000000..15811b73c20a
--- /dev/null
+++ b/sound/soc/codecs/es7202.h
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright Everest Semiconductor Co., Ltd.
+ *
+ * Author: David Yang <yangxiaohua@everest-semi.com>
+ * Author: Jun Yan <jerrysteve1101@gmail.com>
+ */
+
+#ifndef _ES7202_H
+#define _ES7202_H
+
+#include <linux/bits.h>
+
+/* Register addresses */
+#define ES7202_RESET		0x00
+#define ES7202_SOFT_MODE	0x01
+#define ES7202_CLK_DIV		0x02
+#define ES7202_CLK_EN		0x03
+#define ES7202_T1_VMID		0x04
+#define ES7202_T2_VMID		0x05
+#define ES7202_CHIP_STA		0x06
+#define ES7202_PDM_INF_CTL	0x07
+#define ES7202_MISC_CTL		0x08
+#define ES7202_ANALOG_EN	0x10
+#define ES7202_BIAS_VMID	0x11
+#define ES7202_PGA1_BIAS	0x12
+#define ES7202_PGA2_BIAS	0x13
+#define ES7202_MOD1_BIAS	0x14
+#define ES7202_MOD2_BIAS	0x15
+#define ES7202_VREFP_BIAS	0x16
+#define ES7202_VMMOD_BIAS	0x17
+#define ES7202_MODS_BIAS	0x18
+#define ES7202_ANALOG_LP1	0x19
+#define ES7202_ANALOG_LP2	0x1a
+#define ES7202_ANALOG_MISC1	0x1b
+#define ES7202_ANALOG_MISC2	0x1c
+#define ES7202_PGA1		0x1d
+#define ES7202_PGA2		0x1e
+#define ES7202_DEV_ID1		0xfd
+#define ES7202_DEV_ID0		0xfe
+
+#define ES7202_DEVICE_ID		0x7201
+
+#define ES7202_RESET_RST_REGS		BIT(5)
+#define ES7202_RESET_RST_DIG		BIT(4)
+#define ES7202_RESET_SEQ_DIS		BIT(1)
+#define ES7202_RESET_CSM_ON		BIT(0)
+
+#define ES7202_MODE_SOFT_MODE_SEL	BIT(0)
+
+#define ES7202_CLK_DIV_MCLK_DIV		GENMASK(3, 0)	/* 0/1 = /16 ... 15 = /240 */
+
+#define ES7202_CLK_MCLK_INVERT		BIT(2)
+#define ES7202_CLK_ANA_CLK_ON		BIT(1)
+#define ES7202_CLK_MCLK_ON		BIT(0)
+
+#define ES7202_CHIP_STA_CSM_STATE	GENMASK(5, 4)
+#define ES7202_CHIP_STA_FORCE_CSM	GENMASK(2, 0)
+
+#define ES7202_PDM_NEG_DATA_VALID	BIT(5)
+#define ES7202_PDM_POS_DATA_VALID	BIT(4)
+#define ES7202_PDM_CHN_CROSS		BIT(3)
+#define ES7202_PDM_IF_DLY		BIT(2)
+#define ES7202_PDM_DATA2_MUTE		BIT(1)
+#define ES7202_PDM_DATA1_MUTE		BIT(0)
+#define ES7202_PDM_INF_CTL_MUTE		(ES7202_PDM_DATA2_MUTE | \
+					 ES7202_PDM_DATA1_MUTE)
+
+#define ES7202_MISC_CLKDET_RST_DIS	BIT(2)
+#define ES7202_MISC_DSM_DITHER_ON	BIT(1)
+#define ES7202_MISC_PDN_CLKDET		BIT(0)
+
+#define ES7202_ANALOG_EN_PDN_ANA	BIT(7)
+#define ES7202_ANALOG_EN_PDN_ADCVREFGEN	BIT(6)
+#define ES7202_ANALOG_EN_MODTOP1_RST	BIT(5)
+#define ES7202_ANALOG_EN_MODTOP2_RST	BIT(4)
+#define ES7202_ANALOG_EN_PDN_MOD1	BIT(3)
+#define ES7202_ANALOG_EN_PDN_MOD2	BIT(2)
+#define ES7202_ANALOG_EN_PDN_PGA1	BIT(1)
+#define ES7202_ANALOG_EN_PDN_PGA2	BIT(0)
+
+#define ES7202_BIAS_ADCBIAS_SWH0	GENMASK(7, 6)
+#define ES7202_BIAS_ENDITHER		BIT(5)
+#define ES7202_BIAS_ADCBIAS_SWH1	GENMASK(3, 2)
+#define ES7202_BIAS_VMIDSEL		GENMASK(1, 0)	/* 0 = off, 1 = 50k, 2 = 500k, 3 = 5k */
+
+/* bias levels 0x12-0x18 (SW0 for 1.8 V, SW1 for 3.3 V) */
+#define ES7202_PGA1_BIAS_SW0		GENMASK(7, 4)
+#define ES7202_PGA1_BIAS_SW1		GENMASK(3, 0)
+#define ES7202_PGA2_BIAS_SW0		GENMASK(7, 4)
+#define ES7202_PGA2_BIAS_SW1		GENMASK(3, 0)
+#define ES7202_MOD1_BIAS_SW0		GENMASK(7, 4)
+#define ES7202_MOD1_BIAS_SW1		GENMASK(3, 0)
+#define ES7202_MOD2_BIAS_SW0		GENMASK(7, 4)
+#define ES7202_MOD2_BIAS_SW1		GENMASK(3, 0)
+#define ES7202_VREFP_BIAS_SW0		GENMASK(7, 4)
+#define ES7202_VREFP_BIAS_SW1		GENMASK(3, 0)
+#define ES7202_VMMOD_BIAS_SW0		GENMASK(7, 4)
+#define ES7202_VMMOD_BIAS_SW1		GENMASK(3, 0)
+#define ES7202_MODS_BIAS_SW0		GENMASK(7, 4)
+#define ES7202_MODS_BIAS_SW1		GENMASK(3, 0)
+
+#define ES7202_LP1_LP_VRP		BIT(7)
+#define ES7202_LP1_LP_VRPOUT		BIT(6)
+#define ES7202_LP1_LP_VMMOD1		BIT(5)
+#define ES7202_LP1_LP_VMMOD2		BIT(4)
+#define ES7202_LP1_LP_MODS1		BIT(3)
+#define ES7202_LP1_LP_MODS2		BIT(2)
+#define ES7202_LP1_LP_MODI1		BIT(1)
+#define ES7202_LP1_LP_MODI2		BIT(0)
+
+#define ES7202_LP2_LP_PGA1		BIT(5)
+#define ES7202_LP2_LP_PGA2		BIT(4)
+#define ES7202_LP2_PDN_DETCT		BIT(3)
+
+#define ES7202_ANALOG_MISC1_OFFSETSEL1	BIT(6)
+#define ES7202_ANALOG_MISC1_OFFSETSEL0	BIT(5)
+#define ES7202_ANALOG_MISC1_SUPPLYSEL	BIT(4)	/* 0 = 1.8 V, 1 = 3.3 V */
+#define ES7202_ANALOG_MISC1_DITHERSEL	GENMASK(2, 0)
+
+#define ES7202_ANALOG_MISC2_VX2OFF_SW0	BIT(7)
+#define ES7202_ANALOG_MISC2_VX1SEL_SW0	BIT(6)
+#define ES7202_ANALOG_MISC2_VMIDLOW_SW0	GENMASK(5, 4)
+#define ES7202_ANALOG_MISC2_VX2OFF_SW1	BIT(3)
+#define ES7202_ANALOG_MISC2_VX1SEL_SW1	BIT(2)
+#define ES7202_ANALOG_MISC2_VMIDLOW_SW1	GENMASK(1, 0)
+
+#define ES7202_PGA_SELMIC1		BIT(4)
+#define ES7202_PGA_MIC1_GAIN		GENMASK(3, 0)
+#define ES7202_PGA_SELMIC2		BIT(4)
+#define ES7202_PGA_MIC2_GAIN		GENMASK(3, 0)
+
+#endif
-- 
2.56.0


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

  parent reply	other threads:[~2026-10-20 14:31 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-20 14:31 [PATCH 0/2] ASoC: codecs: Add Everest ES7202 support Jun Yan
2026-10-20 14:31 ` Jun Yan
2026-10-20 14:31 ` [PATCH 1/2] dt-bindings: sound: add Everest ES7202 Jun Yan
2026-10-20 14:31   ` Jun Yan
2026-10-20 14:31 ` Jun Yan [this message]
2026-10-20 14:31   ` [PATCH 2/2] ASoC: codecs: add support for Everest ES7202 PDM ADC Jun Yan
2026-10-20 14:49   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261020143135.623897-3-jerrysteve1101@gmail.com \
    --to=jerrysteve1101@gmail.com \
    --cc=broonie@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=heiko@sntech.de \
    --cc=krzk+dt@kernel.org \
    --cc=lgirdwood@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rockchip@lists.infradead.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=perex@perex.cz \
    --cc=robh@kernel.org \
    --cc=tiwai@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.