summaryrefslogtreecommitdiff
path: root/sound/soc/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/Kconfig4
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/max98357a.c138
-rw-r--r--sound/soc/codecs/rt286.c31
-rw-r--r--sound/soc/codecs/rt286.h7
-rw-r--r--sound/soc/codecs/rt5645.c81
-rw-r--r--sound/soc/codecs/rt5645.h72
-rw-r--r--sound/soc/codecs/rt5670.c1
8 files changed, 293 insertions, 43 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 3190eed43c38..064e6c18e109 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -69,6 +69,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MAX98088 if I2C
select SND_SOC_MAX98090 if I2C
select SND_SOC_MAX98095 if I2C
+ select SND_SOC_MAX98357A
select SND_SOC_MAX9850 if I2C
select SND_SOC_MAX9768 if I2C
select SND_SOC_MAX9877 if I2C
@@ -456,6 +457,9 @@ config SND_SOC_MAX98090
config SND_SOC_MAX98095
tristate
+config SND_SOC_MAX98357A
+ tristate
+
config SND_SOC_MAX9850
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index bbdfd1e1c182..69b8666d187a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -64,6 +64,7 @@ snd-soc-max9768-objs := max9768.o
snd-soc-max98088-objs := max98088.o
snd-soc-max98090-objs := max98090.o
snd-soc-max98095-objs := max98095.o
+snd-soc-max98357a-objs := max98357a.o
snd-soc-max9850-objs := max9850.o
snd-soc-mc13783-objs := mc13783.o
snd-soc-ml26124-objs := ml26124.o
@@ -245,6 +246,7 @@ obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o
obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o
obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
+obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o
obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
new file mode 100644
index 000000000000..1806333ea29e
--- /dev/null
+++ b/sound/soc/codecs/max98357a.c
@@ -0,0 +1,138 @@
+/* Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * max98357a.c -- MAX98357A ALSA SoC Codec driver
+ */
+
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "max98357a"
+
+static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct gpio_desc *sdmode = snd_soc_dai_get_drvdata(dai);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ gpiod_set_value(sdmode, 1);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ gpiod_set_value(sdmode, 0);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget max98357a_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("SDMode", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_OUTPUT("Speaker"),
+};
+
+static const struct snd_soc_dapm_route max98357a_dapm_routes[] = {
+ {"Speaker", NULL, "SDMode"},
+};
+
+static int max98357a_codec_probe(struct snd_soc_codec *codec)
+{
+ struct gpio_desc *sdmode;
+
+ sdmode = devm_gpiod_get(codec->dev, "sdmode");
+ if (IS_ERR(sdmode)) {
+ dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n",
+ __func__, PTR_ERR(sdmode));
+ return PTR_ERR(sdmode);
+ }
+ gpiod_direction_output(sdmode, 0);
+ snd_soc_codec_set_drvdata(codec, sdmode);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver max98357a_codec_driver = {
+ .probe = max98357a_codec_probe,
+ .dapm_widgets = max98357a_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(max98357a_dapm_widgets),
+ .dapm_routes = max98357a_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(max98357a_dapm_routes),
+};
+
+static struct snd_soc_dai_ops max98357a_dai_ops = {
+ .trigger = max98357a_daiops_trigger,
+};
+
+static struct snd_soc_dai_driver max98357a_dai_driver = {
+ .name = DRV_NAME,
+ .playback = {
+ .stream_name = DRV_NAME "-playback",
+ .formats = SNDRV_PCM_FMTBIT_S16 |
+ SNDRV_PCM_FMTBIT_S24 |
+ SNDRV_PCM_FMTBIT_S32,
+ .rates = SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &max98357a_dai_ops,
+};
+
+static int max98357a_platform_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = snd_soc_register_codec(&pdev->dev, &max98357a_codec_driver,
+ &max98357a_dai_driver, 1);
+ if (ret)
+ dev_err(&pdev->dev, "%s() error registering codec driver: %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static int max98357a_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id max98357a_device_id[] = {
+ { .compatible = "maxim," DRV_NAME, },
+ {}
+};
+MODULE_DEVICE_TABLE(of, max98357a_device_id);
+#endif
+
+static struct platform_driver max98357a_platform_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = of_match_ptr(max98357a_device_id),
+ },
+ .probe = max98357a_platform_probe,
+ .remove = max98357a_platform_remove,
+};
+module_platform_driver(max98357a_platform_driver);
+
+MODULE_DESCRIPTION("Maxim MAX98357A Codec Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 8104d2285602..f374840a5a7c 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -34,6 +34,7 @@
#include "rt286.h"
#define RT286_VENDOR_ID 0x10ec0286
+#define RT288_VENDOR_ID 0x10ec0288
struct rt286_priv {
struct regmap *regmap;
@@ -305,6 +306,8 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
*hp = false;
*mic = false;
+ if (!rt286->codec)
+ return -EINVAL;
if (rt286->pdata.cbj_en) {
regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
*hp = buf & 0x80000000;
@@ -1169,6 +1172,7 @@ static const struct regmap_config rt286_regmap = {
static const struct i2c_device_id rt286_i2c_id[] = {
{"rt286", 0},
+ {"rt288", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, rt286_i2c_id);
@@ -1189,6 +1193,17 @@ static struct dmi_system_id force_combo_jack_table[] = {
{ }
};
+static struct dmi_system_id dmi_dell_dino[] = {
+ {
+ .ident = "Dell Dino",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_BOARD_NAME, "0144P8")
+ }
+ },
+ { }
+};
+
static int rt286_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1211,7 +1226,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
regmap_read(rt286->regmap,
RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &ret);
- if (ret != RT286_VENDOR_ID) {
+ if (ret != RT286_VENDOR_ID && ret != RT288_VENDOR_ID) {
dev_err(&i2c->dev,
"Device with ID register %x is not rt286\n", ret);
return -ENODEV;
@@ -1224,7 +1239,8 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
if (pdata)
rt286->pdata = *pdata;
- if (dmi_check_system(force_combo_jack_table))
+ if (dmi_check_system(force_combo_jack_table) ||
+ dmi_check_system(dmi_dell_dino))
rt286->pdata.cbj_en = true;
regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3);
@@ -1263,6 +1279,17 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737);
regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f);
+ if (dmi_check_system(dmi_dell_dino)) {
+ regmap_update_bits(rt286->regmap,
+ RT286_SET_GPIO_MASK, 0x40, 0x40);
+ regmap_update_bits(rt286->regmap,
+ RT286_SET_GPIO_DIRECTION, 0x40, 0x40);
+ regmap_update_bits(rt286->regmap,
+ RT286_SET_GPIO_DATA, 0x40, 0x40);
+ regmap_update_bits(rt286->regmap,
+ RT286_GPIO_CTRL, 0xc, 0x8);
+ }
+
if (rt286->i2c->irq) {
ret = request_threaded_irq(rt286->i2c->irq, NULL, rt286_irq,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt286", rt286);
diff --git a/sound/soc/codecs/rt286.h b/sound/soc/codecs/rt286.h
index b539b7320a79..7130edb152ef 100644
--- a/sound/soc/codecs/rt286.h
+++ b/sound/soc/codecs/rt286.h
@@ -117,6 +117,12 @@
VERB_CMD(AC_VERB_SET_COEF_INDEX, RT286_VENDOR_REGISTERS, 0)
#define RT286_PROC_COEF\
VERB_CMD(AC_VERB_SET_PROC_COEF, RT286_VENDOR_REGISTERS, 0)
+#define RT286_SET_GPIO_MASK\
+ VERB_CMD(AC_VERB_SET_GPIO_MASK, RT286_AUDIO_FUNCTION_GROUP, 0)
+#define RT286_SET_GPIO_DIRECTION\
+ VERB_CMD(AC_VERB_SET_GPIO_DIRECTION, RT286_AUDIO_FUNCTION_GROUP, 0)
+#define RT286_SET_GPIO_DATA\
+ VERB_CMD(AC_VERB_SET_GPIO_DATA, RT286_AUDIO_FUNCTION_GROUP, 0)
/* Index registers */
#define RT286_A_BIAS_CTRL1 0x01
@@ -131,6 +137,7 @@
#define RT286_POWER_CTRL3 0x0f
#define RT286_MIC1_DET_CTRL 0x19
#define RT286_MISC_CTRL1 0x20
+#define RT286_GPIO_CTRL 0x29
#define RT286_IRQ_CTRL 0x33
#define RT286_PLL_CTRL1 0x49
#define RT286_CBJ_CTRL1 0x4f
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 3e16a889a806..c9a4c5be083b 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -615,6 +615,87 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
}
+/**
+ * rt5645_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @codec: SoC audio codec device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5645 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec,
+ unsigned int filter_mask, unsigned int clk_src)
+{
+ unsigned int asrc2_mask = 0;
+ unsigned int asrc2_value = 0;
+ unsigned int asrc3_mask = 0;
+ unsigned int asrc3_value = 0;
+
+ switch (clk_src) {
+ case RT5645_CLK_SEL_SYS:
+ case RT5645_CLK_SEL_I2S1_ASRC:
+ case RT5645_CLK_SEL_I2S2_ASRC:
+ case RT5645_CLK_SEL_SYS2:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (filter_mask & RT5645_DA_STEREO_FILTER) {
+ asrc2_mask |= RT5645_DA_STO_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5645_DA_STO_CLK_SEL_MASK)
+ | (clk_src << RT5645_DA_STO_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5645_DA_MONO_L_FILTER) {
+ asrc2_mask |= RT5645_DA_MONOL_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5645_DA_MONOL_CLK_SEL_MASK)
+ | (clk_src << RT5645_DA_MONOL_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5645_DA_MONO_R_FILTER) {
+ asrc2_mask |= RT5645_DA_MONOR_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5645_DA_MONOR_CLK_SEL_MASK)
+ | (clk_src << RT5645_DA_MONOR_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5645_AD_STEREO_FILTER) {
+ asrc2_mask |= RT5645_AD_STO1_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5645_AD_STO1_CLK_SEL_MASK)
+ | (clk_src << RT5645_AD_STO1_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5645_AD_MONO_L_FILTER) {
+ asrc3_mask |= RT5645_AD_MONOL_CLK_SEL_MASK;
+ asrc3_value = (asrc3_value & ~RT5645_AD_MONOL_CLK_SEL_MASK)
+ | (clk_src << RT5645_AD_MONOL_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5645_AD_MONO_R_FILTER) {
+ asrc3_mask |= RT5645_AD_MONOR_CLK_SEL_MASK;
+ asrc3_value = (asrc3_value & ~RT5645_AD_MONOR_CLK_SEL_MASK)
+ | (clk_src << RT5645_AD_MONOR_CLK_SEL_SFT);
+ }
+
+ if (asrc2_mask)
+ snd_soc_update_bits(codec, RT5645_ASRC_2,
+ asrc2_mask, asrc2_value);
+
+ if (asrc3_mask)
+ snd_soc_update_bits(codec, RT5645_ASRC_3,
+ asrc3_mask, asrc3_value);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt5645_sel_asrc_clk_src);
+
/* Digital Mixer */
static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER,
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
index 74542310d3f0..dbfd98c22f4d 100644
--- a/sound/soc/codecs/rt5645.h
+++ b/sound/soc/codecs/rt5645.h
@@ -1120,50 +1120,27 @@
#define RT5645_DMIC_2_M_NOR (0x0 << 8)
#define RT5645_DMIC_2_M_ASYN (0x1 << 8)
+/* ASRC clock source selection (0x84, 0x85) */
+#define RT5645_CLK_SEL_SYS (0x0)
+#define RT5645_CLK_SEL_I2S1_ASRC (0x1)
+#define RT5645_CLK_SEL_I2S2_ASRC (0x2)
+#define RT5645_CLK_SEL_SYS2 (0x5)
+
/* ASRC Control 2 (0x84) */
-#define RT5645_MDA_L_M_MASK (0x1 << 15)
-#define RT5645_MDA_L_M_SFT 15
-#define RT5645_MDA_L_M_NOR (0x0 << 15)
-#define RT5645_MDA_L_M_ASYN (0x1 << 15)
-#define RT5645_MDA_R_M_MASK (0x1 << 14)
-#define RT5645_MDA_R_M_SFT 14
-#define RT5645_MDA_R_M_NOR (0x0 << 14)
-#define RT5645_MDA_R_M_ASYN (0x1 << 14)
-#define RT5645_MAD_L_M_MASK (0x1 << 13)
-#define RT5645_MAD_L_M_SFT 13
-#define RT5645_MAD_L_M_NOR (0x0 << 13)
-#define RT5645_MAD_L_M_ASYN (0x1 << 13)
-#define RT5645_MAD_R_M_MASK (0x1 << 12)
-#define RT5645_MAD_R_M_SFT 12
-#define RT5645_MAD_R_M_NOR (0x0 << 12)
-#define RT5645_MAD_R_M_ASYN (0x1 << 12)
-#define RT5645_ADC_M_MASK (0x1 << 11)
-#define RT5645_ADC_M_SFT 11
-#define RT5645_ADC_M_NOR (0x0 << 11)
-#define RT5645_ADC_M_ASYN (0x1 << 11)
-#define RT5645_STO_DAC_M_MASK (0x1 << 5)
-#define RT5645_STO_DAC_M_SFT 5
-#define RT5645_STO_DAC_M_NOR (0x0 << 5)
-#define RT5645_STO_DAC_M_ASYN (0x1 << 5)
-#define RT5645_I2S1_R_D_MASK (0x1 << 4)
-#define RT5645_I2S1_R_D_SFT 4
-#define RT5645_I2S1_R_D_DIS (0x0 << 4)
-#define RT5645_I2S1_R_D_EN (0x1 << 4)
-#define RT5645_I2S2_R_D_MASK (0x1 << 3)
-#define RT5645_I2S2_R_D_SFT 3
-#define RT5645_I2S2_R_D_DIS (0x0 << 3)
-#define RT5645_I2S2_R_D_EN (0x1 << 3)
-#define RT5645_PRE_SCLK_MASK (0x3)
-#define RT5645_PRE_SCLK_SFT 0
-#define RT5645_PRE_SCLK_512 (0x0)
-#define RT5645_PRE_SCLK_1024 (0x1)
-#define RT5645_PRE_SCLK_2048 (0x2)
+#define RT5645_DA_STO_CLK_SEL_MASK (0xf << 12)
+#define RT5645_DA_STO_CLK_SEL_SFT 12
+#define RT5645_DA_MONOL_CLK_SEL_MASK (0xf << 8)
+#define RT5645_DA_MONOL_CLK_SEL_SFT 8
+#define RT5645_DA_MONOR_CLK_SEL_MASK (0xf << 4)
+#define RT5645_DA_MONOR_CLK_SEL_SFT 4
+#define RT5645_AD_STO1_CLK_SEL_MASK (0xf << 0)
+#define RT5645_AD_STO1_CLK_SEL_SFT 0
/* ASRC Control 3 (0x85) */
-#define RT5645_I2S1_RATE_MASK (0xf << 12)
-#define RT5645_I2S1_RATE_SFT 12
-#define RT5645_I2S2_RATE_MASK (0xf << 8)
-#define RT5645_I2S2_RATE_SFT 8
+#define RT5645_AD_MONOL_CLK_SEL_MASK (0xf << 4)
+#define RT5645_AD_MONOL_CLK_SEL_SFT 4
+#define RT5645_AD_MONOR_CLK_SEL_MASK (0xf << 0)
+#define RT5645_AD_MONOR_CLK_SEL_SFT 0
/* ASRC Control 4 (0x89) */
#define RT5645_I2S1_PD_MASK (0x7 << 12)
@@ -2189,6 +2166,19 @@ enum {
CODEC_TYPE_RT5650,
};
+/* filter mask */
+enum {
+ RT5645_DA_STEREO_FILTER = 0x1,
+ RT5645_DA_MONO_L_FILTER = (0x1 << 1),
+ RT5645_DA_MONO_R_FILTER = (0x1 << 2),
+ RT5645_AD_STEREO_FILTER = (0x1 << 3),
+ RT5645_AD_MONO_L_FILTER = (0x1 << 4),
+ RT5645_AD_MONO_R_FILTER = (0x1 << 5),
+};
+
+int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec,
+ unsigned int filter_mask, unsigned int clk_src);
+
struct rt5645_priv {
struct snd_soc_codec *codec;
struct rt5645_platform_data pdata;
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index 7b3d6b5992f1..e1a4a45c57e2 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -2616,6 +2616,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5670 = {
static const struct regmap_config rt5670_regmap = {
.reg_bits = 8,
.val_bits = 16,
+ .use_single_rw = true,
.max_register = RT5670_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5670_ranges) *
RT5670_PR_SPACING),
.volatile_reg = rt5670_volatile_register,