From 3b13f64c6dd1db7c2209d50dd4a6e42f3f726f75 Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Thu, 6 Aug 2020 14:06:21 +0800 Subject: [PATCH] ASoC: es8311: add support es8311 codec driver Signed-off-by: Xing Zheng Change-Id: Iae35145535664754f3babf4245c9682077c1fc00 --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/es8311.c | 648 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/es8311.h | 68 ++++ 4 files changed, 722 insertions(+) create mode 100644 sound/soc/codecs/es8311.c create mode 100644 sound/soc/codecs/es8311.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index eeb57ac64eed..d086df12dee4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -605,6 +605,10 @@ config SND_SOC_ES7134 config SND_SOC_ES7241 tristate "Everest Semi ES7241 CODEC" +config SND_SOC_ES8311 + tristate "Everest Semi ES8311 CODEC" + depends on I2C + config SND_SOC_ES8316 tristate "Everest Semi ES8316 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f6cdac59277f..ef6a3d9d1d18 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -74,6 +74,7 @@ snd-soc-dmic-objs := dmic.o snd-soc-dummy-codec-objs := dummy-codec.o snd-soc-es7134-objs := es7134.o snd-soc-es7241-objs := es7241.o +snd-soc-es8311-objs := es8311.o snd-soc-es8316-objs := es8316.o snd-soc-es8323-objs := es8323.o snd-soc-es8328-objs := es8328.o @@ -344,6 +345,7 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_DUMMY_CODEC) += snd-soc-dummy-codec.o obj-$(CONFIG_SND_SOC_ES7134) += snd-soc-es7134.o obj-$(CONFIG_SND_SOC_ES7241) += snd-soc-es7241.o +obj-$(CONFIG_SND_SOC_ES8311) += snd-soc-es8311.o obj-$(CONFIG_SND_SOC_ES8316) += snd-soc-es8316.o obj-$(CONFIG_SND_SOC_ES8323) += snd-soc-es8323.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o diff --git a/sound/soc/codecs/es8311.c b/sound/soc/codecs/es8311.c new file mode 100644 index 000000000000..137e17140032 --- /dev/null +++ b/sound/soc/codecs/es8311.c @@ -0,0 +1,648 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * es8311.c -- ES8311/ES8312 ALSA SoC Audio Codec + * + * Copyright (C) 2018 Everest Semiconductor Co., Ltd + * + * Authors: David Yang(yangxiaohua@everest-semi.com) + * + * + * Based on es8374.c by David Yang(yangxiaohua@everest-semi.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "es8311.h" + +/* codec private data */ +struct es8311_priv { + struct snd_soc_component *component; + struct clk *mclk_in; + struct gpio_desc *spk_ctl_gpio; + struct regmap *regmap; +}; + +static const DECLARE_TLV_DB_SCALE(vdac_tlv, + -9550, 50, true); +static const DECLARE_TLV_DB_SCALE(vadc_tlv, + -9550, 50, true); +static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, + 0, 300, true); +static const DECLARE_TLV_DB_SCALE(adc_scale_tlv, + 0, 600, false); +static const DECLARE_TLV_DB_SCALE(alc_winsize_tlv, + 0, 25, false); +static const DECLARE_TLV_DB_SCALE(alc_maxlevel_tlv, + -3600, 200, false); +static const DECLARE_TLV_DB_SCALE(alc_minlevel_tlv, + -3600, 200, false); +static const DECLARE_TLV_DB_SCALE(alc_noisegate_tlv, + -9600, 600, false); +static const DECLARE_TLV_DB_SCALE(alc_noisegate_winsize_tlv, + 4200, 4200, false); +static const DECLARE_TLV_DB_SCALE(alc_automute_gain_tlv, + 4200, 4200, false); +static const DECLARE_TLV_DB_SCALE(adc_ramprate_tlv, + 0, 25, false); + +static const char *const dmic_type_txt[] = { + "dmic at high level", + "dmic at low level" +}; +static const struct soc_enum dmic_type = + SOC_ENUM_SINGLE(ES8311_ADC_REG15, 0, 1, dmic_type_txt); + +static const char *const automute_type_txt[] = { + "automute disabled", + "automute enable" +}; +static const struct soc_enum alc_automute_type = + SOC_ENUM_SINGLE(ES8311_ADC_REG18, 6, 1, automute_type_txt); + +static const char *const dacdsm_mute_type_txt[] = { + "mute to 8", + "mute to 7/9" +}; +static const struct soc_enum dacdsm_mute_type = + SOC_ENUM_SINGLE(ES8311_DAC_REG31, 7, 1, dacdsm_mute_type_txt); + +static const char *const aec_type_txt[] = { + "adc left, adc right", + "adc left, null right", + "null left, adc right", + "null left, null right", + "dac left, adc right", + "adc left, dac right", + "dac left, dac right", + "N/A" +}; +static const struct soc_enum aec_type = + SOC_ENUM_SINGLE(ES8311_GPIO_REG44, 4, 7, aec_type_txt); + +static const char *const adc2dac_sel_txt[] = { + "disable", + "adc data to dac", +}; +static const struct soc_enum adc2dac_sel = + SOC_ENUM_SINGLE(ES8311_GPIO_REG44, 7, 1, adc2dac_sel_txt); + +static const char *const mclk_sel_txt[] = { + "from mclk pin", + "from bclk", +}; +static const struct soc_enum mclk_src = + SOC_ENUM_SINGLE(ES8311_CLK_MANAGER_REG01, 7, 1, mclk_sel_txt); + +/* + * es8311 Controls + */ +static const struct snd_kcontrol_new es8311_snd_controls[] = { + SOC_SINGLE_TLV("MIC PGA GAIN", ES8311_SYSTEM_REG14, + 0, 10, 0, mic_pga_tlv), + SOC_SINGLE_TLV("ADC SCALE", ES8311_ADC_REG16, + 0, 7, 0, adc_scale_tlv), + SOC_ENUM("DMIC TYPE", dmic_type), + SOC_SINGLE_TLV("ADC RAMP RATE", ES8311_ADC_REG15, + 4, 15, 0, adc_ramprate_tlv), + SOC_SINGLE("ADC SDP MUTE", ES8311_SDPOUT_REG0A, 6, 1, 0), + SOC_SINGLE("ADC INVERTED", ES8311_ADC_REG16, 4, 1, 0), + SOC_SINGLE("ADC SYNC", ES8311_ADC_REG16, 5, 1, 1), + SOC_SINGLE("ADC RAM CLR", ES8311_ADC_REG16, 3, 1, 0), + SOC_SINGLE_TLV("ADC VOLUME", ES8311_ADC_REG17, + 0, 255, 0, vadc_tlv), + SOC_SINGLE("ALC ENABLE", ES8311_ADC_REG18, 7, 1, 0), + SOC_ENUM("ALC AUTOMUTE TYPE", alc_automute_type), + SOC_SINGLE_TLV("ALC WIN SIZE", ES8311_ADC_REG18, + 0, 15, 0, alc_winsize_tlv), + SOC_SINGLE_TLV("ALC MAX LEVEL", ES8311_ADC_REG19, + 4, 15, 0, alc_maxlevel_tlv), + SOC_SINGLE_TLV("ALC MIN LEVEL", ES8311_ADC_REG19, + 0, 15, 0, alc_minlevel_tlv), + SOC_SINGLE_TLV("ALC AUTOMUTE WINSIZE", ES8311_ADC_REG1A, + 4, 15, 0, alc_noisegate_winsize_tlv), + SOC_SINGLE_TLV("ALC AUTOMUTE GATE THRESHOLD", ES8311_ADC_REG1A, + 0, 15, 0, alc_noisegate_tlv), + SOC_SINGLE_TLV("ALC AUTOMUTE VOLUME", ES8311_ADC_REG1B, + 5, 7, 0, alc_automute_gain_tlv), + SOC_SINGLE("ADC FS MODE", ES8311_CLK_MANAGER_REG03, 6, 1, 0), + SOC_SINGLE("ADC OSR", ES8311_CLK_MANAGER_REG03, 0, 63, 0), + SOC_SINGLE("DAC SDP MUTE", ES8311_SDPIN_REG09, 6, 1, 0), + SOC_SINGLE("DAC DEM MUTE", ES8311_DAC_REG31, 5, 1, 0), + SOC_SINGLE("DAC INVERT", ES8311_DAC_REG31, 4, 1, 0), + SOC_SINGLE("DAC RAM CLR", ES8311_DAC_REG31, 3, 1, 0), + SOC_ENUM("DAC DSM MUTE", dacdsm_mute_type), + SOC_SINGLE("DAC OFFSET", ES8311_DAC_REG33, 0, 255, 0), + SOC_SINGLE_TLV("DAC VOLUME", ES8311_DAC_REG32, + 0, 255, 0, vdac_tlv), + SOC_SINGLE("DRC ENABLE", ES8311_DAC_REG34, 7, 1, 0), + SOC_SINGLE_TLV("DRC WIN SIZE", ES8311_DAC_REG34, + 0, 15, 0, alc_winsize_tlv), + SOC_SINGLE_TLV("DRC MAX LEVEL", ES8311_DAC_REG35, + 4, 15, 0, alc_maxlevel_tlv), + SOC_SINGLE_TLV("DRC MIN LEVEL", ES8311_DAC_REG35, + 0, 15, 0, alc_minlevel_tlv), + SOC_SINGLE_TLV("DAC RAMP RATE", ES8311_DAC_REG37, + 4, 15, 0, adc_ramprate_tlv), + SOC_SINGLE("DAC OSR", ES8311_CLK_MANAGER_REG04, 0, 127, 0), + SOC_ENUM("AEC MODE", aec_type), + SOC_ENUM("ADC DATA TO DAC TEST MODE", adc2dac_sel), + SOC_SINGLE("MCLK INVERT", ES8311_CLK_MANAGER_REG01, 6, 1, 0), + SOC_SINGLE("BCLK INVERT", ES8311_CLK_MANAGER_REG06, 5, 1, 0), + SOC_ENUM("MCLK SOURCE", mclk_src), +}; + +/* + * DAPM Controls + */ +static const char *const es8311_dmic_mux_txt[] = { + "DMIC DISABLE", + "DMIC ENABLE", +}; +static const unsigned int es8311_dmic_mux_values[] = { + 0, 1 +}; +static const struct soc_enum es8311_dmic_mux_enum = + SOC_VALUE_ENUM_SINGLE(ES8311_SYSTEM_REG14, 6, 1, + ARRAY_SIZE(es8311_dmic_mux_txt), + es8311_dmic_mux_txt, + es8311_dmic_mux_values); +static const struct snd_kcontrol_new es8311_dmic_mux_controls = + SOC_DAPM_ENUM("DMIC ROUTE", es8311_dmic_mux_enum); + +static const char *const es8311_adc_sdp_mux_txt[] = { + "FROM ADC", + "FROM EQUALIZER", +}; +static const unsigned int es8311_adc_sdp_mux_values[] = { + 0, 1 +}; +static const struct soc_enum es8311_adc_sdp_mux_enum = + SOC_VALUE_ENUM_SINGLE(ES8311_ADC_REG1C, 6, 1, + ARRAY_SIZE(es8311_adc_sdp_mux_txt), + es8311_adc_sdp_mux_txt, + es8311_adc_sdp_mux_values); +static const struct snd_kcontrol_new es8311_adc_sdp_mux_controls = + SOC_DAPM_ENUM("ADC SDP ROUTE", es8311_adc_sdp_mux_enum); + +/* + * DAC data source + */ +static const char *const es8311_dac_data_mux_txt[] = { + "SELECT SDP LEFT DATA", + "SELECT SDP RIGHT DATA", +}; +static const unsigned int es8311_dac_data_mux_values[] = { + 0, 1 +}; +static const struct soc_enum es8311_dac_data_mux_enum = + SOC_VALUE_ENUM_SINGLE(ES8311_SDPIN_REG09, 7, 1, + ARRAY_SIZE(es8311_dac_data_mux_txt), + es8311_dac_data_mux_txt, + es8311_dac_data_mux_values); +static const struct snd_kcontrol_new es8311_dac_data_mux_controls = + SOC_DAPM_ENUM("DAC SDP ROUTE", es8311_dac_data_mux_enum); + +static const struct snd_soc_dapm_widget es8311_dapm_widgets[] = { + /* Input*/ + SND_SOC_DAPM_INPUT("DMIC"), + SND_SOC_DAPM_INPUT("AMIC"), + + SND_SOC_DAPM_PGA("INPUT PGA", ES8311_SYSTEM_REG0E, + 6, 1, NULL, 0), + /* ADCs */ + SND_SOC_DAPM_ADC("MONO ADC", NULL, ES8311_SYSTEM_REG0E, 5, 1), + /* Dmic MUX */ + SND_SOC_DAPM_MUX("DMIC MUX", SND_SOC_NOPM, 0, 0, + &es8311_dmic_mux_controls), + /* sdp MUX */ + SND_SOC_DAPM_MUX("SDP OUT MUX", SND_SOC_NOPM, 0, 0, + &es8311_adc_sdp_mux_controls), + /* Digital Interface */ + SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture", 1, + SND_SOC_NOPM, 0, 0), + /* Render path */ + SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0, + SND_SOC_NOPM, 0, 0), + /*DACs SDP DATA SRC MUX */ + SND_SOC_DAPM_MUX("DAC SDP SRC MUX", SND_SOC_NOPM, 0, 0, + &es8311_dac_data_mux_controls), + SND_SOC_DAPM_DAC("MONO DAC", NULL, SND_SOC_NOPM, 0, 0), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("DIFFERENTIAL OUT"), +}; + +static const struct snd_soc_dapm_route es8311_dapm_routes[] = { + /* record route map */ + {"INPUT PGA", NULL, "AMIC"}, + {"MONO ADC", NULL, "INPUT PGA"}, + {"DMIC MUX", "DMIC DISABLE", "MONO ADC"}, + {"DMIC MUX", "DMIC ENABLE", "DMIC"}, + {"SDP OUT MUX", "FROM ADC OUT", "DMIC MUX"}, + {"SDP OUT MUX", "FROM EQUALIZER", "DMIC MUX"}, + {"I2S OUT", NULL, "SDP OUT MUX"}, + /* playback route map */ + {"DAC SDP SRC MUX", "SELECT SDP LEFT DATA", "I2S IN"}, + {"DAC SDP SRC MUX", "SELECT SDP RIGHT DATA", "I2S IN"}, + {"MONO DAC", NULL, "DAC SDP SRC MUX"}, + {"DIFFERENTIAL OUT", NULL, "MONO DAC"}, +}; + +static int es8311_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_component *component = codec_dai->component; + u8 iface = 0; + u8 adciface = 0; + u8 daciface = 0; + + iface = snd_soc_component_read32(component, ES8311_RESET_REG00); + adciface = snd_soc_component_read32(component, ES8311_SDPOUT_REG0A); + daciface = snd_soc_component_read32(component, ES8311_SDPIN_REG09); + + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: /* MASTER MODE */ + iface |= 0x40; + break; + case SND_SOC_DAIFMT_CBS_CFS: /* SLAVE MODE */ + iface &= 0xBF; + break; + default: + return -EINVAL; + } + snd_soc_component_write(component, ES8311_RESET_REG00, iface); + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + adciface &= 0xFC; + daciface &= 0xFC; + break; + case SND_SOC_DAIFMT_LEFT_J: + adciface &= 0xFC; + daciface &= 0xFC; + adciface |= 0x01; + daciface |= 0x01; + break; + case SND_SOC_DAIFMT_DSP_A: + adciface &= 0xDC; + daciface &= 0xDC; + adciface |= 0x03; + daciface |= 0x03; + break; + case SND_SOC_DAIFMT_DSP_B: + adciface &= 0xDC; + daciface &= 0xDC; + adciface |= 0x23; + daciface |= 0x23; + break; + case SND_SOC_DAIFMT_RIGHT_J: + default: + return -EINVAL; + } + + iface = snd_soc_component_read32(component, ES8311_CLK_MANAGER_REG06); + /* clock inversion */ + if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) || + ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_LEFT_J)) { + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + iface &= 0xDF; + adciface &= 0xDF; + daciface &= 0xDF; + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x20; + adciface |= 0x20; + daciface |= 0x20; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x20; + adciface &= 0xDF; + daciface &= 0xDF; + break; + case SND_SOC_DAIFMT_NB_IF: + iface &= 0xDF; + adciface |= 0x20; + daciface |= 0x20; + break; + default: + return -EINVAL; + } + } + + snd_soc_component_write(component, ES8311_CLK_MANAGER_REG06, iface); + snd_soc_component_write(component, ES8311_SDPOUT_REG0A, adciface); + snd_soc_component_write(component, ES8311_SDPIN_REG09, daciface); + + return 0; +} + +static int es8311_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component); + + clk_prepare_enable(es8311->mclk_in); + + return 0; +} + +static void es8311_pcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component); + + clk_disable_unprepare(es8311->mclk_in); +} + +static int es8311_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; + u16 iface; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + iface = snd_soc_component_read32(component, ES8311_SDPIN_REG09) & 0xE3; + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + iface |= 0x0c; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= 0x04; + break; + case SNDRV_PCM_FORMAT_S24_LE: + break; + case SNDRV_PCM_FORMAT_S32_LE: + iface |= 0x10; + break; + } + /* set iface */ + snd_soc_component_write(component, ES8311_SDPIN_REG09, iface); + } else { + iface = snd_soc_component_read32(component, ES8311_SDPOUT_REG0A) & 0xE3; + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + iface |= 0x0c; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= 0x04; + break; + case SNDRV_PCM_FORMAT_S24_LE: + break; + case SNDRV_PCM_FORMAT_S32_LE: + iface |= 0x10; + break; + } + /* set iface */ + snd_soc_component_write(component, ES8311_SDPOUT_REG0A, iface); + } + + return 0; +} + +static int es8311_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component); + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + if (IS_ERR(es8311->mclk_in)) + break; + + if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) { + clk_disable_unprepare(es8311->mclk_in); + } else { + ret = clk_prepare_enable(es8311->mclk_in); + if (ret) + return ret; + } + break; + + case SND_SOC_BIAS_STANDBY: + break; + + case SND_SOC_BIAS_OFF: + break; + } + return 0; +} + +static int es8311_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + struct snd_soc_component *component = dai->component; + + if (tristate) + snd_soc_component_update_bits(component, ES8311_CLK_MANAGER_REG07, + 0x30, 0x30); + else + snd_soc_component_update_bits(component, ES8311_CLK_MANAGER_REG07, + 0x30, 0x00); + return 0; +} + +static int es8311_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_component *component = dai->component; + struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component); + + if (mute) { + snd_soc_component_write(component, ES8311_SYSTEM_REG12, 0x02); + snd_soc_component_update_bits(component, ES8311_DAC_REG31, 0x60, 0x60); + if (es8311->spk_ctl_gpio) + gpiod_direction_output(es8311->spk_ctl_gpio, 0); + } else { + snd_soc_component_update_bits(component, ES8311_DAC_REG31, 0x60, 0x00); + snd_soc_component_write(component, ES8311_SYSTEM_REG12, 0x00); + if (es8311->spk_ctl_gpio) + gpiod_direction_output(es8311->spk_ctl_gpio, 1); + } + return 0; +} + +#define ES8311_RATES SNDRV_PCM_RATE_8000_96000 +#define ES8311_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops es8311_ops = { + .startup = es8311_pcm_startup, + .shutdown = es8311_pcm_shutdown, + .hw_params = es8311_pcm_hw_params, + .set_fmt = es8311_set_dai_fmt, + .digital_mute = es8311_mute, + .set_tristate = es8311_set_tristate, +}; + +static struct snd_soc_dai_driver es8311_dai = { + .name = "ES8311 HiFi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = ES8311_RATES, + .formats = ES8311_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = ES8311_RATES, + .formats = ES8311_FORMATS, + }, + .ops = &es8311_ops, + .symmetric_rates = 1, +}; + +static int es8311_regs_init(struct snd_soc_component *component) +{ + /* reset codec */ + snd_soc_component_write(component, ES8311_RESET_REG00, 0x1F); + snd_soc_component_write(component, ES8311_GP_REG45, 0x00); + /* set ADC/DAC CLK */ + snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0x30); + snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, 0x00); + snd_soc_component_write(component, ES8311_CLK_MANAGER_REG03, 0x10); + snd_soc_component_write(component, ES8311_CLK_MANAGER_REG04, 0x10); + snd_soc_component_write(component, ES8311_CLK_MANAGER_REG05, 0x00); + /* set system power up */ + snd_soc_component_write(component, ES8311_SYSTEM_REG0B, 0x00); + snd_soc_component_write(component, ES8311_SYSTEM_REG0C, 0x00); + snd_soc_component_write(component, ES8311_SYSTEM_REG10, 0x1F); + snd_soc_component_write(component, ES8311_SYSTEM_REG11, 0x7F); + /* chip powerup. slave mode */ + snd_soc_component_write(component, ES8311_RESET_REG00, 0x80); + usleep_range(5000, 5500); + + /* power up analog */ + snd_soc_component_write(component, ES8311_SYSTEM_REG0D, 0x01); + /* power up digital */ + snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0x3F); + /* set adc hpf, ADC_EQ bypass */ + snd_soc_component_write(component, ES8311_ADC_REG1C, 0x6A); + + return 0; +} + +static int es8311_probe(struct snd_soc_component *component) +{ + struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component); + + es8311->component = component; + es8311_regs_init(component); + + return 0; +} + +static const struct snd_soc_component_driver soc_component_dev_es8311 = { + .probe = es8311_probe, + .set_bias_level = es8311_set_bias_level, + .controls = es8311_snd_controls, + .num_controls = ARRAY_SIZE(es8311_snd_controls), + .dapm_widgets = es8311_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(es8311_dapm_widgets), + .dapm_routes = es8311_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(es8311_dapm_routes), + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static struct regmap_config es8311_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ES8311_MAX_REGISTER, + .cache_type = REGCACHE_RBTREE, +}; + +static int es8311_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct es8311_priv *es8311; + struct regmap *regmap; + int ret = 0; + + es8311 = devm_kzalloc(&i2c_client->dev, + sizeof(*es8311), GFP_KERNEL); + if (es8311 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c_client, es8311); + + regmap = devm_regmap_init_i2c(i2c_client, &es8311_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + es8311->mclk_in = devm_clk_get(&i2c_client->dev, "mclk"); + if (IS_ERR(es8311->mclk_in)) + return PTR_ERR(es8311->mclk_in); + + es8311->spk_ctl_gpio = devm_gpiod_get_optional(&i2c_client->dev, "spk-ctl", + GPIOD_OUT_LOW); + if (!es8311->spk_ctl_gpio) { + dev_info(&i2c_client->dev, "Don't need spk-ctl gpio\n"); + } else if (IS_ERR(es8311->spk_ctl_gpio)) { + ret = PTR_ERR(es8311->spk_ctl_gpio); + dev_err(&i2c_client->dev, "Unable to claim gpio spk-ctl\n"); + return ret; + } + + return devm_snd_soc_register_component(&i2c_client->dev, + &soc_component_dev_es8311, + &es8311_dai, 1); +} + +static const struct i2c_device_id es8311_i2c_id[] = { + {"es8311", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, es8311_i2c_id); + +static const struct of_device_id es8311_of_match[] = { + { .compatible = "everest,es8311", }, + {}, +}; +MODULE_DEVICE_TABLE(of, es8311_of_match); + +static struct i2c_driver es8311_i2c_driver = { + .driver = { + .name = "es8311", + .of_match_table = of_match_ptr(es8311_of_match), + }, + .probe = es8311_i2c_probe, + .id_table = es8311_i2c_id, +}; +module_i2c_driver(es8311_i2c_driver); + +MODULE_DESCRIPTION("Everest Semi ES8311 ALSA SoC Codec Driver"); +MODULE_AUTHOR("David Yang "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8311.h b/sound/soc/codecs/es8311.h new file mode 100644 index 000000000000..227b34c09879 --- /dev/null +++ b/sound/soc/codecs/es8311.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * ES8311.h -- ES8311 ALSA SoC Audio Codec + * + * Authors: + * + * Based on ES8374.h by David Yang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _ES8311_H +#define _ES8311_H + +/* + * ES8311_REGISTER NAME_REG_REGISTER ADDRESS + */ +#define ES8311_RESET_REG00 0x00 /*reset digital,csm,clock manager etc.*/ + +/* + * Clock Scheme Register definition + */ +#define ES8311_CLK_MANAGER_REG01 0x01 /* select clk src for mclk, enable clock for codec */ +#define ES8311_CLK_MANAGER_REG02 0x02 /* clk divider and clk multiplier */ +#define ES8311_CLK_MANAGER_REG03 0x03 /* adc fsmode and osr */ +#define ES8311_CLK_MANAGER_REG04 0x04 /* dac osr */ +#define ES8311_CLK_MANAGER_REG05 0x05 /* clk divier for adc and dac */ +#define ES8311_CLK_MANAGER_REG06 0x06 /* bclk inverter and divider */ +#define ES8311_CLK_MANAGER_REG07 0x07 /* tri-state, lrck divider */ +#define ES8311_CLK_MANAGER_REG08 0x08 /* lrck divider */ +#define ES8311_SDPIN_REG09 0x09 /* dac serial digital port */ +#define ES8311_SDPOUT_REG0A 0x0A /* adc serial digital port */ +#define ES8311_SYSTEM_REG0B 0x0B /* system */ +#define ES8311_SYSTEM_REG0C 0x0C /* system */ +#define ES8311_SYSTEM_REG0D 0x0D /* system, power up/down */ +#define ES8311_SYSTEM_REG0E 0x0E /* system, power up/down */ +#define ES8311_SYSTEM_REG0F 0x0F /* system, low power */ +#define ES8311_SYSTEM_REG10 0x10 /* system */ +#define ES8311_SYSTEM_REG11 0x11 /* system */ +#define ES8311_SYSTEM_REG12 0x12 /* system, Enable DAC */ +#define ES8311_SYSTEM_REG13 0x13 /* system */ +#define ES8311_SYSTEM_REG14 0x14 /* system, select DMIC, select analog pga gain */ +#define ES8311_ADC_REG15 0x15 /* ADC, adc ramp rate, dmic sense */ +#define ES8311_ADC_REG16 0x16 /* ADC */ +#define ES8311_ADC_REG17 0x17 /* ADC, volume */ +#define ES8311_ADC_REG18 0x18 /* ADC, alc enable and winsize */ +#define ES8311_ADC_REG19 0x19 /* ADC, alc maxlevel */ +#define ES8311_ADC_REG1A 0x1A /* ADC, alc automute */ +#define ES8311_ADC_REG1B 0x1B /* ADC, alc automute, adc hpf s1 */ +#define ES8311_ADC_REG1C 0x1C /* ADC, equalizer, hpf s2 */ +#define ES8311_DAC_REG31 0x31 /* DAC, mute */ +#define ES8311_DAC_REG32 0x32 /* DAC, volume */ +#define ES8311_DAC_REG33 0x33 /* DAC, offset */ +#define ES8311_DAC_REG34 0x34 /* DAC, drc enable, drc winsize */ +#define ES8311_DAC_REG35 0x35 /* DAC, drc maxlevel, minilevel */ +#define ES8311_DAC_REG37 0x37 /* DAC, ramprate */ +#define ES8311_GPIO_REG44 0x44 /* GPIO, dac2adc for test */ +#define ES8311_GP_REG45 0x45 /* GP CONTROL */ +#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */ +#define ES8311_CHD2_REGFE 0xFE /* CHIP ID2 */ +#define ES8311_CHVER_REGFF 0xFF /* VERSION */ +#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */ + +#define ES8311_MAX_REGISTER 0xFF + +#endif