summaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/Kconfig5
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/ak4613.c95
-rw-r--r--sound/soc/codecs/ak4642.c4
-rw-r--r--sound/soc/codecs/cs35l34.c4
-rw-r--r--sound/soc/codecs/cs35l35.c94
-rw-r--r--sound/soc/codecs/cs35l35.h6
-rw-r--r--sound/soc/codecs/cs4271.c2
-rw-r--r--sound/soc/codecs/cs53l30.c2
-rw-r--r--sound/soc/codecs/da7213.c39
-rw-r--r--sound/soc/codecs/da7218.c2
-rw-r--r--sound/soc/codecs/da7219-aad.c31
-rw-r--r--sound/soc/codecs/da7219.c53
-rw-r--r--sound/soc/codecs/da7219.h5
-rw-r--r--sound/soc/codecs/es8316.c637
-rw-r--r--sound/soc/codecs/es8316.h129
-rw-r--r--sound/soc/codecs/rt286.c7
-rw-r--r--sound/soc/codecs/rt5645.c1
-rw-r--r--sound/soc/codecs/rt5663.c4
-rw-r--r--sound/soc/codecs/rt5663.h4
-rw-r--r--sound/soc/codecs/rt5670.c14
-rw-r--r--sound/soc/codecs/rt5677.c32
22 files changed, 1073 insertions, 99 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 883ed4c8a551..f0f794186186 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,10 @@ config SND_SOC_HDMI_CODEC
config SND_SOC_ES7134
tristate "Everest Semi ES7134 CODEC"
+config SND_SOC_ES8316
+ tristate "Everest Semi ES8316 CODEC"
+ depends on I2C
+
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/ak4613.c b/sound/soc/codecs/ak4613.c
index b2dfddead227..690edebf029e 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -94,6 +94,8 @@ struct ak4613_interface {
struct ak4613_priv {
struct mutex lock;
const struct ak4613_interface *iface;
+ struct snd_pcm_hw_constraint_list constraint;
+ unsigned int sysclk;
unsigned int fmt;
u8 oc;
@@ -139,9 +141,7 @@ static const struct reg_default ak4613_reg[] = {
#define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt }
static const struct ak4613_interface ak4613_iface[] = {
/* capture */ /* playback */
- [0] = { AUDIO_IFACE(24, LEFT_J), AUDIO_IFACE(16, RIGHT_J) },
- [1] = { AUDIO_IFACE(24, LEFT_J), AUDIO_IFACE(20, RIGHT_J) },
- [2] = { AUDIO_IFACE(24, LEFT_J), AUDIO_IFACE(24, RIGHT_J) },
+ /* [0] - [2] are not supported */
[3] = { AUDIO_IFACE(24, LEFT_J), AUDIO_IFACE(24, LEFT_J) },
[4] = { AUDIO_IFACE(24, I2S), AUDIO_IFACE(24, I2S) },
};
@@ -254,6 +254,74 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
mutex_unlock(&priv->lock);
}
+static void ak4613_hw_constraints(struct ak4613_priv *priv,
+ struct snd_pcm_runtime *runtime)
+{
+ static const unsigned int ak4613_rates[] = {
+ 32000,
+ 44100,
+ 48000,
+ 64000,
+ 88200,
+ 96000,
+ 176400,
+ 192000,
+ };
+ struct snd_pcm_hw_constraint_list *constraint = &priv->constraint;
+ unsigned int fs;
+ int i;
+
+ constraint->list = ak4613_rates;
+ constraint->mask = 0;
+ constraint->count = 0;
+
+ /*
+ * Slave Mode
+ * Normal: [32kHz, 48kHz] : 256fs,384fs or 512fs
+ * Double: [64kHz, 96kHz] : 256fs
+ * Quad : [128kHz,192kHz]: 128fs
+ *
+ * Master mode
+ * Normal: [32kHz, 48kHz] : 256fs or 512fs
+ * Double: [64kHz, 96kHz] : 256fs
+ * Quad : [128kHz,192kHz]: 128fs
+ */
+ for (i = 0; i < ARRAY_SIZE(ak4613_rates); i++) {
+ /* minimum fs on each range */
+ fs = (ak4613_rates[i] <= 96000) ? 256 : 128;
+
+ if (priv->sysclk >= ak4613_rates[i] * fs)
+ constraint->count = i + 1;
+ }
+
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, constraint);
+}
+
+static int ak4613_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ priv->cnt++;
+
+ ak4613_hw_constraints(priv, substream->runtime);
+
+ return 0;
+}
+
+static int ak4613_dai_set_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ priv->sysclk = freq;
+
+ return 0;
+}
+
static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_codec *codec = dai->codec;
@@ -262,11 +330,9 @@ static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
fmt &= SND_SOC_DAIFMT_FORMAT_MASK;
switch (fmt) {
- case SND_SOC_DAIFMT_RIGHT_J:
case SND_SOC_DAIFMT_LEFT_J:
case SND_SOC_DAIFMT_I2S:
priv->fmt = fmt;
-
break;
default:
return -EINVAL;
@@ -286,13 +352,8 @@ static bool ak4613_dai_fmt_matching(const struct ak4613_interface *iface,
if (fmts->fmt != fmt)
return false;
- if (fmt == SND_SOC_DAIFMT_RIGHT_J) {
- if (fmts->width != width)
- return false;
- } else {
- if (fmts->width < width)
- return false;
- }
+ if (fmts->width != width)
+ return false;
return true;
}
@@ -319,6 +380,7 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
case 48000:
ctrl2 = DFS_NORMAL_SPEED;
break;
+ case 64000:
case 88200:
case 96000:
ctrl2 = DFS_DOUBLE_SPEED;
@@ -345,7 +407,7 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
if (ak4613_dai_fmt_matching(priv->iface, is_play, fmt, width))
iface = priv->iface;
} else {
- for (i = ARRAY_SIZE(ak4613_iface); i >= 0; i--) {
+ for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) {
if (!ak4613_dai_fmt_matching(ak4613_iface + i,
is_play,
fmt, width))
@@ -358,7 +420,6 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
if ((priv->iface == NULL) ||
(priv->iface == iface)) {
priv->iface = iface;
- priv->cnt++;
ret = 0;
}
mutex_unlock(&priv->lock);
@@ -407,7 +468,9 @@ static int ak4613_set_bias_level(struct snd_soc_codec *codec,
}
static const struct snd_soc_dai_ops ak4613_dai_ops = {
+ .startup = ak4613_dai_startup,
.shutdown = ak4613_dai_shutdown,
+ .set_sysclk = ak4613_dai_set_sysclk,
.set_fmt = ak4613_dai_set_fmt,
.hw_params = ak4613_dai_hw_params,
};
@@ -420,8 +483,7 @@ static const struct snd_soc_dai_ops ak4613_dai_ops = {
SNDRV_PCM_RATE_96000 |\
SNDRV_PCM_RATE_176400 |\
SNDRV_PCM_RATE_192000)
-#define AK4613_PCM_FMTBIT (SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S24_LE)
+#define AK4613_PCM_FMTBIT (SNDRV_PCM_FMTBIT_S24_LE)
static struct snd_soc_dai_driver ak4613_dai = {
.name = "ak4613-hifi",
@@ -527,6 +589,7 @@ static int ak4613_i2c_probe(struct i2c_client *i2c,
priv->iface = NULL;
priv->cnt = 0;
+ priv->sysclk = 0;
mutex_init(&priv->lock);
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 23ab9646c351..66de8a2013a6 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -433,7 +433,7 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
static int ak4642_set_mcko(struct snd_soc_codec *codec,
u32 frequency)
{
- u32 fs_list[] = {
+ static const u32 fs_list[] = {
[0] = 8000,
[1] = 12000,
[2] = 16000,
@@ -447,7 +447,7 @@ static int ak4642_set_mcko(struct snd_soc_codec *codec,
[14] = 29400,
[15] = 44100,
};
- u32 ps_list[] = {
+ static const u32 ps_list[] = {
[0] = 256,
[1] = 128,
[2] = 64,
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
index 7c5d1510cf2c..0a747c66cc6c 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -567,12 +567,12 @@ static int cs35l34_pcm_hw_params(struct snd_pcm_substream *substream,
return ret;
}
-static unsigned int cs35l34_src_rates[] = {
+static const unsigned int cs35l34_src_rates[] = {
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
};
-static struct snd_pcm_hw_constraint_list cs35l34_constraints = {
+static const struct snd_pcm_hw_constraint_list cs35l34_constraints = {
.count = ARRAY_SIZE(cs35l34_src_rates),
.list = cs35l34_src_rates,
};
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
index f8aef5869b03..f1ee184ecab2 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -162,6 +162,14 @@ static bool cs35l35_precious_register(struct device *dev, unsigned int reg)
}
}
+static void cs35l35_reset(struct cs35l35_private *cs35l35)
+{
+ gpiod_set_value_cansleep(cs35l35->reset_gpio, 0);
+ usleep_range(2000, 2100);
+ gpiod_set_value_cansleep(cs35l35->reset_gpio, 1);
+ usleep_range(1000, 1100);
+}
+
static int cs35l35_wait_for_pdn(struct cs35l35_private *cs35l35)
{
int ret;
@@ -756,6 +764,76 @@ static int cs35l35_codec_set_sysclk(struct snd_soc_codec *codec,
return ret;
}
+static int cs35l35_boost_inductor(struct cs35l35_private *cs35l35,
+ int inductor)
+{
+ struct regmap *regmap = cs35l35->regmap;
+ unsigned int bst_ipk = 0;
+
+ /*
+ * Digital Boost Converter Configuration for feedback,
+ * ramping, switching frequency, and estimation block seeding.
+ */
+
+ regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+ CS35L35_BST_CONV_SWFREQ_MASK, 0x00);
+
+ regmap_read(regmap, CS35L35_BST_PEAK_I, &bst_ipk);
+ bst_ipk &= CS35L35_BST_IPK_MASK;
+
+ switch (inductor) {
+ case 1000: /* 1 uH */
+ regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x24);
+ regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x24);
+ regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+ CS35L35_BST_CONV_LBST_MASK, 0x00);
+
+ if (bst_ipk < 0x04)
+ regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B);
+ else
+ regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x4E);
+ break;
+ case 1200: /* 1.2 uH */
+ regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x20);
+ regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x20);
+ regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+ CS35L35_BST_CONV_LBST_MASK, 0x01);
+
+ if (bst_ipk < 0x04)
+ regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B);
+ else
+ regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x47);
+ break;
+ case 1500: /* 1.5uH */
+ regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x20);
+ regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x20);
+ regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+ CS35L35_BST_CONV_LBST_MASK, 0x02);
+
+ if (bst_ipk < 0x04)
+ regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B);
+ else
+ regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x3C);
+ break;
+ case 2200: /* 2.2uH */
+ regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x19);
+ regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x25);
+ regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+ CS35L35_BST_CONV_LBST_MASK, 0x03);
+
+ if (bst_ipk < 0x04)
+ regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B);
+ else
+ regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x23);
+ break;
+ default:
+ dev_err(cs35l35->dev, "Invalid Inductor Value %d uH\n",
+ inductor);
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int cs35l35_codec_probe(struct snd_soc_codec *codec)
{
struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
@@ -775,6 +853,10 @@ static int cs35l35_codec_probe(struct snd_soc_codec *codec)
cs35l35->pdata.bst_ipk <<
CS35L35_BST_IPK_SHIFT);
+ ret = cs35l35_boost_inductor(cs35l35, cs35l35->pdata.boost_ind);
+ if (ret)
+ return ret;
+
if (cs35l35->pdata.gain_zc)
regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL,
CS35L35_AMP_GAIN_ZC_MASK,
@@ -1195,7 +1277,15 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client,
return -EINVAL;
}
- pdata->bst_ipk = (val32 - 1680) / 110;
+ pdata->bst_ipk = ((val32 - 1680) / 110) | CS35L35_VALID_PDATA;
+ }
+
+ ret = of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val32);
+ if (ret >= 0) {
+ pdata->boost_ind = val32;
+ } else {
+ dev_err(&i2c_client->dev, "Inductor not specified.\n");
+ return -EINVAL;
}
if (of_property_read_u32(np, "cirrus,sp-drv-strength", &val32) >= 0)
@@ -1454,7 +1544,7 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client,
}
}
- gpiod_set_value_cansleep(cs35l35->reset_gpio, 1);
+ cs35l35_reset(cs35l35);
init_completion(&cs35l35->pdn_done);
diff --git a/sound/soc/codecs/cs35l35.h b/sound/soc/codecs/cs35l35.h
index 5a6e43a87c4d..621bfef70d03 100644
--- a/sound/soc/codecs/cs35l35.h
+++ b/sound/soc/codecs/cs35l35.h
@@ -200,6 +200,12 @@
#define CS35L35_SP_I2S_DRV_MASK 0x03
#define CS35L35_SP_I2S_DRV_SHIFT 0
+/* Boost Converter Config */
+#define CS35L35_BST_CONV_COEFF_MASK 0xFF
+#define CS35L35_BST_CONV_SLOPE_MASK 0xFF
+#define CS35L35_BST_CONV_LBST_MASK 0x03
+#define CS35L35_BST_CONV_SWFREQ_MASK 0xF0
+
/* Class H Algorithm Control */
#define CS35L35_CH_STEREO_MASK 0x40
#define CS35L35_CH_STEREO_SHIFT 6
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index e78b5f055f25..d8824773dc29 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -674,8 +674,6 @@ static int cs4271_common_probe(struct device *dev,
cs4271->gpio_nreset = cs4271plat->gpio_nreset;
if (gpio_is_valid(cs4271->gpio_nreset)) {
- int ret;
-
ret = devm_gpio_request(dev, cs4271->gpio_nreset,
"CS4271 Reset");
if (ret < 0)
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index 1e0d5973b758..06933a5d0a75 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -747,7 +747,7 @@ static unsigned int const cs53l30_src_rates[] = {
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
};
-static struct snd_pcm_hw_constraint_list src_constraints = {
+static const struct snd_pcm_hw_constraint_list src_constraints = {
.count = ARRAY_SIZE(cs53l30_src_rates),
.list = cs53l30_src_rates,
};
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 6dd7578f0bb8..c3e11897f8ae 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -13,6 +13,8 @@
*/
#include <linux/acpi.h>
+#include <linux/of_device.h>
+#include <linux/property.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -772,7 +774,7 @@ static int da7213_dai_event(struct snd_soc_dapm_widget *w,
++i;
msleep(50);
}
- } while ((i < DA7213_SRM_CHECK_RETRIES) & (!srm_lock));
+ } while ((i < DA7213_SRM_CHECK_RETRIES) && (!srm_lock));
if (!srm_lock)
dev_warn(codec->dev, "SRM failed to lock\n");
@@ -1606,12 +1608,12 @@ static enum da7213_dmic_clk_rate
}
static struct da7213_platform_data
- *da7213_of_to_pdata(struct snd_soc_codec *codec)
+ *da7213_fw_to_pdata(struct snd_soc_codec *codec)
{
- struct device_node *np = codec->dev->of_node;
+ struct device *dev = codec->dev;
struct da7213_platform_data *pdata;
- const char *of_str;
- u32 of_val32;
+ const char *fw_str;
+ u32 fw_val32;
pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
@@ -1619,29 +1621,29 @@ static struct da7213_platform_data
return NULL;
}
- if (of_property_read_u32(np, "dlg,micbias1-lvl", &of_val32) >= 0)
- pdata->micbias1_lvl = da7213_of_micbias_lvl(codec, of_val32);
+ if (device_property_read_u32(dev, "dlg,micbias1-lvl", &fw_val32) >= 0)
+ pdata->micbias1_lvl = da7213_of_micbias_lvl(codec, fw_val32);
else
pdata->micbias1_lvl = DA7213_MICBIAS_2_2V;
- if (of_property_read_u32(np, "dlg,micbias2-lvl", &of_val32) >= 0)
- pdata->micbias2_lvl = da7213_of_micbias_lvl(codec, of_val32);
+ if (device_property_read_u32(dev, "dlg,micbias2-lvl", &fw_val32) >= 0)
+ pdata->micbias2_lvl = da7213_of_micbias_lvl(codec, fw_val32);
else
pdata->micbias2_lvl = DA7213_MICBIAS_2_2V;
- if (!of_property_read_string(np, "dlg,dmic-data-sel", &of_str))
- pdata->dmic_data_sel = da7213_of_dmic_data_sel(codec, of_str);
+ if (!device_property_read_string(dev, "dlg,dmic-data-sel", &fw_str))
+ pdata->dmic_data_sel = da7213_of_dmic_data_sel(codec, fw_str);
else
pdata->dmic_data_sel = DA7213_DMIC_DATA_LRISE_RFALL;
- if (!of_property_read_string(np, "dlg,dmic-samplephase", &of_str))
+ if (!device_property_read_string(dev, "dlg,dmic-samplephase", &fw_str))
pdata->dmic_samplephase =
- da7213_of_dmic_samplephase(codec, of_str);
+ da7213_of_dmic_samplephase(codec, fw_str);
else
pdata->dmic_samplephase = DA7213_DMIC_SAMPLE_ON_CLKEDGE;
- if (of_property_read_u32(np, "dlg,dmic-clkrate", &of_val32) >= 0)
- pdata->dmic_clk_rate = da7213_of_dmic_clkrate(codec, of_val32);
+ if (device_property_read_u32(dev, "dlg,dmic-clkrate", &fw_val32) >= 0)
+ pdata->dmic_clk_rate = da7213_of_dmic_clkrate(codec, fw_val32);
else
pdata->dmic_clk_rate = DA7213_DMIC_CLK_3_0MHZ;
@@ -1713,10 +1715,9 @@ static int da7213_probe(struct snd_soc_codec *codec)
DA7213_LINE_AMP_OE, DA7213_LINE_AMP_OE);
/* Handle DT/Platform data */
- if (codec->dev->of_node)
- da7213->pdata = da7213_of_to_pdata(codec);
- else
- da7213->pdata = dev_get_platdata(codec->dev);
+ da7213->pdata = dev_get_platdata(codec->dev);
+ if (!da7213->pdata)
+ da7213->pdata = da7213_fw_to_pdata(codec);
/* Set platform data values */
if (da7213->pdata) {
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index d256ebf9e309..6e1940eb0653 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -1457,7 +1457,7 @@ static int da7218_dai_event(struct snd_soc_dapm_widget *w,
++i;
msleep(DA7218_SRM_CHECK_DELAY);
}
- } while ((i < DA7218_SRM_CHECK_TRIES) & (!success));
+ } while ((i < DA7218_SRM_CHECK_TRIES) && (!success));
if (!success)
dev_warn(codec->dev, "SRM failed to lock\n");
diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c
index 6274d79c1353..1d1d10dd92ae 100644
--- a/sound/soc/codecs/da7219-aad.c
+++ b/sound/soc/codecs/da7219-aad.c
@@ -115,19 +115,21 @@ static void da7219_aad_hptest_work(struct work_struct *work)
struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
u16 tonegen_freq_hptest;
- u8 pll_srm_sts, gain_ramp_ctrl, accdet_cfg8;
+ u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8;
int report = 0, ret = 0;
- /* Lock DAPM and any Kcontrols that are affected by this test */
+ /* Lock DAPM, Kcontrols affected by this test and the PLL */
snd_soc_dapm_mutex_lock(dapm);
- mutex_lock(&da7219->lock);
+ mutex_lock(&da7219->ctrl_lock);
+ mutex_lock(&da7219->pll_lock);
/* Ensure MCLK is available for HP test procedure */
if (da7219->mclk) {
ret = clk_prepare_enable(da7219->mclk);
if (ret) {
dev_err(codec->dev, "Failed to enable mclk - %d\n", ret);
- mutex_unlock(&da7219->lock);
+ mutex_unlock(&da7219->pll_lock);
+ mutex_unlock(&da7219->ctrl_lock);
snd_soc_dapm_mutex_unlock(dapm);
return;
}
@@ -136,12 +138,21 @@ static void da7219_aad_hptest_work(struct work_struct *work)
/*
* If MCLK not present, then we're using the internal oscillator and
* require different frequency settings to achieve the same result.
+ *
+ * If MCLK is present, but PLL is not enabled then we enable it here to
+ * ensure a consistent detection procedure.
*/
pll_srm_sts = snd_soc_read(codec, DA7219_PLL_SRM_STS);
- if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK)
+ if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) {
tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ);
- else
+
+ pll_ctrl = snd_soc_read(codec, DA7219_PLL_CTRL);
+ if ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS)
+ da7219_set_pll(codec, DA7219_SYSCLK_PLL,
+ DA7219_PLL_FREQ_OUT_98304);
+ } else {
tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC);
+ }
/* Ensure gain ramping at fastest rate */
gain_ramp_ctrl = snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL);
@@ -302,11 +313,17 @@ static void da7219_aad_hptest_work(struct work_struct *work)
snd_soc_update_bits(codec, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK,
DA7219_HP_R_AMP_OE_MASK);
+ /* Restore PLL to previous configuration, if re-configured */
+ if ((pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) &&
+ ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS))
+ da7219_set_pll(codec, DA7219_SYSCLK_MCLK, 0);
+
/* Remove MCLK, if previously enabled */
if (da7219->mclk)
clk_disable_unprepare(da7219->mclk);
- mutex_unlock(&da7219->lock);
+ mutex_unlock(&da7219->pll_lock);
+ mutex_unlock(&da7219->ctrl_lock);
snd_soc_dapm_mutex_unlock(dapm);
/*
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 99601627f83c..f71d72c22bfc 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -260,9 +260,9 @@ static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol,
struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
int ret;
- mutex_lock(&da7219->lock);
+ mutex_lock(&da7219->ctrl_lock);
ret = snd_soc_get_volsw(kcontrol, ucontrol);
- mutex_unlock(&da7219->lock);
+ mutex_unlock(&da7219->ctrl_lock);
return ret;
}
@@ -274,9 +274,9 @@ static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol,
struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
int ret;
- mutex_lock(&da7219->lock);
+ mutex_lock(&da7219->ctrl_lock);
ret = snd_soc_put_volsw(kcontrol, ucontrol);
- mutex_unlock(&da7219->lock);
+ mutex_unlock(&da7219->ctrl_lock);
return ret;
}
@@ -288,9 +288,9 @@ static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol,
struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
int ret;
- mutex_lock(&da7219->lock);
+ mutex_lock(&da7219->ctrl_lock);
ret = snd_soc_get_enum_double(kcontrol, ucontrol);
- mutex_unlock(&da7219->lock);
+ mutex_unlock(&da7219->ctrl_lock);
return ret;
}
@@ -302,9 +302,9 @@ static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol,
struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
int ret;
- mutex_lock(&da7219->lock);
+ mutex_lock(&da7219->ctrl_lock);
ret = snd_soc_put_enum_double(kcontrol, ucontrol);
- mutex_unlock(&da7219->lock);
+ mutex_unlock(&da7219->ctrl_lock);
return ret;
}
@@ -424,9 +424,9 @@ static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol,
u16 val;
int ret;
- mutex_lock(&da7219->lock);
+ mutex_lock(&da7219->ctrl_lock);
ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val));
- mutex_unlock(&da7219->lock);
+ mutex_unlock(&da7219->ctrl_lock);
if (ret)
return ret;
@@ -458,9 +458,9 @@ static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol,
*/
val = cpu_to_le16(ucontrol->value.integer.value[0]);
- mutex_lock(&da7219->lock);
+ mutex_lock(&da7219->ctrl_lock);
ret = regmap_raw_write(da7219->regmap, reg, &val, sizeof(val));
- mutex_unlock(&da7219->lock);
+ mutex_unlock(&da7219->ctrl_lock);
return ret;
}
@@ -801,7 +801,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
++i;
msleep(50);
}
- } while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock));
+ } while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock));
if (!srm_lock)
dev_warn(codec->dev, "SRM failed to lock\n");
@@ -1129,6 +1129,8 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
return -EINVAL;
}
+ mutex_lock(&da7219->pll_lock);
+
switch (clk_id) {
case DA7219_CLKSRC_MCLK_SQR:
snd_soc_update_bits(codec, DA7219_PLL_CTRL,
@@ -1141,6 +1143,7 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
break;
default:
dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+ mutex_unlock(&da7219->pll_lock);
return -EINVAL;
}
@@ -1152,19 +1155,20 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
if (ret) {
dev_err(codec_dai->dev, "Failed to set clock rate %d\n",
freq);
+ mutex_unlock(&da7219->pll_lock);
return ret;
}
}
da7219->mclk_rate = freq;
+ mutex_unlock(&da7219->pll_lock);
+
return 0;
}
-static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
- int source, unsigned int fref, unsigned int fout)
+int da7219_set_pll(struct snd_soc_codec *codec, int source, unsigned int fout)
{
- struct snd_soc_codec *codec = codec_dai->codec;
struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
u8 pll_ctrl, indiv_bits, indiv;
@@ -1237,6 +1241,20 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
return 0;
}
+static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int fref, unsigned int fout)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ mutex_lock(&da7219->pll_lock);
+ ret = da7219_set_pll(codec, source, fout);
+ mutex_unlock(&da7219->pll_lock);
+
+ return ret;
+}
+
static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
@@ -1741,7 +1759,8 @@ static int da7219_probe(struct snd_soc_codec *codec)
unsigned int rev;
int ret;
- mutex_init(&da7219->lock);
+ mutex_init(&da7219->ctrl_lock);
+ mutex_init(&da7219->pll_lock);
/* Regulator configuration */
ret = da7219_handle_supplies(codec);
diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h
index 6baba7455fa1..8d6c3c8c8026 100644
--- a/sound/soc/codecs/da7219.h
+++ b/sound/soc/codecs/da7219.h
@@ -810,7 +810,8 @@ struct da7219_priv {
bool wakeup_source;
struct regulator_bulk_data supplies[DA7219_NUM_SUPPLIES];
struct regmap *regmap;
- struct mutex lock;
+ struct mutex ctrl_lock;
+ struct mutex pll_lock;
struct clk *mclk;
unsigned int mclk_rate;
@@ -821,4 +822,6 @@ struct da7219_priv {
u8 gain_ramp_ctrl;
};
+int da7219_set_pll(struct snd_soc_codec *codec, int source, unsigned int fout);
+
#endif /* __DA7219_H */
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
new file mode 100644
index 000000000000..ecc02449c569
--- /dev/null
+++ b/sound/soc/codecs/es8316.c
@@ -0,0 +1,637 @@
+/*
+ * 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 SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9600, 50, 1);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9600, 50, 1);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_max_gain_tlv, -650, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_min_gain_tlv, -1200, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_target_tlv, -1650, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(hpmixer_gain_tlv, -1200, 150, 0);
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(adc_pga_gain_tlv,
+ 0, 0, TLV_DB_SCALE_ITEM(-350, 0, 0),
+ 1, 1, TLV_DB_SCALE_ITEM(0, 0, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(250, 0, 0),
+ 3, 3, TLV_DB_SCALE_ITEM(450, 0, 0),
+ 4, 4, TLV_DB_SCALE_ITEM(700, 0, 0),
+ 5, 5, TLV_DB_SCALE_ITEM(1000, 0, 0),
+ 6, 6, TLV_DB_SCALE_ITEM(1300, 0, 0),
+ 7, 7, TLV_DB_SCALE_ITEM(1600, 0, 0),
+ 8, 8, TLV_DB_SCALE_ITEM(1800, 0, 0),
+ 9, 9, TLV_DB_SCALE_ITEM(2100, 0, 0),
+ 10, 10, TLV_DB_SCALE_ITEM(2400, 0, 0),
+);
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(hpout_vol_tlv,
+ 0, 0, TLV_DB_SCALE_ITEM(-4800, 0, 0),
+ 1, 3, TLV_DB_SCALE_ITEM(-2400, 1200, 0),
+);
+
+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_ALC_NG, 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("Headphone Playback Volume", ES8316_CPHP_ICAL_VOL,
+ 4, 0, 3, 1, hpout_vol_tlv),
+ SOC_DOUBLE_TLV("Headphone Mixer Volume", ES8316_HPMIX_VOL,
+ 0, 4, 7, 0, hpmixer_gain_tlv),
+
+ SOC_ENUM("Playback Polarity", dacpol),
+ SOC_DOUBLE_R_TLV("DAC Playback Volume", ES8316_DAC_VOLL,
+ ES8316_DAC_VOLR, 0, 0xc0, 1, dac_vol_tlv),
+ SOC_SINGLE("DAC Soft Ramp Switch", ES8316_DAC_SET1, 4, 1, 1),
+ SOC_SINGLE("DAC Soft Ramp Rate", ES8316_DAC_SET1, 2, 4, 0),
+ SOC_SINGLE("DAC Notch Filter Switch", ES8316_DAC_SET2, 6, 1, 0),
+ SOC_SINGLE("DAC Double Fs Switch", ES8316_DAC_SET2, 7, 1, 0),
+ SOC_SINGLE("DAC Stereo Enhancement", ES8316_DAC_SET3, 0, 7, 0),
+
+ SOC_ENUM("Capture Polarity", adcpol),
+ SOC_SINGLE("Mic Boost Switch", ES8316_ADC_D2SEPGA, 0, 1, 0),
+ SOC_SINGLE_TLV("ADC Capture Volume", ES8316_ADC_VOLUME,
+ 0, 0xc0, 1, adc_vol_tlv),
+ SOC_SINGLE_TLV("ADC PGA Gain Volume", ES8316_ADC_PGAGAIN,
+ 4, 10, 0, adc_pga_gain_tlv),
+ SOC_SINGLE("ADC Soft Ramp Switch", ES8316_ADC_MUTE, 4, 1, 0),
+ SOC_SINGLE("ADC Double Fs Switch", ES8316_ADC_DMIC, 4, 1, 0),
+
+ SOC_SINGLE("ALC Capture Switch", ES8316_ADC_ALC1, 6, 1, 0),
+ SOC_SINGLE_TLV("ALC Capture Max Volume", ES8316_ADC_ALC1, 0, 28, 0,
+ alc_max_gain_tlv),
+ SOC_SINGLE_TLV("ALC Capture Min Volume", ES8316_ADC_ALC2, 0, 28, 0,
+ alc_min_gain_tlv),
+ SOC_SINGLE_TLV("ALC Capture Target Volume", ES8316_ADC_ALC3, 4, 10, 0,
+ alc_target_tlv),
+ 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 Noise Gate Switch", ES8316_ADC_ALC_NG,
+ 5, 1, 0),
+ SOC_SINGLE("ALC Capture Noise Gate Threshold", ES8316_ADC_ALC_NG,
+ 0, 31, 0),
+ SOC_ENUM("ALC Capture Noise Gate Type", ng_type),
+};
+
+/* 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_SUPPLY("Bias", ES8316_SYS_PDN, 3, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Analog power", ES8316_SYS_PDN, 4, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Mic Bias", ES8316_SYS_PDN, 5, 1, NULL, 0),
+
+ SND_SOC_DAPM_INPUT("DMIC"),
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+
+ /* Input Mux */
+ SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+ &es8316_analog_in_mux_controls),
+
+ SND_SOC_DAPM_SUPPLY("ADC Vref", ES8316_SYS_PDN, 1, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC bias", ES8316_SYS_PDN, 2, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC Clock", ES8316_CLKMGR_CLKSW, 3, 0, NULL, 0),
+ 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 Source Mux", SND_SOC_NOPM, 0, 0,
+ &es8316_dacsrc_mux_controls),
+
+ SND_SOC_DAPM_SUPPLY("DAC Vref", ES8316_SYS_PDN, 0, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC Clock", ES8316_CLKMGR_CLKSW, 2, 0, NULL, 0),
+ SND_SOC_DAPM_DAC("Right DAC", NULL, ES8316_DAC_PDN, 0, 1),
+ SND_SOC_DAPM_DAC("Left DAC", NULL, ES8316_DAC_PDN, 4, 1),
+
+ /* Headphone Output Side */
+ SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0,
+ &es8316_left_hpmux_controls),
+ SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0,
+ &es8316_right_hpmux_controls),
+ SND_SOC_DAPM_MIXER("Left Headphone Mixer", ES8316_HPMIX_PDN,
+ 5, 1, &es8316_out_left_mix[0],
+ ARRAY_SIZE(es8316_out_left_mix)),
+ SND_SOC_DAPM_MIXER("Right Headphone Mixer", ES8316_HPMIX_PDN,
+ 1, 1, &es8316_out_right_mix[0],
+ ARRAY_SIZE(es8316_out_right_mix)),
+ SND_SOC_DAPM_PGA("Left Headphone Mixer Out", ES8316_HPMIX_PDN,
+ 4, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Headphone Mixer Out", ES8316_HPMIX_PDN,
+ 0, 1, NULL, 0),
+
+ SND_SOC_DAPM_OUT_DRV("Left Headphone Charge Pump", ES8316_CPHP_OUTEN,
+ 6, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("Right Headphone Charge Pump", ES8316_CPHP_OUTEN,
+ 2, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8316_CPHP_PDN2,
+ 5, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Headphone Charge Pump Clock", ES8316_CLKMGR_CLKSW,
+ 4, 0, NULL, 0),
+
+ SND_SOC_DAPM_OUT_DRV("Left Headphone Driver", ES8316_CPHP_OUTEN,
+ 5, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("Right Headphone Driver", ES8316_CPHP_OUTEN,
+ 1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Headphone Out", ES8316_CPHP_PDN1, 2, 1, NULL, 0),
+
+ /* pdn_Lical and pdn_Rical bits are documented as Reserved, but must
+ * be explicitly unset in order to enable HP output
+ */
+ SND_SOC_DAPM_SUPPLY("Left Headphone ical", ES8316_CPHP_ICAL_VOL,
+ 7, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Right Headphone ical", ES8316_CPHP_ICAL_VOL,
+ 3, 1, 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, "Mic Bias"},
+ {"MIC2", NULL, "Mic Bias"},
+ {"MIC1", NULL, "Bias"},
+ {"MIC2", NULL, "Bias"},
+ {"MIC1", NULL, "Analog power"},
+ {"MIC2", NULL, "Analog power"},
+
+ {"Differential Mux", "lin1-rin1", "MIC1"},
+ {"Differential Mux", "lin2-rin2", "MIC2"},
+ {"Line input PGA", NULL, "Differential Mux"},
+
+ {"Mono ADC", NULL, "ADC Clock"},
+ {"Mono ADC", NULL, "ADC Vref"},
+ {"Mono ADC", NULL, "ADC bias"},
+ {"Mono ADC", NULL, "Line input PGA"},
+
+ /* It's not clear why, but to avoid recording only silence,
+ * the DAC clock must be running for the ADC to work.
+ */
+ {"Mono ADC", NULL, "DAC Clock"},
+
+ {"Digital Mic Mux", "dmic disable", "Mono ADC"},
+
+ {"I2S OUT", NULL, "Digital Mic Mux"},
+
+ /* Playback */
+ {"DAC Source Mux", "LDATA TO LDAC, RDATA TO RDAC", "I2S IN"},
+
+ {"Left DAC", NULL, "DAC Clock"},
+ {"Right DAC", NULL, "DAC Clock"},
+
+ {"Left DAC", NULL, "DAC Vref"},
+ {"Right DAC", NULL, "DAC Vref"},
+
+ {"Left DAC", NULL, "DAC Source Mux"},
+ {"Right DAC", NULL, "DAC Source Mux"},
+
+ {"Left Headphone Mux", "lin-rin with Boost and PGA", "Line input PGA"},
+ {"Right Headphone Mux", "lin-rin with Boost and PGA", "Line input PGA"},
+
+ {"Left Headphone Mixer", "LLIN Switch", "Left Headphone Mux"},
+ {"Left Headphone Mixer", "Left DAC Switch", "Left DAC"},
+
+ {"Right Headphone Mixer", "RLIN Switch", "Right Headphone Mux"},
+ {"Right Headphone Mixer", "Right DAC Switch", "Right DAC"},
+
+ {"Left Headphone Mixer Out", NULL, "Left Headphone Mixer"},
+ {"Right Headphone Mixer Out", NULL, "Right Headphone Mixer"},
+
+ {"Left Headphone Charge Pump", NULL, "Left Headphone Mixer Out"},
+ {"Right Headphone Charge Pump", NULL, "Right Headphone Mixer Out"},
+
+ {"Left Headphone Charge Pump", NULL, "Headphone Charge Pump"},
+ {"Right Headphone Charge Pump", NULL, "Headphone Charge Pump"},
+
+ {"Left Headphone Charge Pump", NULL, "Headphone Charge Pump Clock"},
+ {"Right Headphone Charge Pump", NULL, "Headphone Charge Pump Clock"},
+
+ {"Left Headphone Driver", NULL, "Left Headphone Charge Pump"},
+ {"Right Headphone Driver", NULL, "Right Headphone Charge Pump"},
+
+ {"HPOL", NULL, "Left Headphone Driver"},
+ {"HPOR", NULL, "Right Headphone Driver"},
+
+ {"HPOL", NULL, "Left Headphone ical"},
+ {"HPOR", NULL, "Right Headphone ical"},
+
+ {"Headphone Out", NULL, "Bias"},
+ {"Headphone Out", NULL, "Analog power"},
+ {"HPOL", NULL, "Headphone Out"},
+ {"HPOR", NULL, "Headphone Out"},
+};
+
+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;
+ int count = 0;
+
+ es8316->sysclk = freq;
+
+ if (freq == 0)
+ return 0;
+
+ /* 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];
+
+ if (freq % ratio == 0)
+ es8316->allowed_rates[count++] = freq / ratio;
+ }
+
+ es8316->sysclk_constraints.list = es8316->allowed_rates;
+ es8316->sysclk_constraints.count = count;
+
+ 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 clksw;
+ 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);
+
+ /* Enable BCLK and MCLK inputs in slave mode */
+ clksw = ES8316_CLKMGR_CLKSW_MCLK_ON | ES8316_CLKMGR_CLKSW_BCLK_ON;
+ snd_soc_update_bits(codec, ES8316_CLKMGR_CLKSW, clksw, clksw);
+
+ 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);
+
+ if (es8316->sysclk == 0) {
+ dev_err(codec->dev, "No sysclk provided\n");
+ return -EINVAL;
+ }
+
+ /* The set of sample rates that can be supported depends on the
+ * MCLK supplied to the CODEC.
+ */
+ 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;
+}
+
+#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)
+{
+ /* Reset codec and enable current state machine */
+ snd_soc_write(codec, ES8316_RESET, 0x3f);
+ usleep_range(5000, 5500);
+ snd_soc_write(codec, ES8316_RESET, ES8316_RESET_CSM_ON);
+ msleep(30);
+
+ /*
+ * Documentation is unclear, but this value from the vendor driver is
+ * needed otherwise audio output is silent.
+ */
+ snd_soc_write(codec, ES8316_SYS_VMIDSEL, 0xff);
+
+ /*
+ * Documentation for this register is unclear and incomplete,
+ * but here is a vendor-provided value that improves volume
+ * and quality for Intel CHT platforms.
+ */
+ snd_soc_write(codec, ES8316_CLKMGR_ADCOSR, 0x32);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_es8316 = {
+ .probe = es8316_probe,
+ .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[] = {
+ {"es8316", 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..6bcdd63ea459
--- /dev/null
+++ b/sound/soc/codecs/es8316.h
@@ -0,0 +1,129 @@
+/*
+ * 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_ALC_NG 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_DEBOUNCE 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_RESET */
+#define ES8316_RESET_CSM_ON 0x80
+
+/* ES8316_CLKMGR_CLKSW */
+#define ES8316_CLKMGR_CLKSW_MCLK_ON 0x40
+#define ES8316_CLKMGR_CLKSW_BCLK_ON 0x20
+
+/* 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
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 9c365a7f758d..7899a2cdeb42 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -1108,6 +1108,13 @@ static const struct dmi_system_id force_combo_jack_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Kabylake Client platform")
}
},
+ {
+ .ident = "Thinkpad Helix 2nd",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Helix 2nd")
+ }
+ },
{ }
};
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 87844a45886a..206b41688d96 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3897,6 +3897,7 @@ static int rt5645_i2c_remove(struct i2c_client *i2c)
cancel_delayed_work_sync(&rt5645->jack_detect_work);
cancel_delayed_work_sync(&rt5645->rcclock_work);
+ del_timer_sync(&rt5645->btn_check_timer);
snd_soc_unregister_codec(&i2c->dev);
regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies);
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index a32508d7dcfd..a33202affeb1 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -2847,6 +2847,8 @@ static int rt5663_resume(struct snd_soc_codec *codec)
regcache_cache_only(rt5663->regmap, false);
regcache_sync(rt5663->regmap);
+ rt5663_irq(0, rt5663);
+
return 0;
}
#else
@@ -3141,7 +3143,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
regmap_update_bits(rt5663->regmap, RT5663_DIG_MISC,
RT5663_DIG_GATE_CTRL_MASK, RT5663_DIG_GATE_CTRL_EN);
regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK,
- RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN);
+ RT5663_IRQ_MANUAL_MASK, RT5663_IRQ_MANUAL_EN);
regmap_update_bits(rt5663->regmap, RT5663_IRQ_1,
RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN);
regmap_update_bits(rt5663->regmap, RT5663_GPIO_1,
diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h
index d77fae619f2f..4621812c94d8 100644
--- a/sound/soc/codecs/rt5663.h
+++ b/sound/soc/codecs/rt5663.h
@@ -590,6 +590,10 @@
#define RT5663_IRQ_POW_SAV_JD1_SHIFT 14
#define RT5663_IRQ_POW_SAV_JD1_DIS (0x0 << 14)
#define RT5663_IRQ_POW_SAV_JD1_EN (0x1 << 14)
+#define RT5663_IRQ_MANUAL_MASK (0x1 << 8)
+#define RT5663_IRQ_MANUAL_SHIFT 8
+#define RT5663_IRQ_MANUAL_DIS (0x0 << 8)
+#define RT5663_IRQ_MANUAL_EN (0x1 << 8)
/* IRQ Control 1 (0x00b6) */
#define RT5663_EN_CB_JD_MASK (0x1 << 3)
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index e27c5a4a0a15..a5f15a104c47 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -1717,7 +1717,6 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
/* DSP */
SND_SOC_DAPM_PGA("TxDP_ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -2086,13 +2085,13 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
{ "IF1 ADC1 IN1 Mux", "IF1_ADC3", "IF1_ADC3" },
{ "IF1 ADC1 IN2 Mux", "IF1_ADC1_IN1", "IF1 ADC1 IN1 Mux" },
- { "IF1 ADC1 IN2 Mux", "IF1_ADC4", "IF1_ADC4" },
+ { "IF1 ADC1 IN2 Mux", "IF1_ADC4", "TxDP_ADC" },
{ "IF1 ADC2 IN Mux", "IF_ADC2", "IF_ADC2" },
{ "IF1 ADC2 IN Mux", "VAD_ADC", "VAD_ADC" },
{ "IF1 ADC2 IN1 Mux", "IF1_ADC2_IN", "IF1 ADC2 IN Mux" },
- { "IF1 ADC2 IN1 Mux", "IF1_ADC4", "IF1_ADC4" },
+ { "IF1 ADC2 IN1 Mux", "IF1_ADC4", "TxDP_ADC" },
{ "IF1_ADC1" , NULL, "IF1 ADC1 IN2 Mux" },
{ "IF1_ADC2" , NULL, "IF1 ADC2 IN1 Mux" },
@@ -2849,6 +2848,10 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Tablet B"),
},
},
+ {}
+};
+
+static const struct dmi_system_id dmi_platform_intel_bytcht_jdmode2[] = {
{
.ident = "Lenovo Thinkpad Tablet 10",
.matches = {
@@ -2883,6 +2886,11 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
rt5670->pdata.dev_gpio = true;
rt5670->pdata.jd_mode = 1;
+ } else if (dmi_check_system(dmi_platform_intel_bytcht_jdmode2)) {
+ rt5670->pdata.dmic_en = true;
+ rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
+ rt5670->pdata.dev_gpio = true;
+ rt5670->pdata.jd_mode = 2;
}
rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap);
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 65ac4518ad06..36e530a36c82 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -41,15 +41,6 @@
#define RT5677_PR_BASE (RT5677_PR_RANGE_BASE + (0 * RT5677_PR_SPACING))
-/* GPIO indexes defined by ACPI */
-enum {
- RT5677_GPIO_PLUG_DET = 0,
- RT5677_GPIO_MIC_PRESENT_L = 1,
- RT5677_GPIO_HOTWORD_DET_L = 2,
- RT5677_GPIO_DSP_INT = 3,
- RT5677_GPIO_HP_AMP_SHDN_L = 4,
-};
-
static const struct regmap_range_cfg rt5677_ranges[] = {
{
.name = "PR",
@@ -5030,7 +5021,6 @@ static const struct regmap_config rt5677_regmap = {
static const struct i2c_device_id rt5677_i2c_id[] = {
{ "rt5677", RT5677 },
{ "rt5676", RT5676 },
- { "RT5677CE:00", RT5677 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
@@ -5041,28 +5031,19 @@ static const struct of_device_id rt5677_of_match[] = {
};
MODULE_DEVICE_TABLE(of, rt5677_of_match);
-static const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false };
-static const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false };
-static const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false };
-
-static const struct acpi_gpio_mapping bdw_rt5677_gpios[] = {
- { "plug-det-gpios", &plug_det_gpio, 1 },
- { "mic-present-gpios", &mic_present_gpio, 1 },
- { "headphone-enable-gpios", &headphone_enable_gpio, 1 },
- { NULL },
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5677_acpi_match[] = {
+ { "RT5677CE", RT5677 },
+ { }
};
+MODULE_DEVICE_TABLE(acpi, rt5677_acpi_match);
+#endif
static void rt5677_read_acpi_properties(struct rt5677_priv *rt5677,
struct device *dev)
{
- int ret;
u32 val;
- ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev),
- bdw_rt5677_gpios);
- if (ret)
- dev_warn(dev, "Failed to add driver gpios\n");
-
if (!device_property_read_u32(dev, "DCLK", &val))
rt5677->pdata.dmic2_clk_pin = val;
@@ -5301,6 +5282,7 @@ static struct i2c_driver rt5677_i2c_driver = {
.driver = {
.name = "rt5677",
.of_match_table = rt5677_of_match,
+ .acpi_match_table = ACPI_PTR(rt5677_acpi_match),
},
.probe = rt5677_i2c_probe,
.remove = rt5677_i2c_remove,
OpenPOWER on IntegriCloud