All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] ASoC: add es8316 codec driver
@ 2017-05-10 18:16 Daniel Drake
  2017-05-10 18:16 ` [PATCH 2/2] ASoC: Intel: add machine driver for BYT/CHT + ES8316 Daniel Drake
  2017-05-10 18:49 ` [PATCH 1/2] ASoC: add es8316 codec driver Pierre-Louis Bossart
  0 siblings, 2 replies; 8+ messages in thread
From: Daniel Drake @ 2017-05-10 18:16 UTC (permalink / raw)
  To: lgirdwood, broonie; +Cc: alsa-devel, linux, pierre-louis.bossart, yangxiaohua

Add a codec driver for the Everest ES8316, based on code provided by
David Yang from Everest Semi.

I limited the functionality to items where the vendor code was clear,
and things that can be tested on the Weibu F3C (Intel Cherry Trail).
As a result the initial implementation only supports running in slave
mode at single speed (up to 48kHz sample rate) using I2S. HPD is not
supported.

Signed-off-by: Daniel Drake <drake@endlessm.com>
---
 sound/soc/codecs/Kconfig  |   4 +
 sound/soc/codecs/Makefile |   2 +
 sound/soc/codecs/es8316.c | 639 ++++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/es8316.h | 122 +++++++++
 4 files changed, 767 insertions(+)
 create mode 100644 sound/soc/codecs/es8316.c
 create mode 100644 sound/soc/codecs/es8316.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 883ed4c8a551..c6286e5ba511 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -72,6 +72,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_DA9055 if I2C
 	select SND_SOC_DIO2125
 	select SND_SOC_DMIC
+	select SND_SOC_ES8316 if I2C
 	select SND_SOC_ES8328_SPI if SPI_MASTER
 	select SND_SOC_ES8328_I2C if I2C
 	select SND_SOC_ES7134
@@ -543,6 +544,9 @@ config SND_SOC_HDMI_CODEC
 config SND_SOC_ES7134
        tristate "Everest Semi ES7134 CODEC"
 
+config SND_SOC_ES8316
+	tristate "Everest Semi ES8316 CODEC"
+
 config SND_SOC_ES8328
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 28a63fdaf982..e878306ce46e 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -65,6 +65,7 @@ snd-soc-da732x-objs := da732x.o
 snd-soc-da9055-objs := da9055.o
 snd-soc-dmic-objs := dmic.o
 snd-soc-es7134-objs := es7134.o
+snd-soc-es8316-objs := es8316.o
 snd-soc-es8328-objs := es8328.o
 snd-soc-es8328-i2c-objs := es8328-i2c.o
 snd-soc-es8328-spi-objs := es8328-spi.o
@@ -300,6 +301,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_ES8316)    += snd-soc-es8316.o
 obj-$(CONFIG_SND_SOC_ES8328)	+= snd-soc-es8328.o
 obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
 obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
new file mode 100644
index 000000000000..aea0b981891b
--- /dev/null
+++ b/sound/soc/codecs/es8316.c
@@ -0,0 +1,639 @@
+/*
+ * es8316.c -- es8316 ALSA SoC audio driver
+ * Copyright Everest Semiconductor Co.,Ltd
+ *
+ * Authors: David Yang <yangxiaohua@everest-semi.com>,
+ *          Daniel Drake <drake@endlessm.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 <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "es8316.h"
+
+/* In slave mode at single speed, the codec is documented as accepting 5
+ * MCLK/LRCK ratios, but we also add ratio 400, which is commonly used on
+ * Intel Cherry Trail platforms (19.2MHz MCLK, 48kHz LRCK).
+ */
+#define NR_SUPPORTED_MCLK_LRCK_RATIOS 6
+static const unsigned int supported_mclk_lrck_ratios[] = {
+	256, 384, 400, 512, 768, 1024
+};
+
+struct es8316_priv {
+	unsigned int sysclk;
+	unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS];
+	struct snd_pcm_hw_constraint_list sysclk_constraints;
+};
+
+/*
+ * ES8316 controls
+ */
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9600, 50, 1);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -9600, 50, 1);
+static const DECLARE_TLV_DB_SCALE(hpmixer_gain_tlv, -1200, 150, 0);
+static const DECLARE_TLV_DB_SCALE(mic_bst_tlv, 0, 1200, 0);
+
+static unsigned int linin_pga_tlv[] = {
+	TLV_DB_RANGE_HEAD(12),
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(300, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(600, 0, 0),
+	3, 3, TLV_DB_SCALE_ITEM(900, 0, 0),
+	4, 4, TLV_DB_SCALE_ITEM(1200, 0, 0),
+	5, 5, TLV_DB_SCALE_ITEM(1500, 0, 0),
+	6, 6, TLV_DB_SCALE_ITEM(1800, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(2100, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(2400, 0, 0),
+};
+static unsigned int hpout_vol_tlv[] = {
+	TLV_DB_RANGE_HEAD(1),
+	0, 3, TLV_DB_SCALE_ITEM(-4800, 1200, 0),
+};
+static const char * const alc_func_txt[] = { "Off", "On" };
+static const struct soc_enum alc_func =
+	SOC_ENUM_SINGLE(ES8316_ADC_ALC1, 6, 2, alc_func_txt);
+
+static const char * const ng_type_txt[] =
+	{ "Constant PGA Gain", "Mute ADC Output"};
+static const struct soc_enum ng_type =
+	SOC_ENUM_SINGLE(ES8316_ADC_ALC6, 6, 2, ng_type_txt);
+
+static const char * const adcpol_txt[] = { "Normal", "Invert" };
+static const struct soc_enum adcpol =
+	SOC_ENUM_SINGLE(ES8316_ADC_MUTE, 1, 2, adcpol_txt);
+static const char *const dacpol_txt[] =
+	{ "Normal", "R Invert", "L Invert", "L + R Invert" };
+static const struct soc_enum dacpol =
+	SOC_ENUM_SINGLE(ES8316_DAC_SET1, 0, 4, dacpol_txt);
+
+static const struct snd_kcontrol_new es8316_snd_controls[] = {
+	SOC_DOUBLE_TLV("HP Playback Volume", ES8316_CPHP_ICAL_VOL,
+		       4, 0, 0, 1, hpout_vol_tlv),
+	SOC_DOUBLE_TLV("HPMixer Gain", ES8316_HPMIX_VOL,
+		       0, 4, 7, 0, hpmixer_gain_tlv),
+
+	SOC_DOUBLE_R_TLV("DAC Playback Volume", ES8316_DAC_VOLL,
+			 ES8316_DAC_VOLR, 0, 0xC0, 1, dac_vol_tlv),
+
+	SOC_SINGLE("Enable DAC Soft Ramp", ES8316_DAC_SET1, 4, 1, 1),
+	SOC_SINGLE("DAC Soft Ramp Rate", ES8316_DAC_SET1, 2, 4, 0),
+
+	SOC_ENUM("Playback Polarity", dacpol),
+	SOC_SINGLE("DAC Notch Filter", ES8316_DAC_SET2, 6, 1, 0),
+	SOC_SINGLE("DAC Double Fs Mode", ES8316_DAC_SET2, 7, 1, 0),
+	SOC_SINGLE("DAC Volume Control-LeR", ES8316_DAC_SET2, 2, 1, 0),
+	SOC_SINGLE("DAC Stereo Enhancement", ES8316_DAC_SET3, 0, 7, 0),
+
+	/* +20dB D2SE PGA Control */
+	SOC_SINGLE_TLV("MIC Boost", ES8316_ADC_D2SEPGA,
+		       0, 1, 0, mic_bst_tlv),
+
+	/* 0-+24dB Lineinput PGA Control */
+	SOC_SINGLE_TLV("Input PGA", ES8316_ADC_PGAGAIN,
+		       4, 8, 0, linin_pga_tlv),
+
+	SOC_SINGLE_TLV("ADC Capture Volume", ES8316_ADC_VOLUME,
+		       0, 0xc0, 1, adc_vol_tlv),
+	SOC_SINGLE("ADC Soft Ramp", ES8316_ADC_MUTE, 4, 1, 0),
+	SOC_ENUM("Capture Polarity", adcpol),
+	SOC_SINGLE("ADC Double FS Mode", ES8316_ADC_DMIC, 4, 1, 0),
+
+	SOC_SINGLE("ALC Capture Target Volume",
+		   ES8316_ADC_ALC3, 4, 10, 0),
+	SOC_SINGLE("ALC Capture Max PGA", ES8316_ADC_ALC1, 0, 28, 0),
+	SOC_SINGLE("ALC Capture Min PGA", ES8316_ADC_ALC2, 0, 28, 0),
+	SOC_ENUM("ALC Capture Function", alc_func),
+	SOC_SINGLE("ALC Capture Hold Time", ES8316_ADC_ALC3, 0, 10, 0),
+	SOC_SINGLE("ALC Capture Decay Time", ES8316_ADC_ALC4, 4, 10, 0),
+	SOC_SINGLE("ALC Capture Attack Time", ES8316_ADC_ALC4, 0, 10, 0),
+	SOC_SINGLE("ALC Capture NG Threshold", ES8316_ADC_ALC6, 0, 31, 0),
+	SOC_ENUM("ALC Capture NG Type", ng_type),
+	SOC_SINGLE("ALC Capture NG Switch", ES8316_ADC_ALC6, 5, 1, 0),
+};
+
+/* Analog Input Mux */
+static const char * const es8316_analog_in_txt[] = {
+		"lin1-rin1",
+		"lin2-rin2",
+		"lin1-rin1 with 20db Boost",
+		"lin2-rin2 with 20db Boost"
+};
+static const unsigned int es8316_analog_in_values[] = { 0, 1, 2, 3 };
+static const struct soc_enum es8316_analog_input_enum =
+	SOC_VALUE_ENUM_SINGLE(ES8316_ADC_PDN_LINSEL, 4, 3,
+			      ARRAY_SIZE(es8316_analog_in_txt),
+			      es8316_analog_in_txt,
+			      es8316_analog_in_values);
+static const struct snd_kcontrol_new es8316_analog_in_mux_controls =
+	SOC_DAPM_ENUM("Route", es8316_analog_input_enum);
+
+static const char * const es8316_dmic_txt[] = {
+		"dmic disable",
+		"dmic data at high level",
+		"dmic data at low level",
+};
+static const unsigned int es8316_dmic_values[] = { 0, 1, 2 };
+static const struct soc_enum es8316_dmic_src_enum =
+	SOC_VALUE_ENUM_SINGLE(ES8316_ADC_DMIC, 0, 3,
+			      ARRAY_SIZE(es8316_dmic_txt),
+			      es8316_dmic_txt,
+			      es8316_dmic_values);
+static const struct snd_kcontrol_new es8316_dmic_src_controls =
+	SOC_DAPM_ENUM("Route", es8316_dmic_src_enum);
+
+/* hp mixer mux */
+static const char * const es8316_hpmux_texts[] = {
+	"lin1-rin1",
+	"lin2-rin2",
+	"lin-rin with Boost",
+	"lin-rin with Boost and PGA"
+};
+
+static const unsigned int es8316_hpmux_values[] = { 0, 1, 2, 3 };
+
+static SOC_ENUM_SINGLE_DECL(es8316_left_hpmux_enum, ES8316_HPMIX_SEL,
+	4, es8316_hpmux_texts);
+
+static const struct snd_kcontrol_new es8316_left_hpmux_controls =
+	SOC_DAPM_ENUM("Route", es8316_left_hpmux_enum);
+
+static SOC_ENUM_SINGLE_DECL(es8316_right_hpmux_enum, ES8316_HPMIX_SEL,
+	0, es8316_hpmux_texts);
+
+static const struct snd_kcontrol_new es8316_right_hpmux_controls =
+	SOC_DAPM_ENUM("Route", es8316_right_hpmux_enum);
+
+/* headphone Output Mixer */
+static const struct snd_kcontrol_new es8316_out_left_mix[] = {
+	SOC_DAPM_SINGLE("LLIN Switch", ES8316_HPMIX_SWITCH, 6, 1, 0),
+	SOC_DAPM_SINGLE("Left DAC Switch", ES8316_HPMIX_SWITCH, 7, 1, 0),
+};
+static const struct snd_kcontrol_new es8316_out_right_mix[] = {
+	SOC_DAPM_SINGLE("RLIN Switch", ES8316_HPMIX_SWITCH, 2, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC Switch", ES8316_HPMIX_SWITCH, 3, 1, 0),
+};
+
+/* DAC data source mux */
+static const char * const es8316_dacsrc_texts[] = {
+	"LDATA TO LDAC, RDATA TO RDAC",
+	"LDATA TO LDAC, LDATA TO RDAC",
+	"RDATA TO LDAC, RDATA TO RDAC",
+	"RDATA TO LDAC, LDATA TO RDAC",
+};
+
+static const unsigned int es8316_dacsrc_values[] = { 0, 1, 2, 3 };
+
+static SOC_ENUM_SINGLE_DECL(es8316_dacsrc_mux_enum, ES8316_DAC_SET1,
+	6, es8316_dacsrc_texts);
+
+static const struct snd_kcontrol_new es8316_dacsrc_mux_controls =
+	SOC_DAPM_ENUM("Route", es8316_dacsrc_mux_enum);
+
+static const struct snd_soc_dapm_widget es8316_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("DMIC"),
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_MICBIAS("micbias", SND_SOC_NOPM, 0, 0),
+
+	/* Input Mux */
+	SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+			 &es8316_analog_in_mux_controls),
+
+	SND_SOC_DAPM_PGA("Line input PGA", ES8316_ADC_PDN_LINSEL,
+			 7, 1, NULL, 0),
+	SND_SOC_DAPM_ADC("Mono ADC", NULL, ES8316_ADC_PDN_LINSEL, 6, 1),
+	SND_SOC_DAPM_MUX("Digital Mic Mux", SND_SOC_NOPM, 0, 0,
+			 &es8316_dmic_src_controls),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture",  1,
+			     ES8316_SERDATA_ADC, 6, 1),
+	SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0,
+			    SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MUX("DAC SRC Mux", SND_SOC_NOPM, 0, 0,
+			 &es8316_dacsrc_mux_controls),
+
+	SND_SOC_DAPM_DAC("Right DAC", NULL, SND_SOC_NOPM, 0, 1),
+	SND_SOC_DAPM_DAC("Left DAC", NULL, SND_SOC_NOPM, 4, 1),
+
+	/* Headphone Output Side */
+	SND_SOC_DAPM_MUX("Left Hp mux", SND_SOC_NOPM, 0, 0,
+			 &es8316_left_hpmux_controls),
+	SND_SOC_DAPM_MUX("Right Hp mux", SND_SOC_NOPM, 0, 0,
+			 &es8316_right_hpmux_controls),
+	SND_SOC_DAPM_MIXER("Left Hp mixer", SND_SOC_NOPM,
+			   4, 1, &es8316_out_left_mix[0],
+			   ARRAY_SIZE(es8316_out_left_mix)),
+	SND_SOC_DAPM_MIXER("Right Hp mixer", SND_SOC_NOPM,
+			   0, 1, &es8316_out_right_mix[0],
+			   ARRAY_SIZE(es8316_out_right_mix)),
+
+	/* Output charge pump */
+	SND_SOC_DAPM_PGA("HPCP L", SND_SOC_NOPM, 6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HPCP R", SND_SOC_NOPM, 2, 0, NULL, 0),
+
+	/* Output Driver */
+	SND_SOC_DAPM_PGA("HPVOL L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HPVOL R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_route es8316_dapm_routes[] = {
+	/* Recording */
+	{"MIC1", NULL, "micbias"},
+	{"MIC2", NULL, "micbias"},
+
+	{"Differential Mux", "lin1-rin1", "MIC1"},
+	{"Differential Mux", "lin2-rin2", "MIC2"},
+	{"Line input PGA", NULL, "Differential Mux"},
+
+	{"Mono ADC", NULL, "Line input PGA"},
+
+	{"Digital Mic Mux", "dmic disable", "Mono ADC"},
+
+	{"I2S OUT", NULL, "Digital Mic Mux"},
+
+	/* Playback */
+	{"DAC SRC Mux", "LDATA TO LDAC, RDATA TO RDAC", "I2S IN"},
+
+	{"Left DAC", NULL, "DAC SRC Mux"},
+	{"Right DAC", NULL, "DAC SRC Mux"},
+
+	{"Left Hp mux", "lin-rin with Boost and PGA", "Line input PGA"},
+	{"Right Hp mux", "lin-rin with Boost and PGA", "Line input PGA"},
+
+	{"Left Hp mixer", "LLIN Switch", "Left Hp mux"},
+	{"Left Hp mixer", "Left DAC Switch", "Left DAC"},
+
+	{"Right Hp mixer", "RLIN Switch", "Right Hp mux"},
+	{"Right Hp mixer", "Right DAC Switch", "Right DAC"},
+
+	{"HPCP L", NULL, "Left Hp mixer"},
+	{"HPCP R", NULL, "Right Hp mixer"},
+
+	{"HPVOL L", NULL, "HPCP L"},
+	{"HPVOL R", NULL, "HPCP R"},
+
+	{"HPOL", NULL, "HPVOL L"},
+	{"HPOR", NULL, "HPVOL R"},
+};
+
+static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
+	int i;
+
+	if (freq == 0)
+		return -EINVAL;
+
+	/* Limit supported sample rates to ones that can be autodetected
+	 * by the codec running in slave mode.
+	 */
+	for (i = 0; i < NR_SUPPORTED_MCLK_LRCK_RATIOS; i++) {
+		const unsigned int ratio = supported_mclk_lrck_ratios[i];
+
+		es8316->allowed_rates[i] = freq / ratio;
+	}
+
+	es8316->sysclk_constraints.list = es8316->allowed_rates;
+	es8316->sysclk_constraints.count = NR_SUPPORTED_MCLK_LRCK_RATIOS;
+	es8316->sysclk = freq;
+
+	return 0;
+}
+
+static int es8316_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 serdata1 = 0;
+	u8 serdata2 = 0;
+	u8 mask;
+
+	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+		dev_err(codec->dev, "Codec driver only supports slave mode\n");
+		return -EINVAL;
+	}
+
+	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
+		dev_err(codec->dev, "Codec driver only supports I2S format\n");
+		return -EINVAL;
+	}
+
+	/* Clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		serdata1 |= ES8316_SERDATA1_BCLK_INV;
+		serdata2 |= ES8316_SERDATA2_ADCLRP;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		serdata1 |= ES8316_SERDATA1_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		serdata2 |= ES8316_SERDATA2_ADCLRP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mask = ES8316_SERDATA1_MASTER | ES8316_SERDATA1_BCLK_INV;
+	snd_soc_update_bits(codec, ES8316_SERDATA1, mask, serdata1);
+
+	mask = ES8316_SERDATA2_FMT_MASK | ES8316_SERDATA2_ADCLRP;
+	snd_soc_update_bits(codec, ES8316_SERDATA_ADC, mask, serdata2);
+	snd_soc_update_bits(codec, ES8316_SERDATA_DAC, mask, serdata2);
+
+	return 0;
+}
+
+static int es8316_pcm_startup(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
+
+	/* The set of sample rates that can be supported depends on the
+	 * MCLK supplied to the CODEC.
+	 */
+	if (es8316->sysclk)
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+					   SNDRV_PCM_HW_PARAM_RATE,
+					   &es8316->sysclk_constraints);
+
+	return 0;
+}
+
+static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
+	u8 wordlen = 0;
+
+	if (!es8316->sysclk) {
+		dev_err(codec->dev, "No MCLK configured\n");
+		return -EINVAL;
+	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		wordlen = ES8316_SERDATA2_LEN_16;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		wordlen = ES8316_SERDATA2_LEN_20;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		wordlen = ES8316_SERDATA2_LEN_24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		wordlen = ES8316_SERDATA2_LEN_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, ES8316_SERDATA_DAC,
+			    ES8316_SERDATA2_LEN_MASK, wordlen);
+	snd_soc_update_bits(codec, ES8316_SERDATA_ADC,
+			    ES8316_SERDATA2_LEN_MASK, wordlen);
+	return 0;
+}
+
+static int es8316_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_update_bits(dai->codec, ES8316_DAC_SET1, 0x20,
+			    mute ? 0x20 : 0);
+	return 0;
+}
+
+static int es8316_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_write(codec, ES8316_RESET, 0xC0);
+		snd_soc_write(codec, ES8316_CPHP_OUTEN, 0x66);
+		snd_soc_write(codec, ES8316_DAC_PDN, 0x00);
+		snd_soc_write(codec, ES8316_CPHP_LDOCTL, 0x30);
+		snd_soc_write(codec, ES8316_CPHP_PDN2, 0x10);
+		snd_soc_write(codec, ES8316_CPHP_PDN1, 0x03);
+		snd_soc_write(codec, ES8316_HPMIX_PDN, 0x00);
+		snd_soc_update_bits(codec, ES8316_ADC_PDN_LINSEL, 0xc0, 0x00);
+		snd_soc_write(codec, ES8316_SYS_PDN, 0x00);
+		snd_soc_write(codec, ES8316_SYS_LP1, 0x04);
+		snd_soc_write(codec, ES8316_SYS_LP2, 0x0c);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_write(codec, ES8316_CPHP_OUTEN, 0x00);
+		snd_soc_write(codec, ES8316_DAC_PDN, 0x11);
+		snd_soc_write(codec, ES8316_CPHP_LDOCTL, 0x03);
+		snd_soc_write(codec, ES8316_CPHP_PDN2, 0x22);
+		snd_soc_write(codec, ES8316_CPHP_PDN1, 0x06);
+		snd_soc_write(codec, ES8316_HPMIX_PDN, 0x33);
+		snd_soc_update_bits(codec, ES8316_ADC_PDN_LINSEL, 0xc0, 0xc0);
+		snd_soc_write(codec, ES8316_SYS_PDN, 0x3f);
+		snd_soc_write(codec, ES8316_SYS_LP1, 0x3f);
+		snd_soc_write(codec, ES8316_SYS_LP2, 0x1f);
+		snd_soc_write(codec, ES8316_RESET, 0x00);
+		break;
+	}
+
+	return 0;
+}
+
+#define ES8316_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops es8316_ops = {
+	.startup = es8316_pcm_startup,
+	.hw_params = es8316_pcm_hw_params,
+	.set_fmt = es8316_set_dai_fmt,
+	.set_sysclk = es8316_set_dai_sysclk,
+	.digital_mute = es8316_mute,
+};
+
+static struct snd_soc_dai_driver es8316_dai = {
+	.name = "ES8316 HiFi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = ES8316_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = ES8316_FORMATS,
+	},
+	.ops = &es8316_ops,
+	.symmetric_rates = 1,
+};
+
+static int es8316_probe(struct snd_soc_codec *codec)
+{
+	snd_soc_write(codec, ES8316_RESET, 0x3f);
+	usleep_range(5000, 5500);
+	snd_soc_write(codec, ES8316_RESET, 0x00);
+	snd_soc_write(codec, ES8316_SYS_VMIDSEL, 0xFF);
+	msleep(30);
+
+	snd_soc_write(codec, ES8316_CLKMGR_CLKSEL, 0x08);
+	snd_soc_write(codec, ES8316_CLKMGR_ADCOSR, 0x20);
+	snd_soc_write(codec, ES8316_CLKMGR_ADCDIV1, 0x11);
+	snd_soc_write(codec, ES8316_CLKMGR_ADCDIV2, 0x00);
+	snd_soc_write(codec, ES8316_CLKMGR_DACDIV1, 0x11);
+	snd_soc_write(codec, ES8316_CLKMGR_DACDIV2, 0x00);
+	snd_soc_write(codec, ES8316_CLKMGR_CPDIV, 0x00);
+	snd_soc_write(codec, ES8316_SERDATA1, 0x04);
+	snd_soc_write(codec, ES8316_CLKMGR_CLKSW, 0x7f);
+	snd_soc_write(codec, ES8316_CAL_TYPE, 0x0F);
+	snd_soc_write(codec, ES8316_CAL_HPLIV, 0x90);
+	snd_soc_write(codec, ES8316_CAL_HPRIV, 0x90);
+	snd_soc_write(codec, ES8316_ADC_VOLUME, 0x00);
+	snd_soc_write(codec, ES8316_ADC_D2SEPGA, 0x00);
+	snd_soc_write(codec, ES8316_ADC_DMIC, 0x08);
+	snd_soc_write(codec, ES8316_DAC_SET2, 0x00);
+	snd_soc_write(codec, ES8316_DAC_SET3, 0x00);
+	snd_soc_write(codec, ES8316_DAC_VOLL, 0x02);
+	snd_soc_write(codec, ES8316_DAC_VOLR, 0x02);
+	snd_soc_write(codec, ES8316_SERDATA_ADC, 0x00);
+	snd_soc_write(codec, ES8316_SERDATA_DAC, 0x00);
+	snd_soc_write(codec, ES8316_SYS_VMIDLOW, 0x11);
+	snd_soc_write(codec, ES8316_SYS_VSEL, 0xfc);
+	snd_soc_write(codec, ES8316_SYS_REF, 0x28);
+	snd_soc_write(codec, ES8316_HPMIX_SEL, 0x00);
+	snd_soc_write(codec, ES8316_HPMIX_SWITCH, 0x88);
+	snd_soc_write(codec, ES8316_HPMIX_VOL, 0x88);
+	snd_soc_write(codec, ES8316_CPHP_ICAL_VOL, 0x00);
+	snd_soc_write(codec, ES8316_GPIO_SEL, 0x00);
+	snd_soc_write(codec, ES8316_GPIO_DEBUNCE_INT, 0x02);
+	snd_soc_write(codec, ES8316_TESTMODE, 0xa0);
+	snd_soc_write(codec, ES8316_TEST1, 0x00);
+	snd_soc_write(codec, ES8316_TEST2, 0x04);
+	snd_soc_write(codec, ES8316_RESET, 0xc0);
+	msleep(50);
+	snd_soc_write(codec, ES8316_ADC_PGAGAIN, 0x60);
+	snd_soc_write(codec, ES8316_ADC_D2SEPGA, 0x01);
+
+	/* ADC DS mode, HPF enable */
+	snd_soc_write(codec, ES8316_ADC_DMIC, 0x08);
+	snd_soc_write(codec, ES8316_ADC_ALC1, 0xcd);
+	snd_soc_write(codec, ES8316_ADC_ALC2, 0x08);
+	snd_soc_write(codec, ES8316_ADC_ALC3, 0xa0);
+	snd_soc_write(codec, ES8316_ADC_ALC4, 0x05);
+	snd_soc_write(codec, ES8316_ADC_ALC5, 0x06);
+	snd_soc_write(codec, ES8316_ADC_ALC6, 0x61);
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_es8316 = {
+	.probe		= es8316_probe,
+	.set_bias_level	= es8316_set_bias_level,
+	.idle_bias_off	= true,
+
+	.component_driver = {
+		.controls		= es8316_snd_controls,
+		.num_controls		= ARRAY_SIZE(es8316_snd_controls),
+		.dapm_widgets		= es8316_dapm_widgets,
+		.num_dapm_widgets	= ARRAY_SIZE(es8316_dapm_widgets),
+		.dapm_routes		= es8316_dapm_routes,
+		.num_dapm_routes	= ARRAY_SIZE(es8316_dapm_routes),
+	},
+};
+
+static const struct regmap_config es8316_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = 0x53,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int es8316_i2c_probe(struct i2c_client *i2c_client,
+			    const struct i2c_device_id *id)
+{
+	struct es8316_priv *es8316;
+	struct regmap *regmap;
+
+	es8316 = devm_kzalloc(&i2c_client->dev, sizeof(struct es8316_priv),
+			      GFP_KERNEL);
+	if (es8316 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c_client, es8316);
+
+	regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return snd_soc_register_codec(&i2c_client->dev, &soc_codec_dev_es8316,
+				      &es8316_dai, 1);
+}
+
+static int es8316_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id es8316_i2c_id[] = {
+	{"ESSX8316", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, es8316_i2c_id);
+
+static const struct of_device_id es8316_of_match[] = {
+	{ .compatible = "everest,es8316", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, es8316_of_match);
+
+static const struct acpi_device_id es8316_acpi_match[] = {
+	{"ESSX8316", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, es8316_acpi_match);
+
+static struct i2c_driver es8316_i2c_driver = {
+	.driver = {
+		.name			= "es8316",
+		.acpi_match_table	= ACPI_PTR(es8316_acpi_match),
+		.of_match_table		= of_match_ptr(es8316_of_match),
+	},
+	.probe		= es8316_i2c_probe,
+	.remove		= es8316_i2c_remove,
+	.id_table	= es8316_i2c_id,
+};
+module_i2c_driver(es8316_i2c_driver);
+
+MODULE_DESCRIPTION("Everest Semi ES8316 ALSA SoC Codec Driver");
+MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/es8316.h b/sound/soc/codecs/es8316.h
new file mode 100644
index 000000000000..702bebc69ca8
--- /dev/null
+++ b/sound/soc/codecs/es8316.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright Everest Semiconductor Co.,Ltd
+ *
+ * Author: 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.
+ *
+ */
+
+#ifndef _ES8316_H
+#define _ES8316_H
+
+/*
+ * ES8316 register space
+ */
+
+/* Reset Control */
+#define ES8316_RESET		0x00
+
+/* Clock Management */
+#define ES8316_CLKMGR_CLKSW	0x01
+#define ES8316_CLKMGR_CLKSEL	0x02
+#define ES8316_CLKMGR_ADCOSR	0x03
+#define ES8316_CLKMGR_ADCDIV1	0x04
+#define ES8316_CLKMGR_ADCDIV2	0x05
+#define ES8316_CLKMGR_DACDIV1	0x06
+#define ES8316_CLKMGR_DACDIV2	0x07
+#define ES8316_CLKMGR_CPDIV	0x08
+
+/* Serial Data Port Control */
+#define ES8316_SERDATA1		0x09
+#define ES8316_SERDATA_ADC	0x0a
+#define ES8316_SERDATA_DAC	0x0b
+
+/* System Control */
+#define ES8316_SYS_VMIDSEL	0x0c
+#define ES8316_SYS_PDN		0x0d
+#define ES8316_SYS_LP1		0x0e
+#define ES8316_SYS_LP2		0x0f
+#define ES8316_SYS_VMIDLOW	0x10
+#define ES8316_SYS_VSEL		0x11
+#define ES8316_SYS_REF		0x12
+
+/* Headphone Mixer */
+#define ES8316_HPMIX_SEL	0x13
+#define ES8316_HPMIX_SWITCH	0x14
+#define ES8316_HPMIX_PDN	0x15
+#define ES8316_HPMIX_VOL	0x16
+
+/* Charge Pump Headphone driver */
+#define ES8316_CPHP_OUTEN	0x17
+#define ES8316_CPHP_ICAL_VOL	0x18
+#define ES8316_CPHP_PDN1	0x19
+#define ES8316_CPHP_PDN2	0x1a
+#define ES8316_CPHP_LDOCTL	0x1b
+
+/* Calibration */
+#define ES8316_CAL_TYPE		0x1c
+#define ES8316_CAL_SET		0x1d
+#define ES8316_CAL_HPLIV	0x1e
+#define ES8316_CAL_HPRIV	0x1f
+#define ES8316_CAL_HPLMV	0x20
+#define ES8316_CAL_HPRMV	0x21
+
+/* ADC Control */
+#define ES8316_ADC_PDN_LINSEL	0x22
+#define ES8316_ADC_PGAGAIN	0x23
+#define ES8316_ADC_D2SEPGA	0x24
+#define ES8316_ADC_DMIC		0x25
+#define ES8316_ADC_MUTE		0x26
+#define ES8316_ADC_VOLUME	0x27
+#define ES8316_ADC_ALC1		0x29
+#define ES8316_ADC_ALC2		0x2a
+#define ES8316_ADC_ALC3		0x2b
+#define ES8316_ADC_ALC4		0x2c
+#define ES8316_ADC_ALC5		0x2d
+#define ES8316_ADC_ALC6		0x2e
+
+/* DAC Control */
+#define ES8316_DAC_PDN		0x2f
+#define ES8316_DAC_SET1		0x30
+#define ES8316_DAC_SET2		0x31
+#define ES8316_DAC_SET3		0x32
+#define ES8316_DAC_VOLL		0x33
+#define ES8316_DAC_VOLR		0x34
+
+/* GPIO */
+#define ES8316_GPIO_SEL		0x4d
+#define ES8316_GPIO_DEBUNCE_INT 0x4e
+#define ES8316_GPIO_FLAG	0x4f
+
+/* Test mode */
+#define ES8316_TESTMODE		0x50
+#define ES8316_TEST1		0x51
+#define ES8316_TEST2		0x52
+#define ES8316_TEST3		0x53
+
+/*
+ * Field definitions
+ */
+
+/* ES8316_SERDATA1 */
+#define ES8316_SERDATA1_MASTER		0x80
+#define ES8316_SERDATA1_BCLK_INV	0x20
+
+/* ES8316_SERDATA_ADC and _DAC */
+#define ES8316_SERDATA2_FMT_MASK	0x3
+#define ES8316_SERDATA2_FMT_I2S		0x00
+#define ES8316_SERDATA2_FMT_LEFTJ	0x01
+#define ES8316_SERDATA2_FMT_RIGHTJ	0x02
+#define ES8316_SERDATA2_FMT_PCM		0x03
+#define ES8316_SERDATA2_ADCLRP		0x20
+#define ES8316_SERDATA2_LEN_MASK	0x1c
+#define ES8316_SERDATA2_LEN_24		0x00
+#define ES8316_SERDATA2_LEN_20		0x04
+#define ES8316_SERDATA2_LEN_18		0x08
+#define ES8316_SERDATA2_LEN_16		0x0c
+#define ES8316_SERDATA2_LEN_32		0x10
+
+#endif
-- 
2.11.0

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

* [PATCH 2/2] ASoC: Intel: add machine driver for BYT/CHT + ES8316
  2017-05-10 18:16 [PATCH 1/2] ASoC: add es8316 codec driver Daniel Drake
@ 2017-05-10 18:16 ` Daniel Drake
  2017-05-10 18:49   ` Pierre-Louis Bossart
  2017-05-10 18:49 ` [PATCH 1/2] ASoC: add es8316 codec driver Pierre-Louis Bossart
  1 sibling, 1 reply; 8+ messages in thread
From: Daniel Drake @ 2017-05-10 18:16 UTC (permalink / raw)
  To: lgirdwood, broonie; +Cc: alsa-devel, linux, pierre-louis.bossart, yangxiaohua

Add new machine driver, tested with Weibu F3C MiniPC.

Based heavily on code provided by David Yang @ Everest, and other
machine drivers in the same directory.

Signed-off-by: Daniel Drake <drake@endlessm.com>
---
 sound/soc/intel/Kconfig                |  12 ++
 sound/soc/intel/atom/sst/sst_acpi.c    |   2 +
 sound/soc/intel/boards/Makefile        |   2 +
 sound/soc/intel/boards/bytcht_es8316.c | 338 +++++++++++++++++++++++++++++++++
 4 files changed, 354 insertions(+)
 create mode 100644 sound/soc/intel/boards/bytcht_es8316.c

diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 67968ef3bbda..013f056c6c12 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -214,6 +214,18 @@ config SND_SOC_INTEL_BYT_CHT_DA7213_MACH
 	  platforms with DA7212/7213 audio codec.
 	  If unsure select "N".
 
+config SND_SOC_INTEL_BYT_CHT_ES8316_MACH
+	tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with ES8316 codec"
+	depends on X86_INTEL_LPSS && I2C && ACPI
+	select SND_SOC_ES8316
+	select SND_SST_ATOM_HIFI2_PLATFORM
+	select SND_SST_IPC_ACPI
+	select SND_SOC_INTEL_SST_MATCH if ACPI
+	help
+	  This adds support for ASoC machine driver for Intel(R) Baytrail &
+	  Cherrytrail platforms with ES8316 audio codec.
+	  If unsure select "N".
+
 config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
 	tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)"
 	depends on X86_INTEL_LPSS && I2C && ACPI
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index dd250b8b26f2..e0b7346cbb16 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -533,6 +533,8 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
 						&chv_platform_data },
 	{"DLGS7213", "bytcht_da7213", "intel/fw_sst_22a8.bin", "bytcht_da7213", NULL,
 						&chv_platform_data },
+	{"ESSX8316", "bytcht_es8316", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
+						&chv_platform_data },
 	/* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
 	{"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk,
 						&chv_platform_data },
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 56896e09445d..0cca726d249b 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -11,6 +11,7 @@ snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
 snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
 snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o
 snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o
+snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o
 snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o
 snd-soc-skl_rt286-objs := skl_rt286.o
 snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
@@ -29,6 +30,7 @@ obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o
 obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o
+obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o
 obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o
 obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
 obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
new file mode 100644
index 000000000000..5e94e0befa34
--- /dev/null
+++ b/sound/soc/intel/boards/bytcht_es8316.c
@@ -0,0 +1,338 @@
+/*
+ *  bytbyt_cht_es8316.c - ASoc Machine driver for Intel Baytrail/Cherrytrail
+ *                    platforms with Everest ES8316 SoC
+ *
+ *  Copyright (C) 2017 Endless Mobile, Inc.
+ *  Authors: David Yang <yangxiaohua@everest-semi.com>,
+ *           Daniel Drake <drake@endlessm.com>
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <asm/platform_sst_audio.h>
+#include <linux/clk.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../atom/sst-atom-controls.h"
+#include "../common/sst-acpi.h"
+#include "../common/sst-dsp.h"
+
+struct byt_cht_es8316_private {
+	struct clk *mclk;
+};
+
+#define CODEC_DAI1	"ES8316 HiFi"
+
+static inline struct snd_soc_dai *get_codec_dai(struct snd_soc_card *card)
+{
+	struct snd_soc_pcm_runtime *rtd;
+
+	list_for_each_entry(rtd, &card->rtd_list, list) {
+		if (!strncmp(rtd->codec_dai->name, CODEC_DAI1,
+			     strlen(CODEC_DAI1)))
+			return rtd->codec_dai;
+	}
+	return NULL;
+}
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *k, int event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct snd_soc_dai *codec_dai = get_codec_dai(card);
+	struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card);
+
+	if (!codec_dai) {
+		dev_err(card->dev,
+			"Codec dai not found; Unable to set platform clock\n");
+		return -EIO;
+	}
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		int ret = clk_prepare_enable(priv->mclk);
+
+		if (ret < 0) {
+			dev_err(card->dev,
+				"could not configure MCLK state");
+			return ret;
+		}
+	} else {
+		clk_disable_unprepare(priv->mclk);
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone", NULL),
+	SND_SOC_DAPM_MIC("Microphone 1", NULL),
+	SND_SOC_DAPM_MIC("Microphone 2", NULL),
+	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+			    platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = {
+	{"MIC1", NULL, "Microphone 1"},
+	{"MIC2", NULL, "Microphone 2"},
+
+	{"Headphone", NULL, "HPOL"},
+	{"Headphone", NULL, "HPOR"},
+
+	{"Playback", NULL, "ssp2 Tx"},
+	{"ssp2 Tx", NULL, "codec_out0"},
+	{"ssp2 Tx", NULL, "codec_out1"},
+	{"codec_in0", NULL, "ssp2 Rx" },
+	{"codec_in1", NULL, "ssp2 Rx" },
+	{"ssp2 Rx", NULL, "Capture"},
+
+	{"Headphone", NULL, "Platform Clock"},
+	{"Microphone 1", NULL, "Platform Clock"},
+	{"Microphone 2", NULL, "Platform Clock"},
+};
+
+static const struct snd_kcontrol_new byt_cht_es8316_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone"),
+	SOC_DAPM_PIN_SWITCH("Microphone 1"),
+	SOC_DAPM_PIN_SWITCH("Microphone 2"),
+};
+
+static int byt_cht_es8316_aif1_hw_params(struct snd_pcm_substream *substream,
+					 struct snd_pcm_hw_params *params)
+
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int ret;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, 19200000, SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set codec clock %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime)
+{
+	struct snd_soc_card *card = runtime->card;
+	struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card);
+	int ret;
+
+	card->dapm.idle_bias_off = true;
+
+	/*
+	 * The firmware might enable the clock at boot (this information
+	 * may or may not be reflected in the enable clock register).
+	 * To change the rate we must disable the clock first to cover these
+	 * cases. Due to common clock framework restrictions that do not allow
+	 * to disable a clock that has not been enabled, we need to enable
+	 * the clock first.
+	 */
+	ret = clk_prepare_enable(priv->mclk);
+	if (!ret)
+		clk_disable_unprepare(priv->mclk);
+
+	ret = clk_set_rate(priv->mclk, 19200000);
+	if (ret)
+		dev_err(card->dev, "unable to set MCLK rate\n");
+
+	return 0;
+}
+
+static const struct snd_soc_pcm_stream byt_cht_es8316_dai_params = {
+	.formats = SNDRV_PCM_FMTBIT_S24_LE,
+	.rate_min = 48000,
+	.rate_max = 48000,
+	.channels_min = 2,
+	.channels_max = 2,
+};
+
+static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+			    struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+						SNDRV_PCM_HW_PARAM_CHANNELS);
+	int ret;
+
+	/* The DSP will covert the FE rate to 48k, stereo */
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	/* set SSP2 to 24-bit */
+	params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+
+	/*
+	 * Default mode for SSP configuration is TDM 4 slot, override config
+	 * with explicit setting to I2S 2ch 24-bit. The word length is set with
+	 * dai_set_tdm_slot() since there is no other API exposed
+	 */
+	ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
+				SND_SOC_DAIFMT_I2S     |
+				SND_SOC_DAIFMT_NB_NF   |
+				SND_SOC_DAIFMT_CBS_CFS
+		);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int byt_cht_es8316_aif1_startup(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_hw_constraint_single(substream->runtime,
+			SNDRV_PCM_HW_PARAM_RATE, 48000);
+}
+
+static const struct snd_soc_ops byt_cht_es8316_aif1_ops = {
+	.startup = byt_cht_es8316_aif1_startup,
+};
+
+static const struct snd_soc_ops byt_cht_es8316_be_ssp2_ops = {
+	.hw_params = byt_cht_es8316_aif1_hw_params,
+};
+
+static struct snd_soc_dai_link byt_cht_es8316_dais[] = {
+	[MERR_DPCM_AUDIO] = {
+		.name = "Audio Port",
+		.stream_name = "Audio",
+		.cpu_dai_name = "media-cpu-dai",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.platform_name = "sst-mfld-platform",
+		.nonatomic = true,
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.ops = &byt_cht_es8316_aif1_ops,
+	},
+
+	[MERR_DPCM_DEEP_BUFFER] = {
+		.name = "Deep-Buffer Audio Port",
+		.stream_name = "Deep-Buffer Audio",
+		.cpu_dai_name = "deepbuffer-cpu-dai",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.platform_name = "sst-mfld-platform",
+		.nonatomic = true,
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.ops = &byt_cht_es8316_aif1_ops,
+	},
+
+	[MERR_DPCM_COMPR] = {
+		.name = "Compressed Port",
+		.stream_name = "Compress",
+		.cpu_dai_name = "compress-cpu-dai",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.platform_name = "sst-mfld-platform",
+	},
+
+		/* back ends */
+	{
+		.name = "SSP2-Codec",
+		.id = 1,
+		.cpu_dai_name = "ssp2-port",
+		.platform_name = "sst-mfld-platform",
+		.no_pcm = 1,
+		.codec_dai_name = "ES8316 HiFi",
+		.codec_name = "i2c-ESSX8316:00",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+						| SND_SOC_DAIFMT_CBS_CFS,
+		.be_hw_params_fixup = byt_cht_es8316_codec_fixup,
+		.nonatomic = true,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.init = byt_cht_es8316_init,
+		.ops = &byt_cht_es8316_be_ssp2_ops,
+	},
+};
+
+
+/* SoC card */
+static struct snd_soc_card byt_cht_es8316_card = {
+	.name = "bytcht-es8316",
+	.owner = THIS_MODULE,
+	.dai_link = byt_cht_es8316_dais,
+	.num_links = ARRAY_SIZE(byt_cht_es8316_dais),
+	.dapm_widgets = byt_cht_es8316_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(byt_cht_es8316_widgets),
+	.dapm_routes = byt_cht_es8316_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(byt_cht_es8316_audio_map),
+	.controls = byt_cht_es8316_controls,
+	.num_controls = ARRAY_SIZE(byt_cht_es8316_controls),
+	.fully_routed = true,
+};
+
+static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct byt_cht_es8316_private *priv;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
+	if (!priv)
+		return -ENOMEM;
+
+	/* register the soc card */
+	byt_cht_es8316_card.dev = &pdev->dev;
+	snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv);
+
+	priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
+	if (IS_ERR(priv->mclk)) {
+		ret = PTR_ERR(priv->mclk);
+		dev_err(&pdev->dev,
+			"Failed to get MCLK from pmc_plt_clk_3: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_card(&pdev->dev, &byt_cht_es8316_card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret);
+		return ret;
+	}
+	platform_set_drvdata(pdev, &byt_cht_es8316_card);
+	return ret;
+}
+
+static struct platform_driver snd_byt_cht_es8316_mc_driver = {
+	.driver = {
+		.name = "bytcht_es8316",
+	},
+	.probe = snd_byt_cht_es8316_mc_probe,
+};
+
+module_platform_driver(snd_byt_cht_es8316_mc_driver);
+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Machine driver");
+MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bytcht_es8316");
-- 
2.11.0

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

* Re: [PATCH 2/2] ASoC: Intel: add machine driver for BYT/CHT + ES8316
  2017-05-10 18:16 ` [PATCH 2/2] ASoC: Intel: add machine driver for BYT/CHT + ES8316 Daniel Drake
@ 2017-05-10 18:49   ` Pierre-Louis Bossart
  2017-05-15 18:07     ` Daniel Drake
  0 siblings, 1 reply; 8+ messages in thread
From: Pierre-Louis Bossart @ 2017-05-10 18:49 UTC (permalink / raw)
  To: Daniel Drake, lgirdwood, broonie; +Cc: alsa-devel, linux, yangxiaohua

On 5/10/17 1:16 PM, Daniel Drake wrote:
> Add new machine driver, tested with Weibu F3C MiniPC.

You may want to add a comment that this patch is based on the use of 
SSP2 and hence cannot work on BYT-CR devices.

>
> Based heavily on code provided by David Yang @ Everest, and other
> machine drivers in the same directory.
>
> Signed-off-by: Daniel Drake <drake@endlessm.com>
> ---
>  sound/soc/intel/Kconfig                |  12 ++
>  sound/soc/intel/atom/sst/sst_acpi.c    |   2 +
>  sound/soc/intel/boards/Makefile        |   2 +
>  sound/soc/intel/boards/bytcht_es8316.c | 338 +++++++++++++++++++++++++++++++++
>  4 files changed, 354 insertions(+)
>  create mode 100644 sound/soc/intel/boards/bytcht_es8316.c
>
> diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
> index 67968ef3bbda..013f056c6c12 100644
> --- a/sound/soc/intel/Kconfig
> +++ b/sound/soc/intel/Kconfig
> @@ -214,6 +214,18 @@ config SND_SOC_INTEL_BYT_CHT_DA7213_MACH
>  	  platforms with DA7212/7213 audio codec.
>  	  If unsure select "N".
>
> +config SND_SOC_INTEL_BYT_CHT_ES8316_MACH
> +	tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with ES8316 codec"
> +	depends on X86_INTEL_LPSS && I2C && ACPI
> +	select SND_SOC_ES8316
> +	select SND_SST_ATOM_HIFI2_PLATFORM
> +	select SND_SST_IPC_ACPI
> +	select SND_SOC_INTEL_SST_MATCH if ACPI
> +	help
> +	  This adds support for ASoC machine driver for Intel(R) Baytrail &
> +	  Cherrytrail platforms with ES8316 audio codec.
> +	  If unsure select "N".
> +
>  config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
>  	tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)"
>  	depends on X86_INTEL_LPSS && I2C && ACPI
> diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
> index dd250b8b26f2..e0b7346cbb16 100644
> --- a/sound/soc/intel/atom/sst/sst_acpi.c
> +++ b/sound/soc/intel/atom/sst/sst_acpi.c
> @@ -533,6 +533,8 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
>  						&chv_platform_data },
>  	{"DLGS7213", "bytcht_da7213", "intel/fw_sst_22a8.bin", "bytcht_da7213", NULL,
>  						&chv_platform_data },
> +	{"ESSX8316", "bytcht_es8316", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
> +						&chv_platform_data },
>  	/* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
>  	{"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk,
>  						&chv_platform_data },
> diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
> index 56896e09445d..0cca726d249b 100644
> --- a/sound/soc/intel/boards/Makefile
> +++ b/sound/soc/intel/boards/Makefile
> @@ -11,6 +11,7 @@ snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
>  snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
>  snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o
>  snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o
> +snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o
>  snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o
>  snd-soc-skl_rt286-objs := skl_rt286.o
>  snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
> @@ -29,6 +30,7 @@ obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
>  obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
>  obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o
>  obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o
> +obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o
>  obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o
>  obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
>  obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
> diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
> new file mode 100644
> index 000000000000..5e94e0befa34
> --- /dev/null
> +++ b/sound/soc/intel/boards/bytcht_es8316.c
> @@ -0,0 +1,338 @@
> +/*
> + *  bytbyt_cht_es8316.c - ASoc Machine driver for Intel Baytrail/Cherrytrail

typo bytbyt

> + *                    platforms with Everest ES8316 SoC
> + *
> + *  Copyright (C) 2017 Endless Mobile, Inc.
> + *  Authors: David Yang <yangxiaohua@everest-semi.com>,

same comment about the signoff.

> + *           Daniel Drake <drake@endlessm.com>
> + *
> + *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; version 2 of the License.
> + *
> + *  This program is distributed in the hope that it will be useful, but
> + *  WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  General Public License for more details.
> + *
> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + */
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/device.h>
> +#include <linux/slab.h>
> +#include <asm/platform_sst_audio.h>
> +#include <linux/clk.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
> +#include "../atom/sst-atom-controls.h"
> +#include "../common/sst-acpi.h"
> +#include "../common/sst-dsp.h"
> +
> +struct byt_cht_es8316_private {
> +	struct clk *mclk;
> +};
> +
> +#define CODEC_DAI1	"ES8316 HiFi"
> +
> +static inline struct snd_soc_dai *get_codec_dai(struct snd_soc_card *card)
> +{
> +	struct snd_soc_pcm_runtime *rtd;
> +
> +	list_for_each_entry(rtd, &card->rtd_list, list) {
> +		if (!strncmp(rtd->codec_dai->name, CODEC_DAI1,
> +			     strlen(CODEC_DAI1)))
> +			return rtd->codec_dai;
> +	}
> +	return NULL;
> +}
> +
> +static int platform_clock_control(struct snd_soc_dapm_widget *w,
> +				  struct snd_kcontrol *k, int event)
> +{
> +	struct snd_soc_dapm_context *dapm = w->dapm;
> +	struct snd_soc_card *card = dapm->card;
> +	struct snd_soc_dai *codec_dai = get_codec_dai(card);
> +	struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card);
> +
> +	if (!codec_dai) {
> +		dev_err(card->dev,
> +			"Codec dai not found; Unable to set platform clock\n");
> +		return -EIO;
> +	}
> +
> +	if (SND_SOC_DAPM_EVENT_ON(event)) {
> +		int ret = clk_prepare_enable(priv->mclk);
> +
> +		if (ret < 0) {
> +			dev_err(card->dev,
> +				"could not configure MCLK state");
> +			return ret;
> +		}
> +	} else {
> +		clk_disable_unprepare(priv->mclk);

what is the behavior on the codec side if the sysclk is set to 19.2 MHz 
but the MCLK is stopped?

> +	}
> +
> +	return 0;
> +}
> +
> +static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = {
> +	SND_SOC_DAPM_HP("Headphone", NULL),
> +	SND_SOC_DAPM_MIC("Microphone 1", NULL),
> +	SND_SOC_DAPM_MIC("Microphone 2", NULL),
> +	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
> +			    platform_clock_control, SND_SOC_DAPM_PRE_PMU |
> +			    SND_SOC_DAPM_POST_PMD),
> +};
> +
> +static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = {
> +	{"MIC1", NULL, "Microphone 1"},
> +	{"MIC2", NULL, "Microphone 2"},
> +
> +	{"Headphone", NULL, "HPOL"},
> +	{"Headphone", NULL, "HPOR"},
> +
> +	{"Playback", NULL, "ssp2 Tx"},
> +	{"ssp2 Tx", NULL, "codec_out0"},
> +	{"ssp2 Tx", NULL, "codec_out1"},
> +	{"codec_in0", NULL, "ssp2 Rx" },
> +	{"codec_in1", NULL, "ssp2 Rx" },
> +	{"ssp2 Rx", NULL, "Capture"},
> +
> +	{"Headphone", NULL, "Platform Clock"},
> +	{"Microphone 1", NULL, "Platform Clock"},
> +	{"Microphone 2", NULL, "Platform Clock"},
> +};
> +
> +static const struct snd_kcontrol_new byt_cht_es8316_controls[] = {
> +	SOC_DAPM_PIN_SWITCH("Headphone"),
> +	SOC_DAPM_PIN_SWITCH("Microphone 1"),
> +	SOC_DAPM_PIN_SWITCH("Microphone 2"),

do you really need to control the two analog mics independently? And 
along the same lines, should there be a path for DMICS?

> +};
> +
> +static int byt_cht_es8316_aif1_hw_params(struct snd_pcm_substream *substream,
> +					 struct snd_pcm_hw_params *params)
> +
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_dai *codec_dai = rtd->codec_dai;
> +	int ret;
> +
> +	ret = snd_soc_dai_set_sysclk(codec_dai, 0, 19200000, SND_SOC_CLOCK_IN);
> +	if (ret < 0) {
> +		dev_err(rtd->dev, "can't set codec clock %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime)
> +{
> +	struct snd_soc_card *card = runtime->card;
> +	struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card);
> +	int ret;
> +
> +	card->dapm.idle_bias_off = true;
> +
> +	/*
> +	 * The firmware might enable the clock at boot (this information
> +	 * may or may not be reflected in the enable clock register).
> +	 * To change the rate we must disable the clock first to cover these
> +	 * cases. Due to common clock framework restrictions that do not allow
> +	 * to disable a clock that has not been enabled, we need to enable
> +	 * the clock first.
> +	 */
> +	ret = clk_prepare_enable(priv->mclk);
> +	if (!ret)
> +		clk_disable_unprepare(priv->mclk);
> +
> +	ret = clk_set_rate(priv->mclk, 19200000);
> +	if (ret)
> +		dev_err(card->dev, "unable to set MCLK rate\n");
> +
> +	return 0;
> +}
> +
> +static const struct snd_soc_pcm_stream byt_cht_es8316_dai_params = {
> +	.formats = SNDRV_PCM_FMTBIT_S24_LE,
> +	.rate_min = 48000,
> +	.rate_max = 48000,
> +	.channels_min = 2,
> +	.channels_max = 2,
> +};
> +
> +static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd,
> +			    struct snd_pcm_hw_params *params)
> +{
> +	struct snd_interval *rate = hw_param_interval(params,
> +			SNDRV_PCM_HW_PARAM_RATE);
> +	struct snd_interval *channels = hw_param_interval(params,
> +						SNDRV_PCM_HW_PARAM_CHANNELS);
> +	int ret;
> +
> +	/* The DSP will covert the FE rate to 48k, stereo */
> +	rate->min = rate->max = 48000;
> +	channels->min = channels->max = 2;
> +
> +	/* set SSP2 to 24-bit */
> +	params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
> +
> +	/*
> +	 * Default mode for SSP configuration is TDM 4 slot, override config
> +	 * with explicit setting to I2S 2ch 24-bit. The word length is set with
> +	 * dai_set_tdm_slot() since there is no other API exposed
> +	 */
> +	ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
> +				SND_SOC_DAIFMT_I2S     |
> +				SND_SOC_DAIFMT_NB_NF   |
> +				SND_SOC_DAIFMT_CBS_CFS
> +		);
> +	if (ret < 0) {
> +		dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24);
> +	if (ret < 0) {
> +		dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int byt_cht_es8316_aif1_startup(struct snd_pcm_substream *substream)
> +{
> +	return snd_pcm_hw_constraint_single(substream->runtime,
> +			SNDRV_PCM_HW_PARAM_RATE, 48000);
> +}
> +
> +static const struct snd_soc_ops byt_cht_es8316_aif1_ops = {
> +	.startup = byt_cht_es8316_aif1_startup,
> +};
> +
> +static const struct snd_soc_ops byt_cht_es8316_be_ssp2_ops = {
> +	.hw_params = byt_cht_es8316_aif1_hw_params,
> +};
> +
> +static struct snd_soc_dai_link byt_cht_es8316_dais[] = {
> +	[MERR_DPCM_AUDIO] = {
> +		.name = "Audio Port",
> +		.stream_name = "Audio",
> +		.cpu_dai_name = "media-cpu-dai",
> +		.codec_dai_name = "snd-soc-dummy-dai",
> +		.codec_name = "snd-soc-dummy",
> +		.platform_name = "sst-mfld-platform",
> +		.nonatomic = true,
> +		.dynamic = 1,
> +		.dpcm_playback = 1,
> +		.dpcm_capture = 1,
> +		.ops = &byt_cht_es8316_aif1_ops,
> +	},
> +
> +	[MERR_DPCM_DEEP_BUFFER] = {
> +		.name = "Deep-Buffer Audio Port",
> +		.stream_name = "Deep-Buffer Audio",
> +		.cpu_dai_name = "deepbuffer-cpu-dai",
> +		.codec_dai_name = "snd-soc-dummy-dai",
> +		.codec_name = "snd-soc-dummy",
> +		.platform_name = "sst-mfld-platform",
> +		.nonatomic = true,
> +		.dynamic = 1,
> +		.dpcm_playback = 1,
> +		.ops = &byt_cht_es8316_aif1_ops,
> +	},
> +
> +	[MERR_DPCM_COMPR] = {
> +		.name = "Compressed Port",
> +		.stream_name = "Compress",
> +		.cpu_dai_name = "compress-cpu-dai",
> +		.codec_dai_name = "snd-soc-dummy-dai",
> +		.codec_name = "snd-soc-dummy",
> +		.platform_name = "sst-mfld-platform",
> +	},
> +
> +		/* back ends */
> +	{
> +		.name = "SSP2-Codec",
> +		.id = 1,
> +		.cpu_dai_name = "ssp2-port",
> +		.platform_name = "sst-mfld-platform",
> +		.no_pcm = 1,
> +		.codec_dai_name = "ES8316 HiFi",
> +		.codec_name = "i2c-ESSX8316:00",
> +		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
> +						| SND_SOC_DAIFMT_CBS_CFS,
> +		.be_hw_params_fixup = byt_cht_es8316_codec_fixup,
> +		.nonatomic = true,
> +		.dpcm_playback = 1,
> +		.dpcm_capture = 1,
> +		.init = byt_cht_es8316_init,
> +		.ops = &byt_cht_es8316_be_ssp2_ops,
> +	},
> +};
> +
> +
> +/* SoC card */
> +static struct snd_soc_card byt_cht_es8316_card = {
> +	.name = "bytcht-es8316",
> +	.owner = THIS_MODULE,
> +	.dai_link = byt_cht_es8316_dais,
> +	.num_links = ARRAY_SIZE(byt_cht_es8316_dais),
> +	.dapm_widgets = byt_cht_es8316_widgets,
> +	.num_dapm_widgets = ARRAY_SIZE(byt_cht_es8316_widgets),
> +	.dapm_routes = byt_cht_es8316_audio_map,
> +	.num_dapm_routes = ARRAY_SIZE(byt_cht_es8316_audio_map),
> +	.controls = byt_cht_es8316_controls,
> +	.num_controls = ARRAY_SIZE(byt_cht_es8316_controls),
> +	.fully_routed = true,
> +};
> +
> +static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
> +{
> +	int ret = 0;
> +	struct byt_cht_es8316_private *priv;
> +
> +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	/* register the soc card */
> +	byt_cht_es8316_card.dev = &pdev->dev;
> +	snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv);
> +
> +	priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
> +	if (IS_ERR(priv->mclk)) {
> +		ret = PTR_ERR(priv->mclk);
> +		dev_err(&pdev->dev,
> +			"Failed to get MCLK from pmc_plt_clk_3: %d\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	ret = devm_snd_soc_register_card(&pdev->dev, &byt_cht_es8316_card);
> +	if (ret) {
> +		dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret);
> +		return ret;
> +	}
> +	platform_set_drvdata(pdev, &byt_cht_es8316_card);
> +	return ret;
> +}
> +
> +static struct platform_driver snd_byt_cht_es8316_mc_driver = {
> +	.driver = {
> +		.name = "bytcht_es8316",
> +	},
> +	.probe = snd_byt_cht_es8316_mc_probe,
> +};
> +
> +module_platform_driver(snd_byt_cht_es8316_mc_driver);
> +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Machine driver");
> +MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:bytcht_es8316");
>

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

* Re: [PATCH 1/2] ASoC: add es8316 codec driver
  2017-05-10 18:16 [PATCH 1/2] ASoC: add es8316 codec driver Daniel Drake
  2017-05-10 18:16 ` [PATCH 2/2] ASoC: Intel: add machine driver for BYT/CHT + ES8316 Daniel Drake
@ 2017-05-10 18:49 ` Pierre-Louis Bossart
  2017-05-10 19:18   ` Daniel Drake
  1 sibling, 1 reply; 8+ messages in thread
From: Pierre-Louis Bossart @ 2017-05-10 18:49 UTC (permalink / raw)
  To: Daniel Drake, lgirdwood, broonie; +Cc: alsa-devel, linux, yangxiaohua

On 5/10/17 1:16 PM, Daniel Drake wrote:
> Add a codec driver for the Everest ES8316, based on code provided by
> David Yang from Everest Semi.
>
> I limited the functionality to items where the vendor code was clear,
> and things that can be tested on the Weibu F3C (Intel Cherry Trail).
> As a result the initial implementation only supports running in slave
> mode at single speed (up to 48kHz sample rate) using I2S. HPD is not
> supported.
>
> Signed-off-by: Daniel Drake <drake@endlessm.com>
> ---
>  sound/soc/codecs/Kconfig  |   4 +
>  sound/soc/codecs/Makefile |   2 +
>  sound/soc/codecs/es8316.c | 639 ++++++++++++++++++++++++++++++++++++++++++++++
>  sound/soc/codecs/es8316.h | 122 +++++++++
>  4 files changed, 767 insertions(+)
>  create mode 100644 sound/soc/codecs/es8316.c
>  create mode 100644 sound/soc/codecs/es8316.h
>
> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
> index 883ed4c8a551..c6286e5ba511 100644
> --- a/sound/soc/codecs/Kconfig
> +++ b/sound/soc/codecs/Kconfig
> @@ -72,6 +72,7 @@ config SND_SOC_ALL_CODECS
>  	select SND_SOC_DA9055 if I2C
>  	select SND_SOC_DIO2125
>  	select SND_SOC_DMIC
> +	select SND_SOC_ES8316 if I2C
>  	select SND_SOC_ES8328_SPI if SPI_MASTER
>  	select SND_SOC_ES8328_I2C if I2C
>  	select SND_SOC_ES7134
> @@ -543,6 +544,9 @@ config SND_SOC_HDMI_CODEC
>  config SND_SOC_ES7134
>         tristate "Everest Semi ES7134 CODEC"
>
> +config SND_SOC_ES8316
> +	tristate "Everest Semi ES8316 CODEC"
> +
>  config SND_SOC_ES8328
>  	tristate
>
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index 28a63fdaf982..e878306ce46e 100644
> --- a/sound/soc/codecs/Makefile
> +++ b/sound/soc/codecs/Makefile
> @@ -65,6 +65,7 @@ snd-soc-da732x-objs := da732x.o
>  snd-soc-da9055-objs := da9055.o
>  snd-soc-dmic-objs := dmic.o
>  snd-soc-es7134-objs := es7134.o
> +snd-soc-es8316-objs := es8316.o
>  snd-soc-es8328-objs := es8328.o
>  snd-soc-es8328-i2c-objs := es8328-i2c.o
>  snd-soc-es8328-spi-objs := es8328-spi.o
> @@ -300,6 +301,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_ES8316)    += snd-soc-es8316.o
>  obj-$(CONFIG_SND_SOC_ES8328)	+= snd-soc-es8328.o
>  obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
>  obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
> diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
> new file mode 100644
> index 000000000000..aea0b981891b
> --- /dev/null
> +++ b/sound/soc/codecs/es8316.c
> @@ -0,0 +1,639 @@
> +/*
> + * es8316.c -- es8316 ALSA SoC audio driver
> + * Copyright Everest Semiconductor Co.,Ltd
> + *
> + * Authors: David Yang <yangxiaohua@everest-semi.com>,

If the copyright is held by Everest Semiconductor and David Yang is also 
from Everest Semiconductor, then a signoff from Everest looks very much 
required?

> + *          Daniel Drake <drake@endlessm.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 <linux/module.h>
> +#include <linux/acpi.h>
> +#include <linux/delay.h>
> +#include <linux/i2c.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/regmap.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
> +#include <sound/soc-dapm.h>
> +#include <sound/tlv.h>
> +#include "es8316.h"
> +
> +/* In slave mode at single speed, the codec is documented as accepting 5
> + * MCLK/LRCK ratios, but we also add ratio 400, which is commonly used on
> + * Intel Cherry Trail platforms (19.2MHz MCLK, 48kHz LRCK).
> + */
> +#define NR_SUPPORTED_MCLK_LRCK_RATIOS 6
> +static const unsigned int supported_mclk_lrck_ratios[] = {
> +	256, 384, 400, 512, 768, 1024
> +};
> +
> +struct es8316_priv {
> +	unsigned int sysclk;
> +	unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS];
> +	struct snd_pcm_hw_constraint_list sysclk_constraints;
> +};
> +
> +/*
> + * ES8316 controls
> + */
> +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9600, 50, 1);
> +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -9600, 50, 1);
> +static const DECLARE_TLV_DB_SCALE(hpmixer_gain_tlv, -1200, 150, 0);
> +static const DECLARE_TLV_DB_SCALE(mic_bst_tlv, 0, 1200, 0);
> +
> +static unsigned int linin_pga_tlv[] = {
> +	TLV_DB_RANGE_HEAD(12),
> +	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
> +	1, 1, TLV_DB_SCALE_ITEM(300, 0, 0),
> +	2, 2, TLV_DB_SCALE_ITEM(600, 0, 0),
> +	3, 3, TLV_DB_SCALE_ITEM(900, 0, 0),
> +	4, 4, TLV_DB_SCALE_ITEM(1200, 0, 0),
> +	5, 5, TLV_DB_SCALE_ITEM(1500, 0, 0),
> +	6, 6, TLV_DB_SCALE_ITEM(1800, 0, 0),
> +	7, 7, TLV_DB_SCALE_ITEM(2100, 0, 0),
> +	8, 8, TLV_DB_SCALE_ITEM(2400, 0, 0),
> +};
> +static unsigned int hpout_vol_tlv[] = {
> +	TLV_DB_RANGE_HEAD(1),
> +	0, 3, TLV_DB_SCALE_ITEM(-4800, 1200, 0),
> +};
> +static const char * const alc_func_txt[] = { "Off", "On" };
> +static const struct soc_enum alc_func =
> +	SOC_ENUM_SINGLE(ES8316_ADC_ALC1, 6, 2, alc_func_txt);
> +
> +static const char * const ng_type_txt[] =
> +	{ "Constant PGA Gain", "Mute ADC Output"};
> +static const struct soc_enum ng_type =
> +	SOC_ENUM_SINGLE(ES8316_ADC_ALC6, 6, 2, ng_type_txt);
> +
> +static const char * const adcpol_txt[] = { "Normal", "Invert" };
> +static const struct soc_enum adcpol =
> +	SOC_ENUM_SINGLE(ES8316_ADC_MUTE, 1, 2, adcpol_txt);
> +static const char *const dacpol_txt[] =
> +	{ "Normal", "R Invert", "L Invert", "L + R Invert" };
> +static const struct soc_enum dacpol =
> +	SOC_ENUM_SINGLE(ES8316_DAC_SET1, 0, 4, dacpol_txt);
> +
> +static const struct snd_kcontrol_new es8316_snd_controls[] = {
> +	SOC_DOUBLE_TLV("HP Playback Volume", ES8316_CPHP_ICAL_VOL,
> +		       4, 0, 0, 1, hpout_vol_tlv),
> +	SOC_DOUBLE_TLV("HPMixer Gain", ES8316_HPMIX_VOL,
> +		       0, 4, 7, 0, hpmixer_gain_tlv),
> +
> +	SOC_DOUBLE_R_TLV("DAC Playback Volume", ES8316_DAC_VOLL,
> +			 ES8316_DAC_VOLR, 0, 0xC0, 1, dac_vol_tlv),
> +
> +	SOC_SINGLE("Enable DAC Soft Ramp", ES8316_DAC_SET1, 4, 1, 1),
> +	SOC_SINGLE("DAC Soft Ramp Rate", ES8316_DAC_SET1, 2, 4, 0),
> +
> +	SOC_ENUM("Playback Polarity", dacpol),
> +	SOC_SINGLE("DAC Notch Filter", ES8316_DAC_SET2, 6, 1, 0),
> +	SOC_SINGLE("DAC Double Fs Mode", ES8316_DAC_SET2, 7, 1, 0),
> +	SOC_SINGLE("DAC Volume Control-LeR", ES8316_DAC_SET2, 2, 1, 0),
> +	SOC_SINGLE("DAC Stereo Enhancement", ES8316_DAC_SET3, 0, 7, 0),
> +
> +	/* +20dB D2SE PGA Control */
> +	SOC_SINGLE_TLV("MIC Boost", ES8316_ADC_D2SEPGA,
> +		       0, 1, 0, mic_bst_tlv),
> +
> +	/* 0-+24dB Lineinput PGA Control */
> +	SOC_SINGLE_TLV("Input PGA", ES8316_ADC_PGAGAIN,
> +		       4, 8, 0, linin_pga_tlv),
> +
> +	SOC_SINGLE_TLV("ADC Capture Volume", ES8316_ADC_VOLUME,
> +		       0, 0xc0, 1, adc_vol_tlv),
> +	SOC_SINGLE("ADC Soft Ramp", ES8316_ADC_MUTE, 4, 1, 0),
> +	SOC_ENUM("Capture Polarity", adcpol),
> +	SOC_SINGLE("ADC Double FS Mode", ES8316_ADC_DMIC, 4, 1, 0),
> +
> +	SOC_SINGLE("ALC Capture Target Volume",
> +		   ES8316_ADC_ALC3, 4, 10, 0),
> +	SOC_SINGLE("ALC Capture Max PGA", ES8316_ADC_ALC1, 0, 28, 0),
> +	SOC_SINGLE("ALC Capture Min PGA", ES8316_ADC_ALC2, 0, 28, 0),
> +	SOC_ENUM("ALC Capture Function", alc_func),
> +	SOC_SINGLE("ALC Capture Hold Time", ES8316_ADC_ALC3, 0, 10, 0),
> +	SOC_SINGLE("ALC Capture Decay Time", ES8316_ADC_ALC4, 4, 10, 0),
> +	SOC_SINGLE("ALC Capture Attack Time", ES8316_ADC_ALC4, 0, 10, 0),
> +	SOC_SINGLE("ALC Capture NG Threshold", ES8316_ADC_ALC6, 0, 31, 0),
> +	SOC_ENUM("ALC Capture NG Type", ng_type),
> +	SOC_SINGLE("ALC Capture NG Switch", ES8316_ADC_ALC6, 5, 1, 0),
> +};
> +
> +/* Analog Input Mux */
> +static const char * const es8316_analog_in_txt[] = {
> +		"lin1-rin1",
> +		"lin2-rin2",
> +		"lin1-rin1 with 20db Boost",
> +		"lin2-rin2 with 20db Boost"
> +};
> +static const unsigned int es8316_analog_in_values[] = { 0, 1, 2, 3 };
> +static const struct soc_enum es8316_analog_input_enum =
> +	SOC_VALUE_ENUM_SINGLE(ES8316_ADC_PDN_LINSEL, 4, 3,
> +			      ARRAY_SIZE(es8316_analog_in_txt),
> +			      es8316_analog_in_txt,
> +			      es8316_analog_in_values);
> +static const struct snd_kcontrol_new es8316_analog_in_mux_controls =
> +	SOC_DAPM_ENUM("Route", es8316_analog_input_enum);
> +
> +static const char * const es8316_dmic_txt[] = {
> +		"dmic disable",
> +		"dmic data at high level",
> +		"dmic data at low level",
> +};
> +static const unsigned int es8316_dmic_values[] = { 0, 1, 2 };
> +static const struct soc_enum es8316_dmic_src_enum =
> +	SOC_VALUE_ENUM_SINGLE(ES8316_ADC_DMIC, 0, 3,
> +			      ARRAY_SIZE(es8316_dmic_txt),
> +			      es8316_dmic_txt,
> +			      es8316_dmic_values);
> +static const struct snd_kcontrol_new es8316_dmic_src_controls =
> +	SOC_DAPM_ENUM("Route", es8316_dmic_src_enum);
> +
> +/* hp mixer mux */
> +static const char * const es8316_hpmux_texts[] = {
> +	"lin1-rin1",
> +	"lin2-rin2",
> +	"lin-rin with Boost",
> +	"lin-rin with Boost and PGA"
> +};
> +
> +static const unsigned int es8316_hpmux_values[] = { 0, 1, 2, 3 };
> +
> +static SOC_ENUM_SINGLE_DECL(es8316_left_hpmux_enum, ES8316_HPMIX_SEL,
> +	4, es8316_hpmux_texts);
> +
> +static const struct snd_kcontrol_new es8316_left_hpmux_controls =
> +	SOC_DAPM_ENUM("Route", es8316_left_hpmux_enum);
> +
> +static SOC_ENUM_SINGLE_DECL(es8316_right_hpmux_enum, ES8316_HPMIX_SEL,
> +	0, es8316_hpmux_texts);
> +
> +static const struct snd_kcontrol_new es8316_right_hpmux_controls =
> +	SOC_DAPM_ENUM("Route", es8316_right_hpmux_enum);
> +
> +/* headphone Output Mixer */
> +static const struct snd_kcontrol_new es8316_out_left_mix[] = {
> +	SOC_DAPM_SINGLE("LLIN Switch", ES8316_HPMIX_SWITCH, 6, 1, 0),
> +	SOC_DAPM_SINGLE("Left DAC Switch", ES8316_HPMIX_SWITCH, 7, 1, 0),
> +};
> +static const struct snd_kcontrol_new es8316_out_right_mix[] = {
> +	SOC_DAPM_SINGLE("RLIN Switch", ES8316_HPMIX_SWITCH, 2, 1, 0),
> +	SOC_DAPM_SINGLE("Right DAC Switch", ES8316_HPMIX_SWITCH, 3, 1, 0),
> +};
> +
> +/* DAC data source mux */
> +static const char * const es8316_dacsrc_texts[] = {
> +	"LDATA TO LDAC, RDATA TO RDAC",
> +	"LDATA TO LDAC, LDATA TO RDAC",
> +	"RDATA TO LDAC, RDATA TO RDAC",
> +	"RDATA TO LDAC, LDATA TO RDAC",
> +};
> +
> +static const unsigned int es8316_dacsrc_values[] = { 0, 1, 2, 3 };
> +
> +static SOC_ENUM_SINGLE_DECL(es8316_dacsrc_mux_enum, ES8316_DAC_SET1,
> +	6, es8316_dacsrc_texts);
> +
> +static const struct snd_kcontrol_new es8316_dacsrc_mux_controls =
> +	SOC_DAPM_ENUM("Route", es8316_dacsrc_mux_enum);
> +
> +static const struct snd_soc_dapm_widget es8316_dapm_widgets[] = {
> +	SND_SOC_DAPM_INPUT("DMIC"),
> +	SND_SOC_DAPM_INPUT("MIC1"),
> +	SND_SOC_DAPM_INPUT("MIC2"),
> +	SND_SOC_DAPM_MICBIAS("micbias", SND_SOC_NOPM, 0, 0),
> +
> +	/* Input Mux */
> +	SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
> +			 &es8316_analog_in_mux_controls),
> +
> +	SND_SOC_DAPM_PGA("Line input PGA", ES8316_ADC_PDN_LINSEL,
> +			 7, 1, NULL, 0),
> +	SND_SOC_DAPM_ADC("Mono ADC", NULL, ES8316_ADC_PDN_LINSEL, 6, 1),
> +	SND_SOC_DAPM_MUX("Digital Mic Mux", SND_SOC_NOPM, 0, 0,
> +			 &es8316_dmic_src_controls),
> +
> +	/* Digital Interface */
> +	SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture",  1,
> +			     ES8316_SERDATA_ADC, 6, 1),
> +	SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0,
> +			    SND_SOC_NOPM, 0, 0),
> +
> +	SND_SOC_DAPM_MUX("DAC SRC Mux", SND_SOC_NOPM, 0, 0,
> +			 &es8316_dacsrc_mux_controls),
> +
> +	SND_SOC_DAPM_DAC("Right DAC", NULL, SND_SOC_NOPM, 0, 1),
> +	SND_SOC_DAPM_DAC("Left DAC", NULL, SND_SOC_NOPM, 4, 1),
> +
> +	/* Headphone Output Side */
> +	SND_SOC_DAPM_MUX("Left Hp mux", SND_SOC_NOPM, 0, 0,
> +			 &es8316_left_hpmux_controls),
> +	SND_SOC_DAPM_MUX("Right Hp mux", SND_SOC_NOPM, 0, 0,
> +			 &es8316_right_hpmux_controls),
> +	SND_SOC_DAPM_MIXER("Left Hp mixer", SND_SOC_NOPM,
> +			   4, 1, &es8316_out_left_mix[0],
> +			   ARRAY_SIZE(es8316_out_left_mix)),
> +	SND_SOC_DAPM_MIXER("Right Hp mixer", SND_SOC_NOPM,
> +			   0, 1, &es8316_out_right_mix[0],
> +			   ARRAY_SIZE(es8316_out_right_mix)),
> +
> +	/* Output charge pump */
> +	SND_SOC_DAPM_PGA("HPCP L", SND_SOC_NOPM, 6, 0, NULL, 0),
> +	SND_SOC_DAPM_PGA("HPCP R", SND_SOC_NOPM, 2, 0, NULL, 0),
> +
> +	/* Output Driver */
> +	SND_SOC_DAPM_PGA("HPVOL L", SND_SOC_NOPM, 0, 0, NULL, 0),
> +	SND_SOC_DAPM_PGA("HPVOL R", SND_SOC_NOPM, 0, 0, NULL, 0),
> +
> +	SND_SOC_DAPM_OUTPUT("HPOL"),
> +	SND_SOC_DAPM_OUTPUT("HPOR"),
> +};
> +
> +static const struct snd_soc_dapm_route es8316_dapm_routes[] = {
> +	/* Recording */
> +	{"MIC1", NULL, "micbias"},
> +	{"MIC2", NULL, "micbias"},
> +
> +	{"Differential Mux", "lin1-rin1", "MIC1"},
> +	{"Differential Mux", "lin2-rin2", "MIC2"},
> +	{"Line input PGA", NULL, "Differential Mux"},
> +
> +	{"Mono ADC", NULL, "Line input PGA"},
> +
> +	{"Digital Mic Mux", "dmic disable", "Mono ADC"},
> +
> +	{"I2S OUT", NULL, "Digital Mic Mux"},
> +
> +	/* Playback */
> +	{"DAC SRC Mux", "LDATA TO LDAC, RDATA TO RDAC", "I2S IN"},
> +
> +	{"Left DAC", NULL, "DAC SRC Mux"},
> +	{"Right DAC", NULL, "DAC SRC Mux"},
> +
> +	{"Left Hp mux", "lin-rin with Boost and PGA", "Line input PGA"},
> +	{"Right Hp mux", "lin-rin with Boost and PGA", "Line input PGA"},
> +
> +	{"Left Hp mixer", "LLIN Switch", "Left Hp mux"},
> +	{"Left Hp mixer", "Left DAC Switch", "Left DAC"},
> +
> +	{"Right Hp mixer", "RLIN Switch", "Right Hp mux"},
> +	{"Right Hp mixer", "Right DAC Switch", "Right DAC"},
> +
> +	{"HPCP L", NULL, "Left Hp mixer"},
> +	{"HPCP R", NULL, "Right Hp mixer"},
> +
> +	{"HPVOL L", NULL, "HPCP L"},
> +	{"HPVOL R", NULL, "HPCP R"},
> +
> +	{"HPOL", NULL, "HPVOL L"},
> +	{"HPOR", NULL, "HPVOL R"},
> +};
> +
> +static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai,
> +				 int clk_id, unsigned int freq, int dir)
> +{
> +	struct snd_soc_codec *codec = codec_dai->codec;
> +	struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
> +	int i;
> +
> +	if (freq == 0)
> +		return -EINVAL;
> +
> +	/* Limit supported sample rates to ones that can be autodetected
> +	 * by the codec running in slave mode.
> +	 */
> +	for (i = 0; i < NR_SUPPORTED_MCLK_LRCK_RATIOS; i++) {
> +		const unsigned int ratio = supported_mclk_lrck_ratios[i];
> +
> +		es8316->allowed_rates[i] = freq / ratio;

Shouldn't this test that an integer ratio is possible instead of adding 
rates that result from a truncation operation?

> +	}
> +
> +	es8316->sysclk_constraints.list = es8316->allowed_rates;
> +	es8316->sysclk_constraints.count = NR_SUPPORTED_MCLK_LRCK_RATIOS;
> +	es8316->sysclk = freq;
> +
> +	return 0;
> +}
> +
> +static int es8316_set_dai_fmt(struct snd_soc_dai *codec_dai,
> +			      unsigned int fmt)
> +{
> +	struct snd_soc_codec *codec = codec_dai->codec;
> +	u8 serdata1 = 0;
> +	u8 serdata2 = 0;
> +	u8 mask;
> +
> +	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
> +		dev_err(codec->dev, "Codec driver only supports slave mode\n");
> +		return -EINVAL;
> +	}
> +
> +	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
> +		dev_err(codec->dev, "Codec driver only supports I2S format\n");
> +		return -EINVAL;
> +	}
> +
> +	/* Clock inversion */
> +	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
> +	case SND_SOC_DAIFMT_NB_NF:
> +		break;
> +	case SND_SOC_DAIFMT_IB_IF:
> +		serdata1 |= ES8316_SERDATA1_BCLK_INV;
> +		serdata2 |= ES8316_SERDATA2_ADCLRP;
> +		break;
> +	case SND_SOC_DAIFMT_IB_NF:
> +		serdata1 |= ES8316_SERDATA1_BCLK_INV;
> +		break;
> +	case SND_SOC_DAIFMT_NB_IF:
> +		serdata2 |= ES8316_SERDATA2_ADCLRP;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	mask = ES8316_SERDATA1_MASTER | ES8316_SERDATA1_BCLK_INV;
> +	snd_soc_update_bits(codec, ES8316_SERDATA1, mask, serdata1);
> +
> +	mask = ES8316_SERDATA2_FMT_MASK | ES8316_SERDATA2_ADCLRP;
> +	snd_soc_update_bits(codec, ES8316_SERDATA_ADC, mask, serdata2);
> +	snd_soc_update_bits(codec, ES8316_SERDATA_DAC, mask, serdata2);
> +
> +	return 0;
> +}
> +
> +static int es8316_pcm_startup(struct snd_pcm_substream *substream,
> +			      struct snd_soc_dai *dai)
> +{
> +	struct snd_soc_codec *codec = dai->codec;
> +	struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
> +
> +	/* The set of sample rates that can be supported depends on the
> +	 * MCLK supplied to the CODEC.
> +	 */
> +	if (es8316->sysclk)
> +		snd_pcm_hw_constraint_list(substream->runtime, 0,
> +					   SNDRV_PCM_HW_PARAM_RATE,
> +					   &es8316->sysclk_constraints);
> +
> +	return 0;
> +}
> +
> +static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
> +				struct snd_pcm_hw_params *params,
> +				struct snd_soc_dai *dai)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_codec *codec = rtd->codec;
> +	struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
> +	u8 wordlen = 0;
> +
> +	if (!es8316->sysclk) {
> +		dev_err(codec->dev, "No MCLK configured\n");
> +		return -EINVAL;
> +	}
> +
> +	switch (params_format(params)) {
> +	case SNDRV_PCM_FORMAT_S16_LE:
> +		wordlen = ES8316_SERDATA2_LEN_16;
> +		break;
> +	case SNDRV_PCM_FORMAT_S20_3LE:
> +		wordlen = ES8316_SERDATA2_LEN_20;
> +		break;
> +	case SNDRV_PCM_FORMAT_S24_LE:
> +		wordlen = ES8316_SERDATA2_LEN_24;
> +		break;
> +	case SNDRV_PCM_FORMAT_S32_LE:
> +		wordlen = ES8316_SERDATA2_LEN_32;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	snd_soc_update_bits(codec, ES8316_SERDATA_DAC,
> +			    ES8316_SERDATA2_LEN_MASK, wordlen);
> +	snd_soc_update_bits(codec, ES8316_SERDATA_ADC,
> +			    ES8316_SERDATA2_LEN_MASK, wordlen);
> +	return 0;
> +}
> +
> +static int es8316_mute(struct snd_soc_dai *dai, int mute)
> +{
> +	snd_soc_update_bits(dai->codec, ES8316_DAC_SET1, 0x20,
> +			    mute ? 0x20 : 0);
> +	return 0;
> +}
> +
> +static int es8316_set_bias_level(struct snd_soc_codec *codec,
> +				 enum snd_soc_bias_level level)
> +{
> +	switch (level) {
> +	case SND_SOC_BIAS_ON:
> +		snd_soc_write(codec, ES8316_RESET, 0xC0);
> +		snd_soc_write(codec, ES8316_CPHP_OUTEN, 0x66);
> +		snd_soc_write(codec, ES8316_DAC_PDN, 0x00);
> +		snd_soc_write(codec, ES8316_CPHP_LDOCTL, 0x30);
> +		snd_soc_write(codec, ES8316_CPHP_PDN2, 0x10);
> +		snd_soc_write(codec, ES8316_CPHP_PDN1, 0x03);
> +		snd_soc_write(codec, ES8316_HPMIX_PDN, 0x00);
> +		snd_soc_update_bits(codec, ES8316_ADC_PDN_LINSEL, 0xc0, 0x00);
> +		snd_soc_write(codec, ES8316_SYS_PDN, 0x00);
> +		snd_soc_write(codec, ES8316_SYS_LP1, 0x04);
> +		snd_soc_write(codec, ES8316_SYS_LP2, 0x0c);
> +		break;
> +	case SND_SOC_BIAS_PREPARE:
> +		break;
> +	case SND_SOC_BIAS_STANDBY:
> +		break;
> +	case SND_SOC_BIAS_OFF:
> +		snd_soc_write(codec, ES8316_CPHP_OUTEN, 0x00);
> +		snd_soc_write(codec, ES8316_DAC_PDN, 0x11);
> +		snd_soc_write(codec, ES8316_CPHP_LDOCTL, 0x03);
> +		snd_soc_write(codec, ES8316_CPHP_PDN2, 0x22);
> +		snd_soc_write(codec, ES8316_CPHP_PDN1, 0x06);
> +		snd_soc_write(codec, ES8316_HPMIX_PDN, 0x33);
> +		snd_soc_update_bits(codec, ES8316_ADC_PDN_LINSEL, 0xc0, 0xc0);
> +		snd_soc_write(codec, ES8316_SYS_PDN, 0x3f);
> +		snd_soc_write(codec, ES8316_SYS_LP1, 0x3f);
> +		snd_soc_write(codec, ES8316_SYS_LP2, 0x1f);
> +		snd_soc_write(codec, ES8316_RESET, 0x00);
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +#define ES8316_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
> +			SNDRV_PCM_FMTBIT_S24_LE)
> +
> +static struct snd_soc_dai_ops es8316_ops = {
> +	.startup = es8316_pcm_startup,
> +	.hw_params = es8316_pcm_hw_params,
> +	.set_fmt = es8316_set_dai_fmt,
> +	.set_sysclk = es8316_set_dai_sysclk,
> +	.digital_mute = es8316_mute,
> +};
> +
> +static struct snd_soc_dai_driver es8316_dai = {
> +	.name = "ES8316 HiFi",
> +	.playback = {
> +		.stream_name = "Playback",
> +		.channels_min = 1,
> +		.channels_max = 2,
> +		.rates = SNDRV_PCM_RATE_8000_48000,
> +		.formats = ES8316_FORMATS,
> +	},
> +	.capture = {
> +		.stream_name = "Capture",
> +		.channels_min = 1,
> +		.channels_max = 2,
> +		.rates = SNDRV_PCM_RATE_8000_48000,
> +		.formats = ES8316_FORMATS,
> +	},
> +	.ops = &es8316_ops,
> +	.symmetric_rates = 1,
> +};
> +
> +static int es8316_probe(struct snd_soc_codec *codec)
> +{
> +	snd_soc_write(codec, ES8316_RESET, 0x3f);
> +	usleep_range(5000, 5500);
> +	snd_soc_write(codec, ES8316_RESET, 0x00);
> +	snd_soc_write(codec, ES8316_SYS_VMIDSEL, 0xFF);
> +	msleep(30);
> +
> +	snd_soc_write(codec, ES8316_CLKMGR_CLKSEL, 0x08);
> +	snd_soc_write(codec, ES8316_CLKMGR_ADCOSR, 0x20);
> +	snd_soc_write(codec, ES8316_CLKMGR_ADCDIV1, 0x11);
> +	snd_soc_write(codec, ES8316_CLKMGR_ADCDIV2, 0x00);
> +	snd_soc_write(codec, ES8316_CLKMGR_DACDIV1, 0x11);
> +	snd_soc_write(codec, ES8316_CLKMGR_DACDIV2, 0x00);
> +	snd_soc_write(codec, ES8316_CLKMGR_CPDIV, 0x00);
> +	snd_soc_write(codec, ES8316_SERDATA1, 0x04);
> +	snd_soc_write(codec, ES8316_CLKMGR_CLKSW, 0x7f);
> +	snd_soc_write(codec, ES8316_CAL_TYPE, 0x0F);
> +	snd_soc_write(codec, ES8316_CAL_HPLIV, 0x90);
> +	snd_soc_write(codec, ES8316_CAL_HPRIV, 0x90);
> +	snd_soc_write(codec, ES8316_ADC_VOLUME, 0x00);
> +	snd_soc_write(codec, ES8316_ADC_D2SEPGA, 0x00);
> +	snd_soc_write(codec, ES8316_ADC_DMIC, 0x08);
> +	snd_soc_write(codec, ES8316_DAC_SET2, 0x00);
> +	snd_soc_write(codec, ES8316_DAC_SET3, 0x00);
> +	snd_soc_write(codec, ES8316_DAC_VOLL, 0x02);
> +	snd_soc_write(codec, ES8316_DAC_VOLR, 0x02);
> +	snd_soc_write(codec, ES8316_SERDATA_ADC, 0x00);
> +	snd_soc_write(codec, ES8316_SERDATA_DAC, 0x00);
> +	snd_soc_write(codec, ES8316_SYS_VMIDLOW, 0x11);
> +	snd_soc_write(codec, ES8316_SYS_VSEL, 0xfc);
> +	snd_soc_write(codec, ES8316_SYS_REF, 0x28);
> +	snd_soc_write(codec, ES8316_HPMIX_SEL, 0x00);
> +	snd_soc_write(codec, ES8316_HPMIX_SWITCH, 0x88);
> +	snd_soc_write(codec, ES8316_HPMIX_VOL, 0x88);
> +	snd_soc_write(codec, ES8316_CPHP_ICAL_VOL, 0x00);
> +	snd_soc_write(codec, ES8316_GPIO_SEL, 0x00);
> +	snd_soc_write(codec, ES8316_GPIO_DEBUNCE_INT, 0x02);
> +	snd_soc_write(codec, ES8316_TESTMODE, 0xa0);
> +	snd_soc_write(codec, ES8316_TEST1, 0x00);
> +	snd_soc_write(codec, ES8316_TEST2, 0x04);
> +	snd_soc_write(codec, ES8316_RESET, 0xc0);
> +	msleep(50);
> +	snd_soc_write(codec, ES8316_ADC_PGAGAIN, 0x60);
> +	snd_soc_write(codec, ES8316_ADC_D2SEPGA, 0x01);
> +
> +	/* ADC DS mode, HPF enable */
> +	snd_soc_write(codec, ES8316_ADC_DMIC, 0x08);
> +	snd_soc_write(codec, ES8316_ADC_ALC1, 0xcd);
> +	snd_soc_write(codec, ES8316_ADC_ALC2, 0x08);
> +	snd_soc_write(codec, ES8316_ADC_ALC3, 0xa0);
> +	snd_soc_write(codec, ES8316_ADC_ALC4, 0x05);
> +	snd_soc_write(codec, ES8316_ADC_ALC5, 0x06);
> +	snd_soc_write(codec, ES8316_ADC_ALC6, 0x61);
> +	return 0;
> +}
> +
> +static struct snd_soc_codec_driver soc_codec_dev_es8316 = {
> +	.probe		= es8316_probe,
> +	.set_bias_level	= es8316_set_bias_level,
> +	.idle_bias_off	= true,
> +
> +	.component_driver = {
> +		.controls		= es8316_snd_controls,
> +		.num_controls		= ARRAY_SIZE(es8316_snd_controls),
> +		.dapm_widgets		= es8316_dapm_widgets,
> +		.num_dapm_widgets	= ARRAY_SIZE(es8316_dapm_widgets),
> +		.dapm_routes		= es8316_dapm_routes,
> +		.num_dapm_routes	= ARRAY_SIZE(es8316_dapm_routes),
> +	},
> +};
> +
> +static const struct regmap_config es8316_regmap = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.max_register = 0x53,
> +	.cache_type = REGCACHE_RBTREE,
> +};
> +
> +static int es8316_i2c_probe(struct i2c_client *i2c_client,
> +			    const struct i2c_device_id *id)
> +{
> +	struct es8316_priv *es8316;
> +	struct regmap *regmap;
> +
> +	es8316 = devm_kzalloc(&i2c_client->dev, sizeof(struct es8316_priv),
> +			      GFP_KERNEL);
> +	if (es8316 == NULL)
> +		return -ENOMEM;
> +
> +	i2c_set_clientdata(i2c_client, es8316);
> +
> +	regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap);
> +	if (IS_ERR(regmap))
> +		return PTR_ERR(regmap);
> +
> +	return snd_soc_register_codec(&i2c_client->dev, &soc_codec_dev_es8316,
> +				      &es8316_dai, 1);
> +}
> +
> +static int es8316_i2c_remove(struct i2c_client *client)
> +{
> +	snd_soc_unregister_codec(&client->dev);
> +	return 0;
> +}
> +
> +static const struct i2c_device_id es8316_i2c_id[] = {
> +	{"ESSX8316", 0 },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(i2c, es8316_i2c_id);
> +
> +static const struct of_device_id es8316_of_match[] = {
> +	{ .compatible = "everest,es8316", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, es8316_of_match);
> +
> +static const struct acpi_device_id es8316_acpi_match[] = {
> +	{"ESSX8316", 0},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(acpi, es8316_acpi_match);
> +
> +static struct i2c_driver es8316_i2c_driver = {
> +	.driver = {
> +		.name			= "es8316",
> +		.acpi_match_table	= ACPI_PTR(es8316_acpi_match),
> +		.of_match_table		= of_match_ptr(es8316_of_match),
> +	},
> +	.probe		= es8316_i2c_probe,
> +	.remove		= es8316_i2c_remove,
> +	.id_table	= es8316_i2c_id,
> +};
> +module_i2c_driver(es8316_i2c_driver);
> +
> +MODULE_DESCRIPTION("Everest Semi ES8316 ALSA SoC Codec Driver");
> +MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
> +MODULE_LICENSE("GPL v2");
> diff --git a/sound/soc/codecs/es8316.h b/sound/soc/codecs/es8316.h
> new file mode 100644
> index 000000000000..702bebc69ca8
> --- /dev/null
> +++ b/sound/soc/codecs/es8316.h
> @@ -0,0 +1,122 @@
> +/*
> + * Copyright Everest Semiconductor Co.,Ltd
> + *
> + * Author: 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.
> + *
> + */
> +
> +#ifndef _ES8316_H
> +#define _ES8316_H
> +
> +/*
> + * ES8316 register space
> + */
> +
> +/* Reset Control */
> +#define ES8316_RESET		0x00
> +
> +/* Clock Management */
> +#define ES8316_CLKMGR_CLKSW	0x01
> +#define ES8316_CLKMGR_CLKSEL	0x02
> +#define ES8316_CLKMGR_ADCOSR	0x03
> +#define ES8316_CLKMGR_ADCDIV1	0x04
> +#define ES8316_CLKMGR_ADCDIV2	0x05
> +#define ES8316_CLKMGR_DACDIV1	0x06
> +#define ES8316_CLKMGR_DACDIV2	0x07
> +#define ES8316_CLKMGR_CPDIV	0x08
> +
> +/* Serial Data Port Control */
> +#define ES8316_SERDATA1		0x09
> +#define ES8316_SERDATA_ADC	0x0a
> +#define ES8316_SERDATA_DAC	0x0b
> +
> +/* System Control */
> +#define ES8316_SYS_VMIDSEL	0x0c
> +#define ES8316_SYS_PDN		0x0d
> +#define ES8316_SYS_LP1		0x0e
> +#define ES8316_SYS_LP2		0x0f
> +#define ES8316_SYS_VMIDLOW	0x10
> +#define ES8316_SYS_VSEL		0x11
> +#define ES8316_SYS_REF		0x12
> +
> +/* Headphone Mixer */
> +#define ES8316_HPMIX_SEL	0x13
> +#define ES8316_HPMIX_SWITCH	0x14
> +#define ES8316_HPMIX_PDN	0x15
> +#define ES8316_HPMIX_VOL	0x16
> +
> +/* Charge Pump Headphone driver */
> +#define ES8316_CPHP_OUTEN	0x17
> +#define ES8316_CPHP_ICAL_VOL	0x18
> +#define ES8316_CPHP_PDN1	0x19
> +#define ES8316_CPHP_PDN2	0x1a
> +#define ES8316_CPHP_LDOCTL	0x1b
> +
> +/* Calibration */
> +#define ES8316_CAL_TYPE		0x1c
> +#define ES8316_CAL_SET		0x1d
> +#define ES8316_CAL_HPLIV	0x1e
> +#define ES8316_CAL_HPRIV	0x1f
> +#define ES8316_CAL_HPLMV	0x20
> +#define ES8316_CAL_HPRMV	0x21
> +
> +/* ADC Control */
> +#define ES8316_ADC_PDN_LINSEL	0x22
> +#define ES8316_ADC_PGAGAIN	0x23
> +#define ES8316_ADC_D2SEPGA	0x24
> +#define ES8316_ADC_DMIC		0x25
> +#define ES8316_ADC_MUTE		0x26
> +#define ES8316_ADC_VOLUME	0x27
> +#define ES8316_ADC_ALC1		0x29
> +#define ES8316_ADC_ALC2		0x2a
> +#define ES8316_ADC_ALC3		0x2b
> +#define ES8316_ADC_ALC4		0x2c
> +#define ES8316_ADC_ALC5		0x2d
> +#define ES8316_ADC_ALC6		0x2e
> +
> +/* DAC Control */
> +#define ES8316_DAC_PDN		0x2f
> +#define ES8316_DAC_SET1		0x30
> +#define ES8316_DAC_SET2		0x31
> +#define ES8316_DAC_SET3		0x32
> +#define ES8316_DAC_VOLL		0x33
> +#define ES8316_DAC_VOLR		0x34
> +
> +/* GPIO */
> +#define ES8316_GPIO_SEL		0x4d
> +#define ES8316_GPIO_DEBUNCE_INT 0x4e
> +#define ES8316_GPIO_FLAG	0x4f
> +
> +/* Test mode */
> +#define ES8316_TESTMODE		0x50
> +#define ES8316_TEST1		0x51
> +#define ES8316_TEST2		0x52
> +#define ES8316_TEST3		0x53
> +
> +/*
> + * Field definitions
> + */
> +
> +/* ES8316_SERDATA1 */
> +#define ES8316_SERDATA1_MASTER		0x80
> +#define ES8316_SERDATA1_BCLK_INV	0x20
> +
> +/* ES8316_SERDATA_ADC and _DAC */
> +#define ES8316_SERDATA2_FMT_MASK	0x3
> +#define ES8316_SERDATA2_FMT_I2S		0x00
> +#define ES8316_SERDATA2_FMT_LEFTJ	0x01
> +#define ES8316_SERDATA2_FMT_RIGHTJ	0x02
> +#define ES8316_SERDATA2_FMT_PCM		0x03
> +#define ES8316_SERDATA2_ADCLRP		0x20
> +#define ES8316_SERDATA2_LEN_MASK	0x1c
> +#define ES8316_SERDATA2_LEN_24		0x00
> +#define ES8316_SERDATA2_LEN_20		0x04
> +#define ES8316_SERDATA2_LEN_18		0x08
> +#define ES8316_SERDATA2_LEN_16		0x0c
> +#define ES8316_SERDATA2_LEN_32		0x10
> +
> +#endif
>

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

* Re: [PATCH 1/2] ASoC: add es8316 codec driver
  2017-05-10 18:49 ` [PATCH 1/2] ASoC: add es8316 codec driver Pierre-Louis Bossart
@ 2017-05-10 19:18   ` Daniel Drake
  2017-05-14  9:36     ` Mark Brown
  0 siblings, 1 reply; 8+ messages in thread
From: Daniel Drake @ 2017-05-10 19:18 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: alsa-devel, Mark Brown, Linux Upstreaming Team, Liam Girdwood,
	yangxiaohua

On Wed, May 10, 2017 at 12:49 PM, Pierre-Louis Bossart
<pierre-louis.bossart@linux.intel.com> wrote:
> If the copyright is held by Everest Semiconductor and David Yang is also
> from Everest Semiconductor, then a signoff from Everest looks very much
> required?

The original patches from David do now have his sign-off:
https://bugzilla.kernel.org/show_bug.cgi?id=189261#c57

But I have now rearranged things quite a bit. What is the norm here,
can I just copy over the sign off from before, or do we need to
request explicit permission again from David?

Thanks
Daniel

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

* Re: [PATCH 1/2] ASoC: add es8316 codec driver
  2017-05-10 19:18   ` Daniel Drake
@ 2017-05-14  9:36     ` Mark Brown
  0 siblings, 0 replies; 8+ messages in thread
From: Mark Brown @ 2017-05-14  9:36 UTC (permalink / raw)
  To: Daniel Drake
  Cc: alsa-devel, Linux Upstreaming Team, Pierre-Louis Bossart,
	yangxiaohua, Liam Girdwood


[-- Attachment #1.1: Type: text/plain, Size: 898 bytes --]

On Wed, May 10, 2017 at 01:18:20PM -0600, Daniel Drake wrote:
> On Wed, May 10, 2017 at 12:49 PM, Pierre-Louis Bossart
> <pierre-louis.bossart@linux.intel.com> wrote:

> > If the copyright is held by Everest Semiconductor and David Yang is also
> > from Everest Semiconductor, then a signoff from Everest looks very much
> > required?

> The original patches from David do now have his sign-off:
> https://bugzilla.kernel.org/show_bug.cgi?id=189261#c57

> But I have now rearranged things quite a bit. What is the norm here,
> can I just copy over the sign off from before, or do we need to
> request explicit permission again from David?

I'm not going to look at patches that don't have signoffs, sorry.
Please see SubmittingPatches for details of what a signoff means and how
to handle them.  Without knowing how closely what you've done resembles
what you're basing it on it's hard to be sure.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



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

* Re: [PATCH 2/2] ASoC: Intel: add machine driver for BYT/CHT + ES8316
  2017-05-10 18:49   ` Pierre-Louis Bossart
@ 2017-05-15 18:07     ` Daniel Drake
  2017-05-15 18:41       ` Pierre-Louis Bossart
  0 siblings, 1 reply; 8+ messages in thread
From: Daniel Drake @ 2017-05-15 18:07 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: alsa-devel, Mark Brown, Linux Upstreaming Team, Liam Girdwood,
	yangxiaohua

On Wed, May 10, 2017 at 12:49 PM, Pierre-Louis Bossart
<pierre-louis.bossart@linux.intel.com> wrote:
> You may want to add a comment that this patch is based on the use of SSP2
> and hence cannot work on BYT-CR devices.

I'm not quite clear on the terminology here. What does BYT-CR mean exactly?

I named the driver with "byt" in addition to "cht" as I was hoping it
can support the baytrail devices mentioned here:
https://bugzilla.kernel.org/show_bug.cgi?id=189261#c71

I also see that bytcht_da7213 is documented as supporting Baytrail
devices and only uses SSP2. But bytcr_rt5640 does switch to SSP0 on
valleyview, and I could do the same.

Not sure which way I should go here at least without more info from
the reporter, let me know if you have any suggestions.

>> +static const struct snd_kcontrol_new byt_cht_es8316_controls[] = {
>> +       SOC_DAPM_PIN_SWITCH("Headphone"),
>> +       SOC_DAPM_PIN_SWITCH("Microphone 1"),
>> +       SOC_DAPM_PIN_SWITCH("Microphone 2"),
>
>
> do you really need to control the two analog mics independently? And along
> the same lines, should there be a path for DMICS?

The ES8316 datasheet is clear that it supports 2 independent analog
stereo mics, and the codec driver exposes the relevant controls for
that, so I added two here. There is a mux so you have to choose which
one you feed into the ADC, but (if you wanted to) you could e.g. feed
the other into the HP output mixer, and use both simultaneously.

The product I'm working with only uses one of them though, so I could
delete the other one if you think that makes sense?

The datasheet does say "Support digital mic" but it makes almost no
other mention of DMIC support, not even which of the 4 mic input pins
you would use for that. The codec driver does expose a single
SND_SOC_DAPM_INPUT("DMIC") though so I could very easily add a route
here, although I would have no way of testing it.

Thanks for your help

Daniel

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

* Re: [PATCH 2/2] ASoC: Intel: add machine driver for BYT/CHT + ES8316
  2017-05-15 18:07     ` Daniel Drake
@ 2017-05-15 18:41       ` Pierre-Louis Bossart
  0 siblings, 0 replies; 8+ messages in thread
From: Pierre-Louis Bossart @ 2017-05-15 18:41 UTC (permalink / raw)
  To: Daniel Drake
  Cc: alsa-devel, Mark Brown, Linux Upstreaming Team, Liam Girdwood,
	yangxiaohua

On 5/15/17 1:07 PM, Daniel Drake wrote:
> On Wed, May 10, 2017 at 12:49 PM, Pierre-Louis Bossart
> <pierre-louis.bossart@linux.intel.com> wrote:
>> You may want to add a comment that this patch is based on the use of SSP2
>> and hence cannot work on BYT-CR devices.
>
> I'm not quite clear on the terminology here. What does BYT-CR mean exactly?

a cost-reduced version where the packaging is different with only SSP0 
and SSP2 exposed.

>
> I named the driver with "byt" in addition to "cht" as I was hoping it
> can support the baytrail devices mentioned here:
> https://bugzilla.kernel.org/show_bug.cgi?id=189261#c71
>
> I also see that bytcht_da7213 is documented as supporting Baytrail
> devices and only uses SSP2. But bytcr_rt5640 does switch to SSP0 on
> valleyview, and I could do the same.
>
> Not sure which way I should go here at least without more info from
> the reporter, let me know if you have any suggestions.

just add a note that SSP0 routing is not supported at the moment, no 
reason to add code if you can't test it.

>
>>> +static const struct snd_kcontrol_new byt_cht_es8316_controls[] = {
>>> +       SOC_DAPM_PIN_SWITCH("Headphone"),
>>> +       SOC_DAPM_PIN_SWITCH("Microphone 1"),
>>> +       SOC_DAPM_PIN_SWITCH("Microphone 2"),
>>
>>
>> do you really need to control the two analog mics independently? And along
>> the same lines, should there be a path for DMICS?
>
> The ES8316 datasheet is clear that it supports 2 independent analog
> stereo mics, and the codec driver exposes the relevant controls for
> that, so I added two here. There is a mux so you have to choose which
> one you feed into the ADC, but (if you wanted to) you could e.g. feed
> the other into the HP output mixer, and use both simultaneously.
>
> The product I'm working with only uses one of them though, so I could
> delete the other one if you think that makes sense?

I am not sure what the recommendation is. I've always seen a single 
'mic' or 'int mic' switch being used regardless of the number of mics. 
Usually you have additional routing controls to define which mics are 
used, this control seems to be a higher level kill switch of sorts.

>
> The datasheet does say "Support digital mic" but it makes almost no
> other mention of DMIC support, not even which of the 4 mic input pins
> you would use for that. The codec driver does expose a single
> SND_SOC_DAPM_INPUT("DMIC") though so I could very easily add a route
> here, although I would have no way of testing it.

ok, fair enough. adding a note of what was tested is helpful in general.

>
> Thanks for your help
>
> Daniel
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>

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

end of thread, other threads:[~2017-05-15 18:41 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-10 18:16 [PATCH 1/2] ASoC: add es8316 codec driver Daniel Drake
2017-05-10 18:16 ` [PATCH 2/2] ASoC: Intel: add machine driver for BYT/CHT + ES8316 Daniel Drake
2017-05-10 18:49   ` Pierre-Louis Bossart
2017-05-15 18:07     ` Daniel Drake
2017-05-15 18:41       ` Pierre-Louis Bossart
2017-05-10 18:49 ` [PATCH 1/2] ASoC: add es8316 codec driver Pierre-Louis Bossart
2017-05-10 19:18   ` Daniel Drake
2017-05-14  9:36     ` Mark Brown

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