[<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