lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240709104117.33431-3-ivprusov@salutedevices.com>
Date: Tue, 9 Jul 2024 13:41:17 +0300
From: Igor Prusov <ivprusov@...utedevices.com>
To: Liam Girdwood <lgirdwood@...il.com>, Mark Brown <broonie@...nel.org>, Rob
 Herring <robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>, Conor
 Dooley <conor+dt@...nel.org>, Jaroslav Kysela <perex@...ex.cz>, Takashi Iwai
	<tiwai@...e.com>, Igor Prusov <ivprusov@...utedevices.com>
CC: <prusovigor@...il.com>, <kernel@...utedevices.com>, David Yang
	<yangxiaohua@...rest-semi.com>, Viktor Prutyanov
	<vvprutyanov@...rdevices.ru>, <linux-sound@...r.kernel.org>,
	<devicetree@...r.kernel.org>, <linux-kernel@...r.kernel.org>
Subject: [PATCH 2/2] ASoC: codecs: add ES7243E ADC driver

Add support for Everest Semi es7243e, which is a 24 bit, 8 to 48 kHz
stereo audio ADC with I2C control and I2S output.

Datasheet: https://www.pawpaw.cn/media/documents/2022-04/ES7243E_DS_pawpaw%E6%9C%A8%E7%93%9C%E7%A7%91%E6%8A%80.pdf

Signed-off-by: David Yang <yangxiaohua@...rest-semi.com>
Signed-off-by: Igor Prusov <ivprusov@...utedevices.com>
Signed-off-by: Viktor Prutyanov <vvprutyanov@...rdevices.ru>
---
 sound/soc/codecs/Kconfig   |   3 +
 sound/soc/codecs/Makefile  |   2 +
 sound/soc/codecs/es7243e.c | 676 +++++++++++++++++++++++++++++++++++++
 3 files changed, 681 insertions(+)
 create mode 100644 sound/soc/codecs/es7243e.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 4afc43d3f71f..bfc21073ea24 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1097,6 +1097,9 @@ config SND_SOC_ES7134
 config SND_SOC_ES7241
 	tristate "Everest Semi ES7241 CODEC"
 
+config SND_SOC_ES7243E
+	tristate "Everest Semi ES7243E CODEC"
+
 config SND_SOC_ES83XX_DSM_COMMON
 	depends on ACPI
 	tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index b4df22186e25..9469903662f8 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -118,6 +118,7 @@ snd-soc-da9055-y := da9055.o
 snd-soc-dmic-y := dmic.o
 snd-soc-es7134-y := es7134.o
 snd-soc-es7241-y := es7241.o
+snd-soc-es7243-y := es7243.o
 snd-soc-es83xx-dsm-common-y := es83xx-dsm-common.o
 snd-soc-es8316-y := es8316.o
 snd-soc-es8326-y := es8326.o
@@ -515,6 +516,7 @@ 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_ES7241)	+= snd-soc-es7241.o
+obj-$(CONFIG_SND_SOC_ES7243E)	+= snd-soc-es7243e.o
 obj-$(CONFIG_SND_SOC_ES83XX_DSM_COMMON)    += snd-soc-es83xx-dsm-common.o
 obj-$(CONFIG_SND_SOC_ES8316)    += snd-soc-es8316.o
 obj-$(CONFIG_SND_SOC_ES8326)    += snd-soc-es8326.o
diff --git a/sound/soc/codecs/es7243e.c b/sound/soc/codecs/es7243e.c
new file mode 100644
index 000000000000..be877d980cec
--- /dev/null
+++ b/sound/soc/codecs/es7243e.c
@@ -0,0 +1,676 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/**
+ * es7243e.c - ASoC Everest Semiconductor ES7243E audio ADC driver
+ *
+ * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
+ *
+ * Authors: Viktor Prutyanov <vvprutyanov@...rdevices.ru>
+ *	    Igor Prusov <ivprusov@...utedevices.com>
+ *
+ * Based on ES7243E driver by David Yang <yangxiaohua@...rest-semi.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <linux/regmap.h>
+
+#define ES7243E_RESET			0x00
+#define ES7243E_CLK1			0x01
+#define  ES7243E_CLK1_ANA_ON		BIT(1)
+#define  ES7243E_CLK1_ADC_ON		BIT(3)
+#define ES7243E_CLK2			0x02
+#define  ES7243E_CLK2_BCLK_INV		BIT(0)
+#define ES7243E_ADC_OSR			0x03
+#define ES7243E_MCLK_PRE		0x04
+#define ES7243E_CF_DSP_DIV		0x05
+#define ES7243E_BCLK_DIV		0x06
+#define ES7243E_CLK7			0x07
+#define  ES7243E_CLK7_LRCK_DIV_HI	GENMASK(3, 0)
+#define ES7243E_LRCK_DIV		0x08
+#define ES7243E_S1_SEL			0x09
+#define ES7243E_S3_SEL			0x0A
+#define ES7243E_SDP			0x0B
+#define  ES7243E_SDP_MUTE		GENMASK(7, 6)
+#define  ES7243E_SDP_LRP		BIT(5)
+#define  ES7243E_SDP_WL			GENMASK(4, 2)
+#define  ES7243E_SDP_FMT		GENMASK(1, 0)
+#define ES7243E_TDM			0x0B
+#define ES7243E_ADCCTL1			0x0D
+#define  ES7243E_ADCCTL1_SCALE		GENMASK(2, 0)
+#define ES7243E_ADC_VOL			0x0E
+#define ES7243E_ADCCTL2			0x0F
+#define ES7243E_AUTOMUTE1		0x10
+#define ES7243E_AUTOMUTE2		0x11
+#define ES7243E_AUTOMUTE3		0x12
+#define ES7243E_AUTOMUTE4		0x13
+#define ES7243E_ADC_HPF1		0x14
+#define ES7243E_ADC_HPF2		0x15
+#define ES7243E_PDN			0x16
+#define  ES7243E_PDN_ANA		BIT(7)
+#define  ES7243E_PDN_BIAS		BIT(6)
+#define  ES7243E_PDN_MOD1_RST		BIT(5)
+#define  ES7243E_PDN_MOD2_RST		BIT(4)
+#define  ES7243E_PDN_MOD1		BIT(3)
+#define  ES7243E_PDN_MOD2		BIT(2)
+#define  ES7243E_PDN_PGA1		BIT(1)
+#define  ES7243E_PDN_PGA2		BIT(0)
+#define ES7243E_VMIDSEL			0x17
+#define ES7243E_ADC_BIAS_0x18		0x18
+#define ES7243E_PGA_BIAS		0x19
+#define ES7243E_ADC_BIAS_0x1A		0x1A
+#define ES7243E_ADC_MICBIAS		0x1B
+#define ES7243E_ADC_VRPBIAS		0x1C
+#define ES7243E_ADC_LP			0x1D
+#define ES7243E_ADC_PGA_LP		0x1E
+#define ES7243E_ADC_VMID		0x1F
+#define ES7243E_PGA1			0x20
+#define	 ES7243E_PGA1_EN		BIT(4)
+#define ES7243E_PGA2			0x21
+#define	 ES7243E_PGA2_EN		BIT(4)
+#define ES7243E_DLL_PWN			0xF9
+#define ES7243E_I2C_CONFIG		0xFC
+#define ES7243E_FLAG			0xFA
+#define ES7243E_CHIP_ID1		0xFD
+#define ES7243E_CHIP_ID2		0xFE
+#define ES7243E_CHIP_VER		0xFF
+
+struct es7243e_priv {
+	struct i2c_client *i2c;
+	struct clk *mclk;
+	unsigned int sysclk;
+	struct snd_pcm_hw_constraint_list *sysclk_constraints;
+};
+
+static const struct regmap_config es7243e_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = ES7243E_CHIP_VER,
+	.cache_type = REGCACHE_MAPLE,
+};
+
+struct coeff_div {
+	u32 mclk;		/* mclk frequency */
+	u32 sr_rate;		/* sample rate */
+	u8 osr;			/* ADC over sample rate */
+	u8 mclk_pre;		/* mclk prediv/premult */
+	u8 cf_dsp_div;		/* adclrck divider and daclrck divider */
+	u8 scale;		/* ADC gain scale up */
+	u8 lrckdiv;		/* lrck divider */
+	u8 bclkdiv;		/* sclk divider */
+};
+
+static const struct coeff_div coeff_div[] = {
+	/* mclk     lrck   osr   pre   div   scale lrdiv bclkdiv */
+	{ 24576000, 8000,  0x20, 0x50, 0x00, 0x00, 0x0b, 0x2f },
+	{ 24576000, 12000, 0x20, 0x30, 0x00, 0x00, 0x07, 0x1f },
+	{ 24576000, 16000, 0x20, 0x20, 0x00, 0x00, 0x05, 0x17 },
+	{ 24576000, 24000, 0x20, 0x10, 0x00, 0x00, 0x03, 0x0f },
+	{ 24576000, 32000, 0x20, 0x21, 0x00, 0x00, 0x02, 0x0b },
+	{ 24576000, 48000, 0x20, 0x00, 0x00, 0x00, 0x01, 0x07 },
+	{ 12288000, 8000,  0x20, 0x20, 0x00, 0x00, 0x05, 0x17 },
+	{ 12288000, 12000, 0x20, 0x10, 0x00, 0x00, 0x03, 0x0f },
+	{ 12288000, 16000, 0x20, 0x21, 0x00, 0x00, 0x02, 0x0b },
+	{ 12288000, 24000, 0x20, 0x00, 0x00, 0x00, 0x01, 0x07 },
+	{ 12288000, 32000, 0x20, 0x22, 0x00, 0x00, 0x01, 0x05 },
+	{ 12288000, 48000, 0x20, 0x01, 0x00, 0x00, 0x00, 0x03 },
+	{ 6144000,  8000,  0x20, 0x21, 0x00, 0x00, 0x02, 0x0b },
+	{ 6144000,  12000, 0x20, 0x00, 0x00, 0x00, 0x01, 0x07 },
+	{ 6144000,  16000, 0x20, 0x22, 0x00, 0x00, 0x01, 0x05 },
+	{ 6144000,  24000, 0x20, 0x01, 0x00, 0x00, 0x00, 0x03 },
+	{ 6144000,  32000, 0x20, 0x23, 0x00, 0x00, 0x00, 0x02 },
+	{ 6144000,  48000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x01 },
+	{ 3072000,  8000,  0x20, 0x22, 0x00, 0x00, 0x01, 0x05 },
+	{ 3072000,  12000, 0x20, 0x01, 0x00, 0x00, 0x00, 0x03 },
+	{ 3072000,  16000, 0x20, 0x23, 0x00, 0x00, 0x00, 0x02 },
+	{ 3072000,  24000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x01 },
+	{ 3072000,  32000, 0x10, 0x03, 0x20, 0x04, 0x00, 0x02 },
+	{ 3072000,  48000, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00 },
+	{ 1536000,  8000,  0x20, 0x23, 0x00, 0x00, 0x00, 0x02 },
+	{ 1536000,  12000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x01 },
+	{ 1536000,  16000, 0x10, 0x03, 0x20, 0x04, 0x00, 0x00 },
+	{ 1536000,  24000, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00 },
+	{ 32768000, 8000,  0x20, 0x70, 0x00, 0x00, 0x0f, 0x3f },
+	{ 32768000, 16000, 0x20, 0x30, 0x00, 0x00, 0x07, 0x1f },
+	{ 32768000, 32000, 0x20, 0x10, 0x00, 0x00, 0x03, 0x0f },
+	{ 16384000, 8000,  0x20, 0x30, 0x00, 0x00, 0x07, 0x1f },
+	{ 16384000, 16000, 0x20, 0x10, 0x00, 0x00, 0x03, 0x0f },
+	{ 16384000, 32000, 0x20, 0x00, 0x00, 0x00, 0x01, 0x07 },
+	{ 8192000,  8000,  0x20, 0x10, 0x00, 0x00, 0x03, 0x0f },
+	{ 8192000,  16000, 0x20, 0x00, 0x00, 0x00, 0x01, 0x07 },
+	{ 8192000,  32000, 0x20, 0x01, 0x00, 0x00, 0x00, 0x03 },
+	{ 4096000,  8000,  0x20, 0x00, 0x00, 0x00, 0x01, 0x07 },
+	{ 4096000,  16000, 0x20, 0x01, 0x00, 0x00, 0x00, 0x03 },
+	{ 4096000,  32000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x01 },
+	{ 2048000,  8000,  0x20, 0x01, 0x00, 0x00, 0x00, 0x03 },
+	{ 2048000,  16000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x01 },
+	{ 2048000,  32000, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00 },
+	{ 1024000,  8000,  0x20, 0x02, 0x00, 0x00, 0x00, 0x01 },
+	{ 1024000,  16000, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00 },
+	{ 22579200, 11025, 0x20, 0x30, 0x00, 0x00, 0x07, 0x1f },
+	{ 22579200, 22050, 0x20, 0x10, 0x00, 0x00, 0x03, 0x0f },
+	{ 22579200, 44100, 0x20, 0x00, 0x00, 0x00, 0x01, 0x07 },
+	{ 11289600, 11025, 0x20, 0x10, 0x00, 0x00, 0x03, 0x0f },
+	{ 11289600, 22050, 0x20, 0x00, 0x00, 0x00, 0x01, 0x07 },
+	{ 11289600, 44100, 0x20, 0x01, 0x00, 0x00, 0x00, 0x03 },
+	{ 56448000, 11025, 0x20, 0x00, 0x00, 0x00, 0x01, 0x07 },
+	{ 56448000, 22050, 0x20, 0x01, 0x00, 0x00, 0x00, 0x03 },
+	{ 56448000, 44100, 0x20, 0x02, 0x00, 0x00, 0x00, 0x01 },
+	{ 28224000, 11025, 0x20, 0x01, 0x00, 0x00, 0x00, 0x03 },
+	{ 28224000, 22050, 0x20, 0x02, 0x00, 0x00, 0x00, 0x01 },
+	{ 28224000, 44100, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00 },
+	{ 14112000, 11025, 0x20, 0x02, 0x00, 0x00, 0x00, 0x01 },
+	{ 14112000, 22050, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00 },
+};
+
+static const struct coeff_div *get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++)
+		if (coeff_div[i].sr_rate == rate && coeff_div[i].mclk == mclk)
+			return &coeff_div[i];
+
+	return NULL;
+}
+
+static unsigned int rates_12288[] = {
+	8000, 12000, 16000, 24000, 32000, 48000, 64000, 96000, 128000, 192000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12288 = {
+	.count = ARRAY_SIZE(rates_12288),
+	.list = rates_12288,
+};
+
+static unsigned int rates_8192[] = {
+	8000, 16000, 32000, 64000, 128000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_8192 = {
+	.count = ARRAY_SIZE(rates_8192),
+	.list = rates_8192,
+};
+
+static unsigned int rates_112896[] = {
+	8000, 11025, 22050, 44100,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_112896 = {
+	.count = ARRAY_SIZE(rates_112896),
+	.list = rates_112896,
+};
+
+static int es7243e_set_dai_sysclk(struct snd_soc_dai *dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct es7243e_priv *es7243e = snd_soc_component_get_drvdata(component);
+
+	switch (freq) {
+	case 11289600:
+	case 22579200:
+		es7243e->sysclk_constraints = &constraints_112896;
+		es7243e->sysclk = freq;
+		break;
+	case 12288000:
+	case 24576000:
+		es7243e->sysclk_constraints = &constraints_12288;
+		es7243e->sysclk = freq;
+		break;
+	case 4096000:
+	case 8192000:
+		es7243e->sysclk_constraints = &constraints_8192;
+		es7243e->sysclk = freq;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_soc_dapm_sync(dapm);
+}
+
+static int es7243e_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int sdpfmt = 0;
+	unsigned int clk2 = 0;
+	bool is_dsp = false;
+	bool invert_lrck = false;
+	int ret;
+
+	/* Set protocol of the serial data port */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		sdpfmt |= FIELD_PREP(ES7243E_SDP_FMT, 0);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		sdpfmt |= FIELD_PREP(ES7243E_SDP_FMT, 1);
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		sdpfmt |= FIELD_PREP(ES7243E_SDP_FMT, 3);
+		is_dsp = true;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		sdpfmt |= FIELD_PREP(ES7243E_SDP_FMT, 3);
+		is_dsp = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Set LR and BCLK polarity */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		clk2 |= FIELD_PREP(ES7243E_CLK2_BCLK_INV, 0);
+		sdpfmt |= FIELD_PREP(ES7243E_SDP_LRP, 0);
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		clk2 |= FIELD_PREP(ES7243E_CLK2_BCLK_INV, 1);
+		sdpfmt |= FIELD_PREP(ES7243E_SDP_LRP, 1);
+		invert_lrck = true;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		clk2 |= FIELD_PREP(ES7243E_CLK2_BCLK_INV, 1);
+		sdpfmt |= FIELD_PREP(ES7243E_SDP_LRP, 0);
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		clk2 |= FIELD_PREP(ES7243E_CLK2_BCLK_INV, 0);
+		sdpfmt |= FIELD_PREP(ES7243E_SDP_LRP, 1);
+		invert_lrck = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Inverted LRCK is not available in DSP mode. */
+	if (is_dsp && invert_lrck)
+		return -EINVAL;
+
+	ret = snd_soc_component_update_bits(component, ES7243E_CLK2,
+					    ES7243E_CLK2_BCLK_INV, clk2);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_component_update_bits(component, ES7243E_SDP,
+					     ES7243E_SDP_LRP, sdpfmt);
+}
+
+static int es7243e_pcm_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct es7243e_priv *es7243e = snd_soc_component_get_drvdata(dai->component);
+
+	if (!es7243e->sysclk_constraints)
+		return 0;
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE,
+					  es7243e->sysclk_constraints);
+}
+
+static int es7243e_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 es7243e_priv *es7243e = dev_get_drvdata(dai->component->dev);
+	const struct coeff_div *cd;
+	unsigned int val;
+	int width;
+	int ret;
+
+	cd = get_coeff(es7243e->sysclk, params_rate(params));
+	if (!cd) {
+		dev_err(dai->component->dev,
+			"Can't set sample rate = %uHz, F_mclk = %uHz\n",
+			params_rate(params), es7243e->sysclk);
+
+		return -EINVAL;
+	}
+
+	ret = snd_soc_component_write(component, ES7243E_ADC_OSR, cd->osr);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_component_write(component, ES7243E_MCLK_PRE,  cd->mclk_pre);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_component_write(component, ES7243E_CF_DSP_DIV, cd->cf_dsp_div);
+	if (ret < 0)
+		return ret;
+
+	val = FIELD_PREP(ES7243E_ADCCTL1_SCALE, cd->scale);
+	ret = snd_soc_component_update_bits(component, ES7243E_ADCCTL1,
+					    ES7243E_ADCCTL1_SCALE, val);
+	if (ret < 0)
+		return ret;
+
+	val = FIELD_PREP(ES7243E_CLK7_LRCK_DIV_HI, cd->lrckdiv);
+	ret = snd_soc_component_update_bits(component, ES7243E_CLK7,
+					    ES7243E_CLK7_LRCK_DIV_HI, val);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_component_write(component, ES7243E_BCLK_DIV, cd->bclkdiv);
+	if (ret < 0)
+		return ret;
+
+	switch ((params_width(params))) {
+	case 24:
+		width = 0;
+		break;
+	case 20:
+		width = 1;
+		break;
+	case 18:
+		width = 2;
+		break;
+	case 16:
+		width = 3;
+		break;
+	case 32:
+		width = 4;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	val = FIELD_PREP(ES7243E_SDP_WL, width);
+	ret = snd_soc_component_update_bits(component, ES7243E_SDP,
+					    ES7243E_SDP_WL, val);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Delay timings are not documented in datasheet and come from vendor's
+	 * driver implementation.
+	 */
+	fsleep(50 * USEC_PER_MSEC);
+	val = FIELD_PREP(ES7243E_SDP_MUTE, 0);
+	return snd_soc_component_update_bits(component, ES7243E_SDP,
+					     ES7243E_SDP_MUTE, val);
+}
+
+static int es7243e_mute(struct snd_soc_dai *dai, int mute, int direction)
+{
+	const int val = FIELD_PREP(ES7243E_SDP_MUTE, 3 * !!mute);
+
+	return snd_soc_component_update_bits(dai->component, ES7243E_SDP,
+					     ES7243E_SDP_MUTE, val);
+}
+
+static const DECLARE_TLV_DB_RANGE(pga_scale,
+	0, 10, TLV_DB_SCALE_ITEM(0, 300, 0),
+	11, 14, TLV_DB_SCALE_ITEM(3300, 150, 0),
+);
+
+static const DECLARE_TLV_DB_SCALE(vol_scale, -9550, 50, 0);
+
+static const struct snd_kcontrol_new es7243e_snd_controls[] = {
+	SOC_SINGLE_RANGE_TLV("PGA1 Volume", ES7243E_PGA1, 0, 0, 14, 0, pga_scale),
+	SOC_SINGLE_RANGE_TLV("PGA2 Volume", ES7243E_PGA2, 0, 0, 14, 0, pga_scale),
+	SOC_SINGLE_RANGE_TLV("ADC Volume", ES7243E_ADC_VOL, 0, 0, 255, 0, vol_scale),
+};
+
+static const struct snd_soc_dapm_widget es7243e_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("INPUT"),
+	SND_SOC_DAPM_ADC("ADC", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SDOUT", "I2S Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route es7243e_dapm_routes[] = {
+	{ "ADC", NULL, "INPUT" },
+	{ "SDOUT", NULL, "ADC" },
+};
+
+static const struct snd_soc_dai_ops es7243e_ops = {
+	.startup = es7243e_pcm_startup,
+	.hw_params = es7243e_pcm_hw_params,
+	.set_fmt = es7243e_set_dai_fmt,
+	.set_sysclk = es7243e_set_dai_sysclk,
+	.mute_stream = es7243e_mute,
+};
+
+static struct snd_soc_dai_driver es7243e_dai = {
+	.name = "es7243e-hifi",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = (SNDRV_PCM_FMTBIT_S16_LE  |
+			    SNDRV_PCM_FMTBIT_S20_3LE |
+			    SNDRV_PCM_FMTBIT_S24_LE  |
+			    SNDRV_PCM_FMTBIT_S32_LE),
+		},
+	.ops = &es7243e_ops,
+};
+
+static const struct reg_sequence init_sequence[] = {
+	{ ES7243E_CLK2,			0x00 },
+	{ ES7243E_SDP,			0x00 },
+	{ ES7243E_TDM,			0x00 },
+
+	/* Set MCLK/LRCK ratio to 256 */
+	{ ES7243E_ADC_OSR,		0x20 },
+	{ ES7243E_ADCCTL1,		0x00 },
+	{ ES7243E_MCLK_PRE,		0x01 },
+	{ ES7243E_CF_DSP_DIV,		0x00 },
+
+	{ ES7243E_S1_SEL,		0xe0 },
+	{ ES7243E_S3_SEL,		0xa0 },
+
+	/* Set ADC volume to 0dB */
+	{ ES7243E_ADC_VOL,		0xbf },
+	/* Enable dynamic HPF (high-pass filter), disable auto level control */
+	{ ES7243E_ADCCTL2,		0x80 },
+	{ ES7243E_ADC_HPF1,		0x0c },
+	{ ES7243E_ADC_HPF2,		0x0c },
+	/* VDDA = 3.3V */
+	{ ES7243E_ADC_BIAS_0x18,	0x26 },
+	{ ES7243E_VMIDSEL,		0x02 },
+	{ ES7243E_PGA_BIAS,		0x77 },
+	{ ES7243E_ADC_BIAS_0x1A,	0xf4 },
+	{ ES7243E_ADC_MICBIAS,		0x66 },
+	{ ES7243E_ADC_VRPBIAS,		0x44 },
+	{ ES7243E_ADC_LP,		0x3c },
+	{ ES7243E_ADC_PGA_LP,		0x00 },
+	{ ES7243E_ADC_VMID,		0x0c },
+	/* Set slave mode, enable clocks, power up */
+	{ ES7243E_RESET,		0x80 },
+	{ ES7243E_CLK1,			0x3a },
+	{ ES7243E_PDN,			0x00 },
+
+	/* Set PGAs gain to 0dB */
+	{ ES7243E_PGA1,			0x10 },
+	{ ES7243E_PGA2,			0x10, 100 * USEC_PER_MSEC },
+
+	/* Reset PGAs */
+	{ ES7243E_PDN,			0x03, 100 * USEC_PER_MSEC  },
+	{ ES7243E_PDN,			0x00 },
+};
+
+static int es7243e_probe(struct snd_soc_component *component)
+{
+	return regmap_multi_reg_write(component->regmap, init_sequence,
+				      ARRAY_SIZE(init_sequence));
+}
+
+static int es7243e_suspend(struct snd_soc_component *component)
+{
+	int ret;
+	unsigned int val, mask;
+
+	val = FIELD_PREP(ES7243E_SDP_MUTE, 0);
+	ret = snd_soc_component_update_bits(component, ES7243E_SDP,
+					    ES7243E_SDP_MUTE, val);
+	if (ret < 0)
+		return ret;
+
+	val = FIELD_PREP(ES7243E_PGA1_EN, 0);
+	snd_soc_component_update_bits(component, ES7243E_PGA1,
+				      ES7243E_PGA1_EN, val);
+	if (ret < 0)
+		return ret;
+
+	val = FIELD_PREP(ES7243E_PGA2_EN, 0);
+	snd_soc_component_update_bits(component, ES7243E_PGA2,
+				      ES7243E_PGA2_EN, val);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_component_write(component, ES7243E_PDN, 0xff);
+	if (ret < 0)
+		return ret;
+
+	mask = ES7243E_CLK1_ANA_ON | ES7243E_CLK1_ADC_ON;
+	ret = snd_soc_component_update_bits(component, ES7243E_CLK1, mask, 0);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int es7243e_resume(struct snd_soc_component *component)
+{
+	int ret;
+	unsigned int val;
+
+	val = ES7243E_CLK1_ANA_ON | ES7243E_CLK1_ADC_ON;
+	ret = snd_soc_component_update_bits(component, ES7243E_CLK1, val, val);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_component_write(component, ES7243E_PDN, 0);
+	if (ret < 0)
+		return ret;
+
+	val = FIELD_PREP(ES7243E_PGA1_EN, 1);
+	snd_soc_component_update_bits(component, ES7243E_PGA1,
+				      ES7243E_PGA1_EN, val);
+	if (ret < 0)
+		return ret;
+
+	val = FIELD_PREP(ES7243E_PGA2_EN, 1);
+	snd_soc_component_update_bits(component, ES7243E_PGA2,
+				      ES7243E_PGA2_EN, val);
+	if (ret < 0)
+		return ret;
+
+	val = FIELD_PREP(ES7243E_SDP_MUTE, 3);
+	ret = snd_soc_component_update_bits(component, ES7243E_SDP,
+					    ES7243E_SDP_MUTE, val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_es7243e = {
+	.probe = es7243e_probe,
+	.controls = es7243e_snd_controls,
+	.suspend = es7243e_suspend,
+	.resume = es7243e_resume,
+	.num_controls = ARRAY_SIZE(es7243e_snd_controls),
+	.dapm_widgets = es7243e_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(es7243e_dapm_widgets),
+	.dapm_routes = es7243e_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(es7243e_dapm_routes),
+};
+
+static int es7243e_hw_init(struct device *dev)
+{
+	struct regmap *regmap = dev_get_regmap(dev, NULL);
+	u8 ids[2];
+	u16 chip_id;
+	int ret;
+
+	ret = regmap_bulk_read(regmap, ES7243E_CHIP_ID1, ids, ARRAY_SIZE(ids));
+	if (ret < 0)
+		goto fail;
+
+	chip_id = (ids[0] << 8) | ids[1];
+
+	if (chip_id != 0x7A43) {
+		return dev_err_probe(dev, -ENODEV,
+				     "wrong CHIP ID: 0x%04x, expected 0x7A43\n",
+				     chip_id);
+	}
+
+	return 0;
+
+fail:
+	return dev_err_probe(dev, ret, "failed to read chip ID\n");
+}
+
+static int es7243e_i2c_probe(struct i2c_client *i2c)
+{
+	struct es7243e_priv *es7243e;
+	struct regmap *regmap;
+	int ret;
+
+	es7243e = devm_kzalloc(&i2c->dev, sizeof(*es7243e), GFP_KERNEL);
+	if (!es7243e)
+		return -ENOMEM;
+
+	es7243e->i2c = i2c;
+	dev_set_drvdata(&i2c->dev, es7243e);
+
+	regmap = devm_regmap_init_i2c(i2c, &es7243e_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&i2c->dev, "failed to init regmap\n");
+		return PTR_ERR(regmap);
+	}
+
+	if (es7243e_hw_init(&i2c->dev))
+		return -ENODEV;
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+					      &soc_component_dev_es7243e,
+					      &es7243e_dai, 1);
+	if (ret)
+		return dev_err_probe(&i2c->dev, ret, "failed to register component\n");
+
+	return ret;
+}
+
+static const struct i2c_device_id es7243e_i2c_id[] = {
+	{ "es7243e", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, es7243e_i2c_id);
+
+static const struct of_device_id es7243e_dt_ids[] = {
+	{ .compatible = "everest,es7243e", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, es7243e_dt_ids);
+
+static struct i2c_driver es7243e_i2c_driver = {
+	.probe = es7243e_i2c_probe,
+	.id_table = es7243e_i2c_id,
+	.driver = {
+		.name = "es7243e-codec",
+		.of_match_table = es7243e_dt_ids,
+	},
+};
+
+module_i2c_driver(es7243e_i2c_driver);
+MODULE_DESCRIPTION("ASoC ES7243E audio ADC driver");
+MODULE_AUTHOR("Igor Prusov <ivprusov@...utedevices.com>");
+MODULE_LICENSE("GPL");
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ