summaryrefslogtreecommitdiff
path: root/sound/soc/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/Kconfig9
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/adau1372.c1
-rw-r--r--sound/soc/codecs/adau1373.c1
-rw-r--r--sound/soc/codecs/adau17x1.c1
-rw-r--r--sound/soc/codecs/ak4458.c13
-rw-r--r--sound/soc/codecs/cs35l36.c4
-rw-r--r--sound/soc/codecs/cs42l83-i2c.c2
-rw-r--r--sound/soc/codecs/cs42xx8-i2c.c28
-rw-r--r--sound/soc/codecs/cs42xx8.c22
-rw-r--r--sound/soc/codecs/cs42xx8.h3
-rw-r--r--sound/soc/codecs/cx2072x.h2
-rw-r--r--sound/soc/codecs/da7219-aad.c4
-rw-r--r--sound/soc/codecs/da7219.c9
-rw-r--r--sound/soc/codecs/hda.c12
-rw-r--r--sound/soc/codecs/hdac_hda.c6
-rw-r--r--sound/soc/codecs/hdac_hdmi.c8
-rw-r--r--sound/soc/codecs/jz4725b.c109
-rw-r--r--sound/soc/codecs/lpass-tx-macro.c149
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.c6
-rw-r--r--sound/soc/codecs/mt6660.c8
-rw-r--r--sound/soc/codecs/nau8315.c2
-rw-r--r--sound/soc/codecs/nau8825.c135
-rw-r--r--sound/soc/codecs/nau8825.h23
-rw-r--r--sound/soc/codecs/rt1019.c20
-rw-r--r--sound/soc/codecs/rt1019.h6
-rw-r--r--sound/soc/codecs/rt1308-sdw.c56
-rw-r--r--sound/soc/codecs/rt1308-sdw.h5
-rw-r--r--sound/soc/codecs/rt1308.h5
-rw-r--r--sound/soc/codecs/rt1316-sdw.c39
-rw-r--r--sound/soc/codecs/rt1316-sdw.h2
-rw-r--r--sound/soc/codecs/rt1318-sdw.c884
-rw-r--r--sound/soc/codecs/rt1318-sdw.h101
-rw-r--r--sound/soc/codecs/rt298.c7
-rw-r--r--sound/soc/codecs/rt5682.c2
-rw-r--r--sound/soc/codecs/rt5682.h2
-rw-r--r--sound/soc/codecs/rt5682s.c37
-rw-r--r--sound/soc/codecs/rt5682s.h3
-rw-r--r--sound/soc/codecs/simple-mux.c9
-rw-r--r--sound/soc/codecs/tlv320adc3xxx.c2
-rw-r--r--sound/soc/codecs/tlv320aic3x.c120
-rw-r--r--sound/soc/codecs/tlv320aic3x.h43
-rw-r--r--sound/soc/codecs/twl4030.c6
-rw-r--r--sound/soc/codecs/wm5102.c7
-rw-r--r--sound/soc/codecs/wm5110.c7
-rw-r--r--sound/soc/codecs/wm8961.c7
-rw-r--r--sound/soc/codecs/wm8962.c54
-rw-r--r--sound/soc/codecs/wm8978.c2
-rw-r--r--sound/soc/codecs/wm8997.c7
-rw-r--r--sound/soc/codecs/wm_adsp.c11
-rw-r--r--sound/soc/codecs/wm_adsp.h1
-rw-r--r--sound/soc/codecs/wsa883x.c28
52 files changed, 1833 insertions, 199 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index e3b90c425faf..6b3726a1ff45 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -199,6 +199,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RT715_SDCA_SDW
imply SND_SOC_RT1308_SDW
imply SND_SOC_RT1316_SDW
+ imply SND_SOC_RT1318_SDW
imply SND_SOC_RT9120
imply SND_SOC_SDW_MOCKUP
imply SND_SOC_SGTL5000
@@ -1311,6 +1312,11 @@ config SND_SOC_RT1316_SDW
depends on SOUNDWIRE
select REGMAP_SOUNDWIRE
+config SND_SOC_RT1318_SDW
+ tristate "Realtek RT1318 Codec - SDW"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+
config SND_SOC_RT5514
tristate
depends on I2C
@@ -1629,6 +1635,7 @@ config SND_SOC_TFA989X
config SND_SOC_TLV320ADC3XXX
tristate "Texas Instruments TLV320ADC3001/3101 audio ADC"
depends on I2C
+ depends on GPIOLIB
help
Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101
ADCs.
@@ -1929,7 +1936,7 @@ config SND_SOC_WM8960
depends on I2C
config SND_SOC_WM8961
- tristate
+ tristate "Wolfson Microelectronics WM8961 CODEC"
depends on I2C
config SND_SOC_WM8962
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 9170ee1447dd..71d3ce5867e4 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -196,6 +196,7 @@ snd-soc-rt1305-objs := rt1305.o
snd-soc-rt1308-objs := rt1308.o
snd-soc-rt1308-sdw-objs := rt1308-sdw.o
snd-soc-rt1316-sdw-objs := rt1316-sdw.o
+snd-soc-rt1318-sdw-objs := rt1318-sdw.o
snd-soc-rt274-objs := rt274.o
snd-soc-rt286-objs := rt286.o
snd-soc-rt298-objs := rt298.o
@@ -551,6 +552,7 @@ obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o
obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o
obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o
obj-$(CONFIG_SND_SOC_RT1316_SDW) += snd-soc-rt1316-sdw.o
+obj-$(CONFIG_SND_SOC_RT1318_SDW) += snd-soc-rt1318-sdw.o
obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c
index a9f89e8565ec..fbb6bf6fb3cc 100644
--- a/sound/soc/codecs/adau1372.c
+++ b/sound/soc/codecs/adau1372.c
@@ -8,7 +8,6 @@
#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/gcd.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 7f832d00ab17..37e178e8a1d0 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -12,7 +12,6 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/slab.h>
-#include <linux/gcd.h>
#include <sound/core.h>
#include <sound/pcm.h>
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index c0f44ecef606..634d4dbca5ec 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -16,7 +16,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
-#include <linux/gcd.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index 1db73552c746..8c69c8cf9b67 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -13,6 +13,7 @@
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
#include <linux/slab.h>
#include <sound/initval.h>
#include <sound/pcm_params.h>
@@ -46,6 +47,7 @@ struct ak4458_priv {
struct device *dev;
struct regmap *regmap;
struct gpio_desc *reset_gpiod;
+ struct reset_control *reset;
struct gpio_desc *mute_gpiod;
int digfil; /* SSLOW, SD, SLOW bits */
int fs; /* sampling rate */
@@ -633,6 +635,12 @@ static void ak4458_reset(struct ak4458_priv *ak4458, bool active)
if (ak4458->reset_gpiod) {
gpiod_set_value_cansleep(ak4458->reset_gpiod, active);
usleep_range(1000, 2000);
+ } else if (!IS_ERR_OR_NULL(ak4458->reset)) {
+ if (active)
+ reset_control_assert(ak4458->reset);
+ else
+ reset_control_deassert(ak4458->reset);
+ usleep_range(1000, 2000);
}
}
@@ -668,7 +676,6 @@ static int __maybe_unused ak4458_runtime_resume(struct device *dev)
if (ak4458->mute_gpiod)
gpiod_set_value_cansleep(ak4458->mute_gpiod, 1);
- ak4458_reset(ak4458, true);
ak4458_reset(ak4458, false);
regcache_cache_only(ak4458->regmap, false);
@@ -748,6 +755,10 @@ static int ak4458_i2c_probe(struct i2c_client *i2c)
ak4458->drvdata = of_device_get_match_data(&i2c->dev);
+ ak4458->reset = devm_reset_control_get_optional_shared(ak4458->dev, NULL);
+ if (IS_ERR(ak4458->reset))
+ return PTR_ERR(ak4458->reset);
+
ak4458->reset_gpiod = devm_gpiod_get_optional(ak4458->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(ak4458->reset_gpiod))
diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c
index 31ae752e242f..a078dd422ea1 100644
--- a/sound/soc/codecs/cs35l36.c
+++ b/sound/soc/codecs/cs35l36.c
@@ -918,8 +918,8 @@ static int cs35l36_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
fs1 = CS35L36_FS1_DEFAULT_VAL;
fs2 = CS35L36_FS2_DEFAULT_VAL;
} else {
- fs1 = 3 * ((CS35L36_FS_NOM_6MHZ * 4 + freq - 1) / freq) + 4;
- fs2 = 5 * ((CS35L36_FS_NOM_6MHZ * 4 + freq - 1) / freq) + 4;
+ fs1 = 3 * DIV_ROUND_UP(CS35L36_FS_NOM_6MHZ * 4, freq) + 4;
+ fs2 = 5 * DIV_ROUND_UP(CS35L36_FS_NOM_6MHZ * 4, freq) + 4;
}
regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL,
diff --git a/sound/soc/codecs/cs42l83-i2c.c b/sound/soc/codecs/cs42l83-i2c.c
index f90d43996a51..37629ebd90e0 100644
--- a/sound/soc/codecs/cs42l83-i2c.c
+++ b/sound/soc/codecs/cs42l83-i2c.c
@@ -145,7 +145,7 @@ static const struct reg_default cs42l83_reg_defaults[] = {
* This is all the same as for CS42L42 but we
* replace the on-reset register defaults.
*/
-const struct regmap_config cs42l83_regmap = {
+static const struct regmap_config cs42l83_regmap = {
.reg_bits = 8,
.val_bits = 8,
diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c
index bd80e9fc907f..052ffb7dcfc6 100644
--- a/sound/soc/codecs/cs42xx8-i2c.c
+++ b/sound/soc/codecs/cs42xx8-i2c.c
@@ -12,15 +12,30 @@
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h>
#include "cs42xx8.h"
+static const struct of_device_id cs42xx8_of_match[];
+
static int cs42xx8_i2c_probe(struct i2c_client *i2c)
{
- int ret = cs42xx8_probe(&i2c->dev,
- devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config));
+ int ret;
+ struct cs42xx8_driver_data *drvdata;
+ const struct of_device_id *of_id;
+
+ of_id = of_match_device(cs42xx8_of_match, &i2c->dev);
+ if (!of_id) {
+ dev_err(&i2c->dev, "failed to find driver data\n");
+ return -EINVAL;
+ }
+
+ drvdata = (struct cs42xx8_driver_data *)of_id->data;
+
+ ret = cs42xx8_probe(&i2c->dev,
+ devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config), drvdata);
if (ret)
return ret;
@@ -35,7 +50,14 @@ static void cs42xx8_i2c_remove(struct i2c_client *i2c)
pm_runtime_disable(&i2c->dev);
}
-static struct i2c_device_id cs42xx8_i2c_id[] = {
+static const struct of_device_id cs42xx8_of_match[] = {
+ { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
+ { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
+
+static const struct i2c_device_id cs42xx8_i2c_id[] = {
{"cs42448", (kernel_ulong_t)&cs42448_data},
{"cs42888", (kernel_ulong_t)&cs42888_data},
{}
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
index d14eb2f6e1dd..4558ec38a7ac 100644
--- a/sound/soc/codecs/cs42xx8.c
+++ b/sound/soc/codecs/cs42xx8.c
@@ -13,7 +13,6 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -511,17 +510,8 @@ const struct cs42xx8_driver_data cs42888_data = {
};
EXPORT_SYMBOL_GPL(cs42888_data);
-const struct of_device_id cs42xx8_of_match[] = {
- { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
- { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
-EXPORT_SYMBOL_GPL(cs42xx8_of_match);
-
-int cs42xx8_probe(struct device *dev, struct regmap *regmap)
+int cs42xx8_probe(struct device *dev, struct regmap *regmap, struct cs42xx8_driver_data *drvdata)
{
- const struct of_device_id *of_id;
struct cs42xx8_priv *cs42xx8;
int ret, val, i;
@@ -535,17 +525,11 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap)
if (cs42xx8 == NULL)
return -ENOMEM;
- cs42xx8->regmap = regmap;
dev_set_drvdata(dev, cs42xx8);
- of_id = of_match_device(cs42xx8_of_match, dev);
- if (of_id)
- cs42xx8->drvdata = of_id->data;
+ cs42xx8->regmap = regmap;
- if (!cs42xx8->drvdata) {
- dev_err(dev, "failed to find driver data\n");
- return -EINVAL;
- }
+ cs42xx8->drvdata = drvdata;
cs42xx8->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h
index d36c61b6df74..342389e8b1a8 100644
--- a/sound/soc/codecs/cs42xx8.h
+++ b/sound/soc/codecs/cs42xx8.h
@@ -22,8 +22,7 @@ extern const struct dev_pm_ops cs42xx8_pm;
extern const struct cs42xx8_driver_data cs42448_data;
extern const struct cs42xx8_driver_data cs42888_data;
extern const struct regmap_config cs42xx8_regmap_config;
-extern const struct of_device_id cs42xx8_of_match[];
-int cs42xx8_probe(struct device *dev, struct regmap *regmap);
+int cs42xx8_probe(struct device *dev, struct regmap *regmap, struct cs42xx8_driver_data *drvdata);
/* CS42888 register map */
#define CS42XX8_CHIPID 0x01 /* Chip ID */
diff --git a/sound/soc/codecs/cx2072x.h b/sound/soc/codecs/cx2072x.h
index ebdd567fa225..09e3a92b184f 100644
--- a/sound/soc/codecs/cx2072x.h
+++ b/sound/soc/codecs/cx2072x.h
@@ -177,7 +177,7 @@
#define CX2072X_PLBK_DRC_PARM_LEN 9
#define CX2072X_CLASSD_AMP_LEN 6
-/* DAI interfae type */
+/* DAI interface type */
#define CX2072X_DAI_HIFI 1
#define CX2072X_DAI_DSP 2
#define CX2072X_DAI_DSP_PWM 3 /* 4 ch, including mic and AEC */
diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c
index bba73c44c219..9bf8d73b4f58 100644
--- a/sound/soc/codecs/da7219-aad.c
+++ b/sound/soc/codecs/da7219-aad.c
@@ -43,7 +43,6 @@ void da7219_aad_jack_det(struct snd_soc_component *component, struct snd_soc_jac
DA7219_ACCDET_EN_MASK,
(jack ? DA7219_ACCDET_EN_MASK : 0));
}
-EXPORT_SYMBOL_GPL(da7219_aad_jack_det);
/*
* Button/HPTest work
@@ -930,7 +929,6 @@ int da7219_aad_init(struct snd_soc_component *component)
return 0;
}
-EXPORT_SYMBOL_GPL(da7219_aad_init);
void da7219_aad_exit(struct snd_soc_component *component)
{
@@ -948,7 +946,6 @@ void da7219_aad_exit(struct snd_soc_component *component)
cancel_work_sync(&da7219_aad->btn_det_work);
cancel_work_sync(&da7219_aad->hptest_work);
}
-EXPORT_SYMBOL_GPL(da7219_aad_exit);
/*
* AAD related I2C probe handling
@@ -972,7 +969,6 @@ int da7219_aad_probe(struct i2c_client *i2c)
return 0;
}
-EXPORT_SYMBOL_GPL(da7219_aad_probe);
MODULE_DESCRIPTION("ASoC DA7219 AAD Driver");
MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 4746c8700451..7468ee4af2ea 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -2633,11 +2633,20 @@ static int da7219_resume(struct snd_soc_component *component)
#define da7219_resume NULL
#endif
+static int da7219_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack,
+ void *data)
+{
+ da7219_aad_jack_det(component, jack);
+
+ return 0;
+}
+
static const struct snd_soc_component_driver soc_component_dev_da7219 = {
.probe = da7219_probe,
.remove = da7219_remove,
.suspend = da7219_suspend,
.resume = da7219_resume,
+ .set_jack = da7219_set_jack,
.set_bias_level = da7219_set_bias_level,
.controls = da7219_snd_controls,
.num_controls = ARRAY_SIZE(da7219_snd_controls),
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
index 61e8e9be6b8d..4b8ec6f77337 100644
--- a/sound/soc/codecs/hda.c
+++ b/sound/soc/codecs/hda.c
@@ -130,10 +130,8 @@ static void hda_codec_unregister_dais(struct hda_codec *codec,
if (strcmp(dai->driver->name, pcm->name))
continue;
- if (dai->playback_widget)
- snd_soc_dapm_free_widget(dai->playback_widget);
- if (dai->capture_widget)
- snd_soc_dapm_free_widget(dai->capture_widget);
+ snd_soc_dapm_free_widget(dai->playback_widget);
+ snd_soc_dapm_free_widget(dai->capture_widget);
snd_soc_unregister_dai(dai);
break;
}
@@ -181,7 +179,7 @@ static int hda_codec_probe(struct snd_soc_component *component)
!pm_runtime_status_suspended(&hdev->dev));
#endif
- hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
+ hlink = snd_hdac_ext_bus_get_hlink_by_addr(bus, hdev->addr);
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
@@ -213,7 +211,7 @@ static int hda_codec_probe(struct snd_soc_component *component)
patch = (hda_codec_patch_t)codec->preset->driver_data;
if (!patch) {
- dev_err(&hdev->dev, "no patch specified?\n");
+ dev_err(&hdev->dev, "no patch specified\n");
ret = -EINVAL;
goto err;
}
@@ -289,7 +287,7 @@ static void hda_codec_remove(struct snd_soc_component *component)
if (hda_codec_is_display(codec))
snd_hdac_display_power(bus, hdev->addr, false);
- hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
+ hlink = snd_hdac_ext_bus_get_hlink_by_addr(bus, hdev->addr);
if (hlink)
snd_hdac_ext_bus_link_put(bus, hlink);
/*
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 8af434e14bfb..be66853afbe2 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -400,7 +400,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
hda_codec_patch_t patch;
int ret;
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
@@ -516,7 +516,7 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
struct hda_codec *codec = hda_pvt->codec;
struct hdac_ext_link *hlink = NULL;
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return;
@@ -584,7 +584,7 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev)
int ret;
/* hold the ref while we probe */
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index cb23650ad522..ed4f7cdda04f 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -1967,7 +1967,7 @@ static int hdmi_codec_probe(struct snd_soc_component *component)
* hold the ref while we probe, also no need to drop the ref on
* exit, we call pm_runtime_suspend() so that will do for us
*/
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
@@ -2144,7 +2144,7 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
const struct hda_device_id *hdac_id = hdac_get_device_id(hdev, hdrv);
/* hold the ref while we probe */
- hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
@@ -2244,7 +2244,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE,
AC_PWRST_D3);
- hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, dev_name(dev));
if (!hlink) {
dev_err(dev, "hdac link not found\n");
return -EIO;
@@ -2270,7 +2270,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
if (!bus)
return 0;
- hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev));
+ hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, dev_name(dev));
if (!hlink) {
dev_err(dev, "hdac link not found\n");
return -EIO;
diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c
index 5201a8f6d7b6..39cebaa167be 100644
--- a/sound/soc/codecs/jz4725b.c
+++ b/sound/soc/codecs/jz4725b.c
@@ -136,28 +136,89 @@ enum {
#define REG_CGR3_GO1L_OFFSET 0
#define REG_CGR3_GO1L_MASK (0x1f << REG_CGR3_GO1L_OFFSET)
+#define REG_CGR4_GO2R_OFFSET 0
+#define REG_CGR4_GO2R_MASK (0x1f << REG_CGR4_GO2R_OFFSET)
+
+#define REG_CGR5_GO2L_OFFSET 0
+#define REG_CGR5_GO2L_MASK (0x1f << REG_CGR5_GO2L_OFFSET)
+
+#define REG_CGR6_GO3R_OFFSET 0
+#define REG_CGR6_GO3R_MASK (0x1f << REG_CGR6_GO3R_OFFSET)
+
+#define REG_CGR7_GO3L_OFFSET 0
+#define REG_CGR7_GO3L_MASK (0x1f << REG_CGR7_GO3L_OFFSET)
+
+#define REG_CGR8_GOR_OFFSET 0
+#define REG_CGR8_GOR_MASK (0x1f << REG_CGR8_GOR_OFFSET)
+
+#define REG_CGR9_GOL_OFFSET 0
+#define REG_CGR9_GOL_MASK (0x1f << REG_CGR9_GOL_OFFSET)
+
+#define REG_CGR10_GIL_OFFSET 0
+#define REG_CGR10_GIR_OFFSET 4
+
struct jz_icdc {
struct regmap *regmap;
void __iomem *base;
struct clk *clk;
};
-static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_dac_tlv, -2250, 0);
-static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_line_tlv, -1500, 600);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_adc_tlv, 0, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_dac_tlv, -2250, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(jz4725b_mix_tlv,
+ 0, 11, TLV_DB_SCALE_ITEM(-2250, 0, 0),
+ 12, 31, TLV_DB_SCALE_ITEM(-2250, 150, 0),
+);
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(jz4725b_out_tlv,
+ 0, 11, TLV_DB_SCALE_ITEM(-3350, 200, 0),
+ 12, 23, TLV_DB_SCALE_ITEM(-1050, 100, 0),
+ 24, 31, TLV_DB_SCALE_ITEM( 100, 50, 0),
+);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_mic_boost_tlv, 0, 2000, 0);
+
+static const char * const jz4725b_mic_mode_texts[] = {
+ "Single Ended", "Differential",
+};
+
+static const struct soc_enum jz4725b_mic_mode_enum =
+ SOC_ENUM_SINGLE(JZ4725B_CODEC_REG_CR3, REG_CR3_MICDIFF_OFFSET,
+ 2, jz4725b_mic_mode_texts);
static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
- SOC_DOUBLE_TLV("Master Playback Volume",
+ SOC_DOUBLE_TLV("DAC Playback Volume",
JZ4725B_CODEC_REG_CGR1,
REG_CGR1_GODL_OFFSET,
REG_CGR1_GODR_OFFSET,
0xf, 1, jz4725b_dac_tlv),
- SOC_DOUBLE_R_TLV("Master Capture Volume",
+ SOC_DOUBLE_TLV("Master Capture Volume",
+ JZ4725B_CODEC_REG_CGR10,
+ REG_CGR10_GIL_OFFSET,
+ REG_CGR10_GIR_OFFSET,
+ 0xf, 0, jz4725b_adc_tlv),
+ SOC_DOUBLE_R_TLV("Mixer Line In Bypass Playback Volume",
JZ4725B_CODEC_REG_CGR3,
JZ4725B_CODEC_REG_CGR2,
REG_CGR2_GO1R_OFFSET,
- 0x1f, 1, jz4725b_line_tlv),
-
- SOC_SINGLE("Master Playback Switch", JZ4725B_CODEC_REG_CR1,
+ 0x1f, 1, jz4725b_mix_tlv),
+ SOC_DOUBLE_R_TLV("Mixer Mic 1 Bypass Playback Volume",
+ JZ4725B_CODEC_REG_CGR5,
+ JZ4725B_CODEC_REG_CGR4,
+ REG_CGR4_GO2R_OFFSET,
+ 0x1f, 1, jz4725b_mix_tlv),
+ SOC_DOUBLE_R_TLV("Mixer Mic 2 Bypass Playback Volume",
+ JZ4725B_CODEC_REG_CGR7,
+ JZ4725B_CODEC_REG_CGR6,
+ REG_CGR6_GO3R_OFFSET,
+ 0x1f, 1, jz4725b_mix_tlv),
+
+ SOC_DOUBLE_R_TLV("Master Playback Volume",
+ JZ4725B_CODEC_REG_CGR9,
+ JZ4725B_CODEC_REG_CGR8,
+ REG_CGR8_GOR_OFFSET,
+ 0x1f, 1, jz4725b_out_tlv),
+
+ SOC_SINGLE("DAC Playback Switch", JZ4725B_CODEC_REG_CR1,
REG_CR1_DAC_MUTE_OFFSET, 1, 1),
SOC_SINGLE("Deemphasize Filter Playback Switch",
@@ -167,6 +228,13 @@ static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
SOC_SINGLE("High-Pass Filter Capture Switch",
JZ4725B_CODEC_REG_CR2,
REG_CR2_ADC_HPF_OFFSET, 1, 0),
+
+ SOC_ENUM("Mic Mode Capture Switch", jz4725b_mic_mode_enum),
+
+ SOC_SINGLE_TLV("Mic1 Boost Capture Volume",
+ JZ4725B_CODEC_REG_PMR2,
+ REG_PMR2_GIM_OFFSET,
+ 1, 0, jz4725b_mic_boost_tlv),
};
static const char * const jz4725b_codec_adc_src_texts[] = {
@@ -180,11 +248,15 @@ static SOC_VALUE_ENUM_SINGLE_DECL(jz4725b_codec_adc_src_enum,
jz4725b_codec_adc_src_texts,
jz4725b_codec_adc_src_values);
static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl =
- SOC_DAPM_ENUM("Route", jz4725b_codec_adc_src_enum);
+ SOC_DAPM_ENUM("ADC Source Capture Route", jz4725b_codec_adc_src_enum);
static const struct snd_kcontrol_new jz4725b_codec_mixer_controls[] = {
- SOC_DAPM_SINGLE("Line In Bypass", JZ4725B_CODEC_REG_CR1,
+ SOC_DAPM_SINGLE("Line In Bypass Playback Switch", JZ4725B_CODEC_REG_CR1,
REG_CR1_BYPASS_OFFSET, 1, 0),
+ SOC_DAPM_SINGLE("Mic 1 Bypass Playback Switch", JZ4725B_CODEC_REG_CR3,
+ REG_CR3_SIDETONE1_OFFSET, 1, 0),
+ SOC_DAPM_SINGLE("Mic 2 Bypass Playback Switch", JZ4725B_CODEC_REG_CR3,
+ REG_CR3_SIDETONE2_OFFSET, 1, 0),
};
static int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w,
@@ -225,7 +297,7 @@ static const struct snd_soc_dapm_widget jz4725b_codec_dapm_widgets[] = {
SND_SOC_DAPM_ADC("ADC", "Capture",
JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_ADC_OFFSET, 1),
- SND_SOC_DAPM_MUX("ADC Source", SND_SOC_NOPM, 0, 0,
+ SND_SOC_DAPM_MUX("ADC Source Capture Route", SND_SOC_NOPM, 0, 0,
&jz4725b_codec_adc_src_ctrl),
/* Mixer */
@@ -236,7 +308,8 @@ static const struct snd_soc_dapm_widget jz4725b_codec_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("DAC to Mixer", JZ4725B_CODEC_REG_CR1,
REG_CR1_DACSEL_OFFSET, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("Line In", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Line In", JZ4725B_CODEC_REG_PMR1,
+ REG_PMR1_SB_LIN_OFFSET, 1, NULL, 0),
SND_SOC_DAPM_MIXER("HP Out", JZ4725B_CODEC_REG_CR1,
REG_CR1_HP_DIS_OFFSET, 1, NULL, 0),
@@ -278,16 +351,18 @@ static const struct snd_soc_dapm_route jz4725b_codec_dapm_routes[] = {
{"Line In", NULL, "LLINEIN"},
{"Line In", NULL, "RLINEIN"},
- {"Mixer", "Line In Bypass", "Line In"},
+ {"Mixer", "Mic 1 Bypass Playback Switch", "Mic 1"},
+ {"Mixer", "Mic 2 Bypass Playback Switch", "Mic 2"},
+ {"Mixer", "Line In Bypass Playback Switch", "Line In"},
{"DAC to Mixer", NULL, "DAC"},
{"Mixer", NULL, "DAC to Mixer"},
{"Mixer to ADC", NULL, "Mixer"},
- {"ADC Source", "Mixer", "Mixer to ADC"},
- {"ADC Source", "Line In", "Line In"},
- {"ADC Source", "Mic 1", "Mic 1"},
- {"ADC Source", "Mic 2", "Mic 2"},
- {"ADC", NULL, "ADC Source"},
+ {"ADC Source Capture Route", "Mixer", "Mixer to ADC"},
+ {"ADC Source Capture Route", "Line In", "Line In"},
+ {"ADC Source Capture Route", "Mic 1", "Mic 1"},
+ {"ADC Source Capture Route", "Mic 2", "Mic 2"},
+ {"ADC", NULL, "ADC Source Capture Route"},
{"Out Stage", NULL, "Mixer"},
{"HP Out", NULL, "Out Stage"},
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
index ee15cf6b98bb..2ef62d6edc30 100644
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -46,6 +46,7 @@
#define CDC_TX_TOP_CSR_SWR_AMIC1_CTL (0x00D4)
#define CDC_TX_INP_MUX_ADC_MUXn_CFG0(n) (0x0100 + 0x8 * n)
#define CDC_TX_MACRO_SWR_MIC_MUX_SEL_MASK GENMASK(3, 0)
+#define CDC_TX_MACRO_DMIC_MUX_SEL_MASK GENMASK(7, 4)
#define CDC_TX_INP_MUX_ADC_MUX0_CFG0 (0x0100)
#define CDC_TX_INP_MUX_ADC_MUXn_CFG1(n) (0x0104 + 0x8 * n)
#define CDC_TX_INP_MUX_ADC_MUX0_CFG1 (0x0104)
@@ -774,7 +775,10 @@ static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
}
if (val != 0) {
- if (val < 5) {
+ if (widget->shift) { /* MSM DMIC */
+ snd_soc_component_write_field(component, mic_sel_reg,
+ CDC_TXn_ADC_DMIC_SEL_MASK, 1);
+ } else if (val < 5) {
snd_soc_component_write_field(component, mic_sel_reg,
CDC_TXn_ADC_DMIC_SEL_MASK, 0);
} else {
@@ -1272,6 +1276,52 @@ static const struct snd_kcontrol_new tx_smic6_mux = SOC_DAPM_ENUM_EXT("tx_smic6"
static const struct snd_kcontrol_new tx_smic7_mux = SOC_DAPM_ENUM_EXT("tx_smic7", tx_smic7_enum,
snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const char * const dmic_mux_text[] = {
+ "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3",
+ "DMIC4", "DMIC5", "DMIC6", "DMIC7"
+};
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic0_enum, CDC_TX_INP_MUX_ADC_MUX0_CFG0,
+ 4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic1_enum, CDC_TX_INP_MUX_ADC_MUX1_CFG0,
+ 4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic2_enum, CDC_TX_INP_MUX_ADC_MUX2_CFG0,
+ 4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic3_enum, CDC_TX_INP_MUX_ADC_MUX3_CFG0,
+ 4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic4_enum, CDC_TX_INP_MUX_ADC_MUX4_CFG0,
+ 4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic5_enum, CDC_TX_INP_MUX_ADC_MUX5_CFG0,
+ 4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic6_enum, CDC_TX_INP_MUX_ADC_MUX6_CFG0,
+ 4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic7_enum, CDC_TX_INP_MUX_ADC_MUX7_CFG0,
+ 4, dmic_mux_text);
+
+static const struct snd_kcontrol_new tx_dmic0_mux = SOC_DAPM_ENUM_EXT("tx_dmic0", tx_dmic0_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic1_mux = SOC_DAPM_ENUM_EXT("tx_dmic1", tx_dmic1_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic2_mux = SOC_DAPM_ENUM_EXT("tx_dmic2", tx_dmic2_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic3_mux = SOC_DAPM_ENUM_EXT("tx_dmic3", tx_dmic3_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic4_mux = SOC_DAPM_ENUM_EXT("tx_dmic4", tx_dmic4_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic5_mux = SOC_DAPM_ENUM_EXT("tx_dmic5", tx_dmic5_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic6_mux = SOC_DAPM_ENUM_EXT("tx_dmic6", tx_dmic6_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic7_mux = SOC_DAPM_ENUM_EXT("tx_dmic7", tx_dmic7_enum,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+
static const char * const dec_mode_mux_text[] = {
"ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF",
};
@@ -1380,6 +1430,15 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = {
SND_SOC_DAPM_MUX("TX SMIC MUX6", SND_SOC_NOPM, 0, 0, &tx_smic6_mux),
SND_SOC_DAPM_MUX("TX SMIC MUX7", SND_SOC_NOPM, 0, 0, &tx_smic7_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX0", SND_SOC_NOPM, 4, 0, &tx_dmic0_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX1", SND_SOC_NOPM, 4, 0, &tx_dmic1_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX2", SND_SOC_NOPM, 4, 0, &tx_dmic2_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX3", SND_SOC_NOPM, 4, 0, &tx_dmic3_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX4", SND_SOC_NOPM, 4, 0, &tx_dmic4_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX5", SND_SOC_NOPM, 4, 0, &tx_dmic5_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX6", SND_SOC_NOPM, 4, 0, &tx_dmic6_mux),
+ SND_SOC_DAPM_MUX("TX DMIC MUX7", SND_SOC_NOPM, 4, 0, &tx_dmic7_mux),
+
SND_SOC_DAPM_INPUT("TX SWR_ADC0"),
SND_SOC_DAPM_INPUT("TX SWR_ADC1"),
SND_SOC_DAPM_INPUT("TX SWR_ADC2"),
@@ -1392,6 +1451,14 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("TX SWR_DMIC5"),
SND_SOC_DAPM_INPUT("TX SWR_DMIC6"),
SND_SOC_DAPM_INPUT("TX SWR_DMIC7"),
+ SND_SOC_DAPM_INPUT("TX DMIC0"),
+ SND_SOC_DAPM_INPUT("TX DMIC1"),
+ SND_SOC_DAPM_INPUT("TX DMIC2"),
+ SND_SOC_DAPM_INPUT("TX DMIC3"),
+ SND_SOC_DAPM_INPUT("TX DMIC4"),
+ SND_SOC_DAPM_INPUT("TX DMIC5"),
+ SND_SOC_DAPM_INPUT("TX DMIC6"),
+ SND_SOC_DAPM_INPUT("TX DMIC7"),
SND_SOC_DAPM_MUX_E("TX DEC0 MUX", SND_SOC_NOPM,
TX_MACRO_DEC0, 0,
@@ -1495,6 +1562,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX DEC6 MUX", NULL, "TX_MCLK"},
{"TX DEC7 MUX", NULL, "TX_MCLK"},
+ {"TX DEC0 MUX", "MSM_DMIC", "TX DMIC MUX0"},
+ {"TX DMIC MUX0", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX0", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX0", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX0", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX0", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX0", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX0", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX0", "DMIC7", "TX DMIC7"},
+
{"TX DEC0 MUX", "SWR_MIC", "TX SMIC MUX0"},
{"TX SMIC MUX0", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX0", "ADC0", "TX SWR_ADC0"},
@@ -1510,6 +1587,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX0", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX0", "SWR_DMIC7", "TX SWR_DMIC7"},
+ {"TX DEC1 MUX", "MSM_DMIC", "TX DMIC MUX1"},
+ {"TX DMIC MUX1", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX1", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX1", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX1", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX1", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX1", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX1", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX1", "DMIC7", "TX DMIC7"},
+
{"TX DEC1 MUX", "SWR_MIC", "TX SMIC MUX1"},
{"TX SMIC MUX1", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX1", "ADC0", "TX SWR_ADC0"},
@@ -1525,6 +1612,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX1", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX1", "SWR_DMIC7", "TX SWR_DMIC7"},
+ {"TX DEC2 MUX", "MSM_DMIC", "TX DMIC MUX2"},
+ {"TX DMIC MUX2", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX2", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX2", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX2", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX2", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX2", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX2", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX2", "DMIC7", "TX DMIC7"},
+
{"TX DEC2 MUX", "SWR_MIC", "TX SMIC MUX2"},
{"TX SMIC MUX2", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX2", "ADC0", "TX SWR_ADC0"},
@@ -1540,6 +1637,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX2", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX2", "SWR_DMIC7", "TX SWR_DMIC7"},
+ {"TX DEC3 MUX", "MSM_DMIC", "TX DMIC MUX3"},
+ {"TX DMIC MUX3", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX3", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX3", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX3", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX3", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX3", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX3", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX3", "DMIC7", "TX DMIC7"},
+
{"TX DEC3 MUX", "SWR_MIC", "TX SMIC MUX3"},
{"TX SMIC MUX3", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX3", "ADC0", "TX SWR_ADC0"},
@@ -1555,6 +1662,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX3", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX3", "SWR_DMIC7", "TX SWR_DMIC7"},
+ {"TX DEC4 MUX", "MSM_DMIC", "TX DMIC MUX4"},
+ {"TX DMIC MUX4", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX4", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX4", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX4", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX4", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX4", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX4", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX4", "DMIC7", "TX DMIC7"},
+
{"TX DEC4 MUX", "SWR_MIC", "TX SMIC MUX4"},
{"TX SMIC MUX4", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX4", "ADC0", "TX SWR_ADC0"},
@@ -1570,6 +1687,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX4", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX4", "SWR_DMIC7", "TX SWR_DMIC7"},
+ {"TX DEC5 MUX", "MSM_DMIC", "TX DMIC MUX5"},
+ {"TX DMIC MUX5", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX5", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX5", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX5", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX5", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX5", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX5", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX5", "DMIC7", "TX DMIC7"},
+
{"TX DEC5 MUX", "SWR_MIC", "TX SMIC MUX5"},
{"TX SMIC MUX5", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX5", "ADC0", "TX SWR_ADC0"},
@@ -1585,6 +1712,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX5", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX5", "SWR_DMIC7", "TX SWR_DMIC7"},
+ {"TX DEC6 MUX", "MSM_DMIC", "TX DMIC MUX6"},
+ {"TX DMIC MUX6", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX6", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX6", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX6", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX6", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX6", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX6", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX6", "DMIC7", "TX DMIC7"},
+
{"TX DEC6 MUX", "SWR_MIC", "TX SMIC MUX6"},
{"TX SMIC MUX6", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX6", "ADC0", "TX SWR_ADC0"},
@@ -1600,6 +1737,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX6", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX6", "SWR_DMIC7", "TX SWR_DMIC7"},
+ {"TX DEC7 MUX", "MSM_DMIC", "TX DMIC MUX7"},
+ {"TX DMIC MUX7", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX7", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX7", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX7", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX7", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX7", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX7", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX7", "DMIC7", "TX DMIC7"},
+
{"TX DEC7 MUX", "SWR_MIC", "TX SMIC MUX7"},
{"TX SMIC MUX7", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX7", "ADC0", "TX SWR_ADC0"},
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index 5e0abefe7cce..5cfe96f6e430 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -4,6 +4,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/of_clk.h>
@@ -2350,14 +2351,15 @@ static int wsa_macro_register_mclk_output(struct wsa_macro *wsa)
{
struct device *dev = wsa->dev;
const char *parent_clk_name;
- const char *clk_name = "mclk";
struct clk_hw *hw;
struct clk_init_data init;
int ret;
parent_clk_name = __clk_get_name(wsa->npl);
- init.name = clk_name;
+ init.name = "mclk";
+ of_property_read_string(dev_of_node(dev), "clock-output-names",
+ &init.name);
init.ops = &swclk_gate_ops;
init.flags = 0;
init.parent_names = &parent_clk_name;
diff --git a/sound/soc/codecs/mt6660.c b/sound/soc/codecs/mt6660.c
index 554c33e8b62f..cc2df5f7ea19 100644
--- a/sound/soc/codecs/mt6660.c
+++ b/sound/soc/codecs/mt6660.c
@@ -503,14 +503,14 @@ static int mt6660_i2c_probe(struct i2c_client *client)
dev_err(chip->dev, "read chip revision fail\n");
goto probe_fail;
}
+ pm_runtime_set_active(chip->dev);
+ pm_runtime_enable(chip->dev);
ret = devm_snd_soc_register_component(chip->dev,
&mt6660_component_driver,
&mt6660_codec_dai, 1);
- if (!ret) {
- pm_runtime_set_active(chip->dev);
- pm_runtime_enable(chip->dev);
- }
+ if (ret)
+ pm_runtime_disable(chip->dev);
return ret;
diff --git a/sound/soc/codecs/nau8315.c b/sound/soc/codecs/nau8315.c
index ad4dce9e5080..125742601f88 100644
--- a/sound/soc/codecs/nau8315.c
+++ b/sound/soc/codecs/nau8315.c
@@ -137,6 +137,7 @@ static int nau8315_platform_probe(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id nau8315_device_id[] = {
{ .compatible = "nuvoton,nau8315" },
+ { .compatible = "nuvoton,nau8318" },
{}
};
MODULE_DEVICE_TABLE(of, nau8315_device_id);
@@ -145,6 +146,7 @@ MODULE_DEVICE_TABLE(of, nau8315_device_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id nau8315_acpi_match[] = {
{ "NVTN2010", 0 },
+ { "NVTN2012", 0},
{},
};
MODULE_DEVICE_TABLE(acpi, nau8315_acpi_match);
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index 3eac7c92df88..4bffa9c20f2b 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -1686,6 +1686,9 @@ static void nau8825_setup_auto_irq(struct nau8825 *nau8825)
/* Enable internal VCO needed for interruptions */
nau8825_configure_sysclk(nau8825, NAU8825_CLK_INTERNAL, 0);
+ /* Raise up the internal clock for jack detection */
+ regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
+ NAU8825_CLK_MCLK_SRC_MASK, 0);
/* Enable ADC needed for interruptions */
regmap_update_bits(regmap, NAU8825_REG_ENA_CTRL,
@@ -1733,6 +1736,121 @@ static int nau8825_button_decode(int value)
return buttons;
}
+static int nau8825_high_imped_detection(struct nau8825 *nau8825)
+{
+ struct regmap *regmap = nau8825->regmap;
+ struct snd_soc_dapm_context *dapm = nau8825->dapm;
+ unsigned int adc_mg1, adc_mg2;
+
+ /* Initial phase */
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+ NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2);
+ regmap_update_bits(regmap, NAU8825_REG_ANALOG_CONTROL_1,
+ NAU8825_TESTDACIN_MASK, NAU8825_TESTDACIN_GND);
+ regmap_write(regmap, NAU8825_REG_TRIM_SETTINGS, 0x6);
+ regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+ NAU8825_MICBIAS_LOWNOISE_MASK | NAU8825_MICBIAS_VOLTAGE_MASK,
+ NAU8825_MICBIAS_LOWNOISE_EN);
+ regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+ NAU8825_SAR_INPUT_MASK | NAU8825_SAR_TRACKING_GAIN_MASK |
+ NAU8825_SAR_HV_SEL_MASK | NAU8825_SAR_RES_SEL_MASK |
+ NAU8825_SAR_COMPARE_TIME_MASK | NAU8825_SAR_SAMPLING_TIME_MASK,
+ NAU8825_SAR_HV_SEL_VDDMIC | NAU8825_SAR_RES_SEL_70K);
+
+ snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+ snd_soc_dapm_force_enable_pin(dapm, "SAR");
+ snd_soc_dapm_sync(dapm);
+
+ /* Configure settings for first reading of SARADC */
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+ NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND2);
+ regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+ NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+ NAU8825_MICBIAS_JKR2);
+ regmap_read(regmap, NAU8825_REG_SARDOUT_RAM_STATUS, &adc_mg1);
+
+ /* Configure settings for second reading of SARADC */
+ regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+ NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, 0);
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+ NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 |
+ NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L);
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+ NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1);
+ regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+ NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+ NAU8825_MICBIAS_JKSLV);
+ regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+ NAU8825_SAR_INPUT_MASK, NAU8825_SAR_INPUT_JKSLV);
+ regmap_read(regmap, NAU8825_REG_SARDOUT_RAM_STATUS, &adc_mg2);
+
+ /* Disable phase */
+ snd_soc_dapm_disable_pin(dapm, "SAR");
+ snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+ snd_soc_dapm_sync(dapm);
+
+ regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+ NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_LOWNOISE_MASK |
+ NAU8825_MICBIAS_VOLTAGE_MASK, nau8825->micbias_voltage);
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+ NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 |
+ NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L);
+ regmap_update_bits(regmap, NAU8825_REG_ANALOG_CONTROL_1,
+ NAU8825_TESTDACIN_MASK, NAU8825_TESTDACIN_GND);
+ regmap_write(regmap, NAU8825_REG_TRIM_SETTINGS, 0);
+ regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+ NAU8825_SAR_TRACKING_GAIN_MASK | NAU8825_SAR_HV_SEL_MASK,
+ nau8825->sar_voltage << NAU8825_SAR_TRACKING_GAIN_SFT);
+ regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+ NAU8825_SAR_COMPARE_TIME_MASK | NAU8825_SAR_SAMPLING_TIME_MASK,
+ (nau8825->sar_compare_time << NAU8825_SAR_COMPARE_TIME_SFT) |
+ (nau8825->sar_sampling_time << NAU8825_SAR_SAMPLING_TIME_SFT));
+ dev_dbg(nau8825->dev, "adc_mg1:%x, adc_mg2:%x\n", adc_mg1, adc_mg2);
+
+ /* Confirmation phase */
+ if (adc_mg1 > adc_mg2) {
+ dev_dbg(nau8825->dev, "OMTP (micgnd1) mic connected\n");
+
+ /* Unground MICGND1 */
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2,
+ NAU8825_SPKR_ENGND2);
+ /* Attach 2kOhm Resistor from MICBIAS to MICGND1 */
+ regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+ NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+ NAU8825_MICBIAS_JKR2);
+ /* Attach SARADC to MICGND1 */
+ regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+ NAU8825_SAR_INPUT_MASK,
+ NAU8825_SAR_INPUT_JKR2);
+ } else if (adc_mg1 < adc_mg2) {
+ dev_dbg(nau8825->dev, "CTIA (micgnd2) mic connected\n");
+
+ /* Unground MICGND2 */
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2,
+ NAU8825_SPKR_ENGND1);
+ /* Attach 2kOhm Resistor from MICBIAS to MICGND2 */
+ regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+ NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+ NAU8825_MICBIAS_JKSLV);
+ /* Attach SARADC to MICGND2 */
+ regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+ NAU8825_SAR_INPUT_MASK,
+ NAU8825_SAR_INPUT_JKSLV);
+ } else {
+ dev_err(nau8825->dev, "Jack broken.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int nau8825_jack_insert(struct nau8825 *nau8825)
{
struct regmap *regmap = nau8825->regmap;
@@ -1794,12 +1912,23 @@ static int nau8825_jack_insert(struct nau8825 *nau8825)
snd_soc_dapm_sync(dapm);
break;
case 3:
- /* detect error case */
- dev_err(nau8825->dev, "detection error; disable mic function\n");
- type = SND_JACK_HEADPHONE;
+ /* Detection failure case */
+ dev_warn(nau8825->dev,
+ "Detection failure. Try the manually mechanism for jack type checking.\n");
+ if (!nau8825_high_imped_detection(nau8825)) {
+ type = SND_JACK_HEADSET;
+ snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+ snd_soc_dapm_force_enable_pin(dapm, "SAR");
+ snd_soc_dapm_sync(dapm);
+ } else
+ type = SND_JACK_HEADPHONE;
break;
}
+ /* Update to the default divider of internal clock for power saving */
+ regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
+ NAU8825_CLK_MCLK_SRC_MASK, 0xf);
+
/* Leaving HPOL/R grounded after jack insert by default. They will be
* ungrounded as part of the widget power up sequence at the beginning
* of playback to reduce pop.
diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h
index d84191a7beb2..0c3a446e0e1a 100644
--- a/sound/soc/codecs/nau8825.h
+++ b/sound/soc/codecs/nau8825.h
@@ -155,6 +155,8 @@
/* HSD_CTRL (0xc) */
#define NAU8825_HSD_AUTO_MODE (1 << 6)
/* 0 - open, 1 - short to GND */
+#define NAU8825_SPKR_ENGND1 (1 << 3)
+#define NAU8825_SPKR_ENGND2 (1 << 2)
#define NAU8825_SPKR_DWN1R (1 << 1)
#define NAU8825_SPKR_DWN1L (1 << 0)
@@ -207,6 +209,17 @@
#define NAU8825_SAR_INPUT_JKR2 (0 << 11)
#define NAU8825_SAR_TRACKING_GAIN_SFT 8
#define NAU8825_SAR_TRACKING_GAIN_MASK (0x7 << NAU8825_SAR_TRACKING_GAIN_SFT)
+#define NAU8825_SAR_HV_SEL_SFT 7
+#define NAU8825_SAR_HV_SEL_MASK (1 << NAU8825_SAR_HV_SEL_SFT)
+#define NAU8825_SAR_HV_SEL_MICBIAS (0 << NAU8825_SAR_HV_SEL_SFT)
+#define NAU8825_SAR_HV_SEL_VDDMIC (1 << NAU8825_SAR_HV_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_SFT 4
+#define NAU8825_SAR_RES_SEL_MASK (0x7 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_35K (0 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_70K (1 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_170K (2 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_360K (3 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_SHORTED (4 << NAU8825_SAR_RES_SEL_SFT)
#define NAU8825_SAR_COMPARE_TIME_SFT 2
#define NAU8825_SAR_COMPARE_TIME_MASK (3 << 2)
#define NAU8825_SAR_SAMPLING_TIME_SFT 0
@@ -385,6 +398,13 @@
#define NAU8825_BIAS_VMID_SEL_SFT 4
#define NAU8825_BIAS_VMID_SEL_MASK (3 << NAU8825_BIAS_VMID_SEL_SFT)
+/* ANALOG_CONTROL_1 (0x69) */
+#define NAU8825_TESTDACIN_SFT 14
+#define NAU8825_TESTDACIN_MASK (0x3 << NAU8825_TESTDACIN_SFT)
+#define NAU8825_TESTDACIN_HIGH (1 << NAU8825_TESTDACIN_SFT)
+#define NAU8825_TESTDACIN_LOW (2 << NAU8825_TESTDACIN_SFT)
+#define NAU8825_TESTDACIN_GND (3 << NAU8825_TESTDACIN_SFT)
+
/* ANALOG_CONTROL_2 (0x6a) */
#define NAU8825_HP_NON_CLASSG_CURRENT_2xADJ (1 << 12)
#define NAU8825_DAC_CAPACITOR_MSB (1 << 1)
@@ -412,6 +432,9 @@
/* MIC_BIAS (0x74) */
#define NAU8825_MICBIAS_JKSLV (1 << 14)
#define NAU8825_MICBIAS_JKR2 (1 << 12)
+#define NAU8825_MICBIAS_LOWNOISE_SFT 10
+#define NAU8825_MICBIAS_LOWNOISE_MASK (0x1 << NAU8825_MICBIAS_LOWNOISE_SFT)
+#define NAU8825_MICBIAS_LOWNOISE_EN (0x1 << NAU8825_MICBIAS_LOWNOISE_SFT)
#define NAU8825_MICBIAS_POWERUP_SFT 8
#define NAU8825_MICBIAS_VOLTAGE_SFT 0
#define NAU8825_MICBIAS_VOLTAGE_MASK 0x7
diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c
index b66bfecbb879..49f527c61a7a 100644
--- a/sound/soc/codecs/rt1019.c
+++ b/sound/soc/codecs/rt1019.c
@@ -391,18 +391,18 @@ static int rt1019_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
unsigned int rx_mask, int slots, int slot_width)
{
struct snd_soc_component *component = dai->component;
- unsigned int val = 0, rx_slotnum;
+ unsigned int cn = 0, cl = 0, rx_slotnum;
int ret = 0, first_bit;
switch (slots) {
case 4:
- val |= RT1019_I2S_TX_4CH;
+ cn = RT1019_I2S_TX_4CH;
break;
case 6:
- val |= RT1019_I2S_TX_6CH;
+ cn = RT1019_I2S_TX_6CH;
break;
case 8:
- val |= RT1019_I2S_TX_8CH;
+ cn = RT1019_I2S_TX_8CH;
break;
case 2:
break;
@@ -412,16 +412,16 @@ static int rt1019_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
switch (slot_width) {
case 20:
- val |= RT1019_I2S_DL_20;
+ cl = RT1019_TDM_CL_20;
break;
case 24:
- val |= RT1019_I2S_DL_24;
+ cl = RT1019_TDM_CL_24;
break;
case 32:
- val |= RT1019_I2S_DL_32;
+ cl = RT1019_TDM_CL_32;
break;
case 8:
- val |= RT1019_I2S_DL_8;
+ cl = RT1019_TDM_CL_8;
break;
case 16:
break;
@@ -470,8 +470,10 @@ static int rt1019_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
goto _set_tdm_err_;
}
+ snd_soc_component_update_bits(component, RT1019_TDM_1,
+ RT1019_TDM_CL_MASK, cl);
snd_soc_component_update_bits(component, RT1019_TDM_2,
- RT1019_I2S_CH_TX_MASK | RT1019_I2S_DF_MASK, val);
+ RT1019_I2S_CH_TX_MASK, cn);
_set_tdm_err_:
return ret;
diff --git a/sound/soc/codecs/rt1019.h b/sound/soc/codecs/rt1019.h
index 64df831eeb72..48ba15efb48d 100644
--- a/sound/soc/codecs/rt1019.h
+++ b/sound/soc/codecs/rt1019.h
@@ -95,6 +95,12 @@
#define RT1019_TDM_BCLK_MASK (0x1 << 6)
#define RT1019_TDM_BCLK_NORM (0x0 << 6)
#define RT1019_TDM_BCLK_INV (0x1 << 6)
+#define RT1019_TDM_CL_MASK (0x7)
+#define RT1019_TDM_CL_8 (0x4)
+#define RT1019_TDM_CL_32 (0x3)
+#define RT1019_TDM_CL_24 (0x2)
+#define RT1019_TDM_CL_20 (0x1)
+#define RT1019_TDM_CL_16 (0x0)
/* 0x0401 TDM Control-2 */
#define RT1019_I2S_CH_TX_MASK (0x3 << 6)
diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c
index 5c29416aa781..7f4248284f35 100644
--- a/sound/soc/codecs/rt1308-sdw.c
+++ b/sound/soc/codecs/rt1308-sdw.c
@@ -50,6 +50,7 @@ static bool rt1308_volatile_register(struct device *dev, unsigned int reg)
case 0x3008:
case 0x300a:
case 0xc000:
+ case 0xc710:
case 0xc860 ... 0xc863:
case 0xc870 ... 0xc873:
return true;
@@ -196,10 +197,22 @@ static void rt1308_apply_calib_params(struct rt1308_sdw_priv *rt1308)
efuse_c_btl_l, efuse_c_btl_r);
}
+static void rt1308_apply_bq_params(struct rt1308_sdw_priv *rt1308)
+{
+ unsigned int i, reg, data;
+
+ for (i = 0; i < rt1308->bq_params_cnt; i += 3) {
+ reg = rt1308->bq_params[i] | (rt1308->bq_params[i + 1] << 8);
+ data = rt1308->bq_params[i + 2];
+ regmap_write(rt1308->regmap, reg, data);
+ }
+}
+
static int rt1308_io_init(struct device *dev, struct sdw_slave *slave)
{
struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev);
int ret = 0;
+ unsigned int tmp;
if (rt1308->hw_init)
return 0;
@@ -231,6 +244,10 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave)
/* sw reset */
regmap_write(rt1308->regmap, RT1308_SDW_RESET, 0);
+ regmap_read(rt1308->regmap, 0xc710, &tmp);
+ rt1308->hw_ver = tmp;
+ dev_dbg(dev, "%s, hw_ver=0x%x\n", __func__, rt1308->hw_ver);
+
/* initial settings */
regmap_write(rt1308->regmap, 0xc103, 0xc0);
regmap_write(rt1308->regmap, 0xc030, 0x17);
@@ -246,8 +263,14 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave)
regmap_write(rt1308->regmap, 0xc062, 0x05);
regmap_write(rt1308->regmap, 0xc171, 0x07);
regmap_write(rt1308->regmap, 0xc173, 0x0d);
- regmap_write(rt1308->regmap, 0xc311, 0x7f);
- regmap_write(rt1308->regmap, 0xc900, 0x90);
+ if (rt1308->hw_ver == RT1308_VER_C) {
+ regmap_write(rt1308->regmap, 0xc311, 0x7f);
+ regmap_write(rt1308->regmap, 0xc300, 0x09);
+ } else {
+ regmap_write(rt1308->regmap, 0xc311, 0x4f);
+ regmap_write(rt1308->regmap, 0xc300, 0x0b);
+ }
+ regmap_write(rt1308->regmap, 0xc900, 0x5a);
regmap_write(rt1308->regmap, 0xc1a0, 0x84);
regmap_write(rt1308->regmap, 0xc1a1, 0x01);
regmap_write(rt1308->regmap, 0xc360, 0x78);
@@ -257,7 +280,6 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave)
regmap_write(rt1308->regmap, 0xc070, 0x00);
regmap_write(rt1308->regmap, 0xc100, 0xd7);
regmap_write(rt1308->regmap, 0xc101, 0xd7);
- regmap_write(rt1308->regmap, 0xc300, 0x09);
if (rt1308->first_hw_init) {
regcache_cache_bypass(rt1308->regmap, false);
@@ -608,14 +630,42 @@ static const struct sdw_slave_ops rt1308_slave_ops = {
.bus_config = rt1308_bus_config,
};
+static int rt1308_sdw_parse_dt(struct rt1308_sdw_priv *rt1308, struct device *dev)
+{
+ int ret = 0;
+
+ device_property_read_u32(dev, "realtek,bq-params-cnt", &rt1308->bq_params_cnt);
+ if (rt1308->bq_params_cnt) {
+ rt1308->bq_params = devm_kzalloc(dev, rt1308->bq_params_cnt, GFP_KERNEL);
+ if (!rt1308->bq_params) {
+ dev_err(dev, "Could not allocate bq_params memory\n");
+ ret = -ENOMEM;
+ } else {
+ ret = device_property_read_u8_array(dev, "realtek,bq-params", rt1308->bq_params, rt1308->bq_params_cnt);
+ if (ret < 0)
+ dev_err(dev, "Could not read list of realtek,bq-params\n");
+ }
+ }
+
+ dev_dbg(dev, "bq_params_cnt=%d\n", rt1308->bq_params_cnt);
+ return ret;
+}
+
static int rt1308_sdw_component_probe(struct snd_soc_component *component)
{
+ struct rt1308_sdw_priv *rt1308 = snd_soc_component_get_drvdata(component);
int ret;
+ rt1308->component = component;
+ rt1308_sdw_parse_dt(rt1308, &rt1308->sdw_slave->dev);
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
+ /* apply BQ params */
+ rt1308_apply_bq_params(rt1308);
+
return 0;
}
diff --git a/sound/soc/codecs/rt1308-sdw.h b/sound/soc/codecs/rt1308-sdw.h
index 6668e19d85d4..1eaaef9f351b 100644
--- a/sound/soc/codecs/rt1308-sdw.h
+++ b/sound/soc/codecs/rt1308-sdw.h
@@ -139,10 +139,12 @@ static const struct reg_default rt1308_reg_defaults[] = {
{ 0x3005, 0x23 },
{ 0x3008, 0x02 },
{ 0x300a, 0x00 },
+ { 0xc000 | (RT1308_DATA_PATH << 4), 0x00 },
{ 0xc003 | (RT1308_DAC_SET << 4), 0x00 },
{ 0xc000 | (RT1308_POWER << 4), 0x00 },
{ 0xc001 | (RT1308_POWER << 4), 0x00 },
{ 0xc002 | (RT1308_POWER << 4), 0x00 },
+ { 0xc000 | (RT1308_POWER_STATUS << 4), 0x00 },
};
#define RT1308_SDW_OFFSET 0xc000
@@ -163,6 +165,9 @@ struct rt1308_sdw_priv {
bool first_hw_init;
int rx_mask;
int slots;
+ int hw_ver;
+ unsigned char *bq_params;
+ unsigned int bq_params_cnt;
};
struct sdw_stream_data {
diff --git a/sound/soc/codecs/rt1308.h b/sound/soc/codecs/rt1308.h
index ff7c423e879e..d3a0f91630ca 100644
--- a/sound/soc/codecs/rt1308.h
+++ b/sound/soc/codecs/rt1308.h
@@ -286,4 +286,9 @@ enum {
RT1308_AIFS
};
+enum rt1308_hw_ver {
+ RT1308_VER_C = 2,
+ RT1308_VER_D
+};
+
#endif /* end of _RT1308_H_ */
diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
index ed0a11436362..2db7ee6c6d33 100644
--- a/sound/soc/codecs/rt1316-sdw.c
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -254,6 +254,17 @@ static int rt1316_read_prop(struct sdw_slave *slave)
return 0;
}
+static void rt1316_apply_bq_params(struct rt1316_sdw_priv *rt1316)
+{
+ unsigned int i, reg, data;
+
+ for (i = 0; i < rt1316->bq_params_cnt; i += 3) {
+ reg = rt1316->bq_params[i] | (rt1316->bq_params[i + 1] << 8);
+ data = rt1316->bq_params[i + 2];
+ regmap_write(rt1316->regmap, reg, data);
+ }
+}
+
static int rt1316_io_init(struct device *dev, struct sdw_slave *slave)
{
struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev);
@@ -590,14 +601,42 @@ static struct sdw_slave_ops rt1316_slave_ops = {
.update_status = rt1316_update_status,
};
+static int rt1316_sdw_parse_dt(struct rt1316_sdw_priv *rt1316, struct device *dev)
+{
+ int ret = 0;
+
+ device_property_read_u32(dev, "realtek,bq-params-cnt", &rt1316->bq_params_cnt);
+ if (rt1316->bq_params_cnt) {
+ rt1316->bq_params = devm_kzalloc(dev, rt1316->bq_params_cnt, GFP_KERNEL);
+ if (!rt1316->bq_params) {
+ dev_err(dev, "Could not allocate bq_params memory\n");
+ ret = -ENOMEM;
+ } else {
+ ret = device_property_read_u8_array(dev, "realtek,bq-params", rt1316->bq_params, rt1316->bq_params_cnt);
+ if (ret < 0)
+ dev_err(dev, "Could not read list of realtek,bq-params\n");
+ }
+ }
+
+ dev_dbg(dev, "bq_params_cnt=%d\n", rt1316->bq_params_cnt);
+ return ret;
+}
+
static int rt1316_sdw_component_probe(struct snd_soc_component *component)
{
+ struct rt1316_sdw_priv *rt1316 = snd_soc_component_get_drvdata(component);
int ret;
+ rt1316->component = component;
+ rt1316_sdw_parse_dt(rt1316, &rt1316->sdw_slave->dev);
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
+ /* apply BQ params */
+ rt1316_apply_bq_params(rt1316);
+
return 0;
}
diff --git a/sound/soc/codecs/rt1316-sdw.h b/sound/soc/codecs/rt1316-sdw.h
index cbcdaa8f8cfa..57dbd49993b0 100644
--- a/sound/soc/codecs/rt1316-sdw.h
+++ b/sound/soc/codecs/rt1316-sdw.h
@@ -46,6 +46,8 @@ struct rt1316_sdw_priv {
struct sdw_bus_params params;
bool hw_init;
bool first_hw_init;
+ unsigned char *bq_params;
+ unsigned int bq_params_cnt;
};
struct sdw_stream_data {
diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c
new file mode 100644
index 000000000000..f85f5ab2c6d0
--- /dev/null
+++ b/sound/soc/codecs/rt1318-sdw.c
@@ -0,0 +1,884 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt1318-sdw.c -- rt1318 SDCA ALSA SoC amplifier audio driver
+//
+// Copyright(c) 2022 Realtek Semiconductor Corp.
+//
+//
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/dmi.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include "rt1318-sdw.h"
+
+static const struct reg_sequence rt1318_blind_write[] = {
+ { 0xc001, 0x43 },
+ { 0xc003, 0xa2 },
+ { 0xc004, 0x44 },
+ { 0xc005, 0x44 },
+ { 0xc006, 0x33 },
+ { 0xc007, 0x64 },
+ { 0xc320, 0x20 },
+ { 0xf203, 0x18 },
+ { 0xf211, 0x00 },
+ { 0xf212, 0x26 },
+ { 0xf20d, 0x17 },
+ { 0xf214, 0x06 },
+ { 0xf20e, 0x00 },
+ { 0xf223, 0x7f },
+ { 0xf224, 0xdb },
+ { 0xf225, 0xee },
+ { 0xf226, 0x3f },
+ { 0xf227, 0x0f },
+ { 0xf21a, 0x78 },
+ { 0xf242, 0x3c },
+ { 0xc321, 0x0b },
+ { 0xc200, 0xd8 },
+ { 0xc201, 0x27 },
+ { 0xc202, 0x0f },
+ { 0xf800, 0x20 },
+ { 0xdf00, 0x10 },
+ { 0xdf5f, 0x01 },
+ { 0xdf60, 0xa7 },
+ { 0xc400, 0x0e },
+ { 0xc401, 0x43 },
+ { 0xc402, 0xe0 },
+ { 0xc403, 0x00 },
+ { 0xc404, 0x4c },
+ { 0xc407, 0x02 },
+ { 0xc408, 0x3f },
+ { 0xc300, 0x01 },
+ { 0xc206, 0x78 },
+ { 0xc203, 0x84 },
+ { 0xc120, 0xc0 },
+ { 0xc121, 0x03 },
+ { 0xe000, 0x88 },
+ { 0xc321, 0x09 },
+ { 0xc322, 0x01 },
+ { 0xe706, 0x0f },
+ { 0xe707, 0x30 },
+ { 0xe806, 0x0f },
+ { 0xe807, 0x30 },
+ { 0xed00, 0xb0 },
+ { 0xce04, 0x02 },
+ { 0xce05, 0x63 },
+ { 0xce06, 0x68 },
+ { 0xce07, 0x07 },
+ { 0xcf04, 0x02 },
+ { 0xcf05, 0x63 },
+ { 0xcf06, 0x68 },
+ { 0xcf07, 0x07 },
+ { 0xce60, 0xe3 },
+ { 0xc130, 0x51 },
+ { 0xf102, 0x00 },
+ { 0xf103, 0x00 },
+ { 0xf104, 0xf5 },
+ { 0xf105, 0x06 },
+ { 0xf109, 0x9b },
+ { 0xf10a, 0x0b },
+ { 0xf10b, 0x4c },
+ { 0xf10b, 0x5c },
+ { 0xf102, 0x00 },
+ { 0xf103, 0x00 },
+ { 0xf104, 0xf5 },
+ { 0xf105, 0x0b },
+ { 0xf109, 0x03 },
+ { 0xf10a, 0x0b },
+ { 0xf10b, 0x4c },
+ { 0xf10b, 0x5c },
+ { 0xf102, 0x00 },
+ { 0xf103, 0x00 },
+ { 0xf104, 0xf5 },
+ { 0xf105, 0x0c },
+ { 0xf109, 0x7f },
+ { 0xf10a, 0x0b },
+ { 0xf10b, 0x4c },
+ { 0xf10b, 0x5c },
+
+ { 0xe604, 0x00 },
+ { 0xdb00, 0x0c },
+ { 0xdd00, 0x0c },
+ { 0xdc19, 0x00 },
+ { 0xdc1a, 0xff },
+ { 0xdc1b, 0xff },
+ { 0xdc1c, 0xff },
+ { 0xdc1d, 0x00 },
+ { 0xdc1e, 0x00 },
+ { 0xdc1f, 0x00 },
+ { 0xdc20, 0xff },
+ { 0xde19, 0x00 },
+ { 0xde1a, 0xff },
+ { 0xde1b, 0xff },
+ { 0xde1c, 0xff },
+ { 0xde1d, 0x00 },
+ { 0xde1e, 0x00 },
+ { 0xde1f, 0x00 },
+ { 0xde20, 0xff },
+ { 0xdb32, 0x00 },
+ { 0xdd32, 0x00 },
+ { 0xdb33, 0x0a },
+ { 0xdd33, 0x0a },
+ { 0xdb34, 0x1a },
+ { 0xdd34, 0x1a },
+ { 0xdb17, 0xef },
+ { 0xdd17, 0xef },
+ { 0xdba7, 0x00 },
+ { 0xdba8, 0x64 },
+ { 0xdda7, 0x00 },
+ { 0xdda8, 0x64 },
+ { 0xdb19, 0x40 },
+ { 0xdd19, 0x40 },
+ { 0xdb00, 0x4c },
+ { 0xdb01, 0x79 },
+ { 0xdd01, 0x79 },
+ { 0xdb04, 0x05 },
+ { 0xdb05, 0x03 },
+ { 0xdd04, 0x05 },
+ { 0xdd05, 0x03 },
+ { 0xdbbb, 0x09 },
+ { 0xdbbc, 0x30 },
+ { 0xdbbd, 0xf0 },
+ { 0xdbbe, 0xf1 },
+ { 0xddbb, 0x09 },
+ { 0xddbc, 0x30 },
+ { 0xddbd, 0xf0 },
+ { 0xddbe, 0xf1 },
+ { 0xdb01, 0x79 },
+ { 0xdd01, 0x79 },
+ { 0xdc52, 0xef },
+ { 0xde52, 0xef },
+ { 0x2f55, 0x22 },
+};
+
+static const struct reg_default rt1318_reg_defaults[] = {
+ { 0x3000, 0x00 },
+ { 0x3004, 0x01 },
+ { 0x3005, 0x23 },
+ { 0x3202, 0x00 },
+ { 0x3203, 0x01 },
+ { 0x3206, 0x00 },
+ { 0xc000, 0x00 },
+ { 0xc001, 0x43 },
+ { 0xc003, 0x22 },
+ { 0xc004, 0x44 },
+ { 0xc005, 0x44 },
+ { 0xc006, 0x33 },
+ { 0xc007, 0x64 },
+ { 0xc008, 0x05 },
+ { 0xc00a, 0xfc },
+ { 0xc00b, 0x0f },
+ { 0xc00c, 0x0e },
+ { 0xc00d, 0xef },
+ { 0xc00e, 0xe5 },
+ { 0xc00f, 0xff },
+ { 0xc120, 0xc0 },
+ { 0xc121, 0x00 },
+ { 0xc122, 0x00 },
+ { 0xc123, 0x14 },
+ { 0xc125, 0x00 },
+ { 0xc200, 0x00 },
+ { 0xc201, 0x00 },
+ { 0xc202, 0x00 },
+ { 0xc203, 0x04 },
+ { 0xc204, 0x00 },
+ { 0xc205, 0x00 },
+ { 0xc206, 0x68 },
+ { 0xc207, 0x70 },
+ { 0xc208, 0x00 },
+ { 0xc20a, 0x00 },
+ { 0xc20b, 0x01 },
+ { 0xc20c, 0x7f },
+ { 0xc20d, 0x01 },
+ { 0xc20e, 0x7f },
+ { 0xc300, 0x00 },
+ { 0xc301, 0x00 },
+ { 0xc303, 0x80 },
+ { 0xc320, 0x00 },
+ { 0xc321, 0x09 },
+ { 0xc322, 0x02 },
+ { 0xc410, 0x04 },
+ { 0xc430, 0x00 },
+ { 0xc431, 0x00 },
+ { 0xca00, 0x10 },
+ { 0xca01, 0x00 },
+ { 0xca02, 0x0b },
+ { 0xca10, 0x10 },
+ { 0xca11, 0x00 },
+ { 0xca12, 0x0b },
+ { 0xdd93, 0x00 },
+ { 0xdd94, 0x64 },
+ { 0xe300, 0xa0 },
+ { 0xed00, 0x80 },
+ { 0xed01, 0x0f },
+ { 0xed02, 0xff },
+ { 0xed03, 0x00 },
+ { 0xed04, 0x00 },
+ { 0xed05, 0x0f },
+ { 0xed06, 0xff },
+ { 0xf010, 0x10 },
+ { 0xf011, 0xec },
+ { 0xf012, 0x68 },
+ { 0xf013, 0x21 },
+ { 0xf800, 0x00 },
+ { 0xf801, 0x12 },
+ { 0xf802, 0xe0 },
+ { 0xf803, 0x2f },
+ { 0xf804, 0x00 },
+ { 0xf805, 0x00 },
+ { 0xf806, 0x07 },
+ { 0xf807, 0xff },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, RT1318_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+};
+
+static bool rt1318_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f55:
+ case 0x3000:
+ case 0x3004 ... 0x3005:
+ case 0x3202 ... 0x3203:
+ case 0x3206:
+ case 0xc000 ... 0xc00f:
+ case 0xc120 ... 0xc125:
+ case 0xc200 ... 0xc20e:
+ case 0xc300 ... 0xc303:
+ case 0xc320 ... 0xc322:
+ case 0xc410:
+ case 0xc430 ... 0xc431:
+ case 0xca00 ... 0xca02:
+ case 0xca10 ... 0xca12:
+ case 0xcb00 ... 0xcb0b:
+ case 0xcc00 ... 0xcce5:
+ case 0xcd00 ... 0xcde5:
+ case 0xce00 ... 0xce6a:
+ case 0xcf00 ... 0xcf53:
+ case 0xd000 ... 0xd0cc:
+ case 0xd100 ... 0xd1b9:
+ case 0xdb00 ... 0xdc53:
+ case 0xdd00 ... 0xde53:
+ case 0xdf00 ... 0xdf6b:
+ case 0xe300:
+ case 0xeb00 ... 0xebcc:
+ case 0xec00 ... 0xecb9:
+ case 0xed00 ... 0xed06:
+ case 0xf010 ... 0xf014:
+ case 0xf800 ... 0xf807:
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, RT1318_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt1318_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f55:
+ case 0x3000 ... 0x3001:
+ case 0xc000:
+ case 0xc301:
+ case 0xc410:
+ case 0xc430 ... 0xc431:
+ case 0xdb06:
+ case 0xdb12:
+ case 0xdb1d ... 0xdb1f:
+ case 0xdb35:
+ case 0xdb37:
+ case 0xdb8a ... 0xdb92:
+ case 0xdbc5 ... 0xdbc8:
+ case 0xdc2b ... 0xdc49:
+ case 0xdd0b:
+ case 0xdd12:
+ case 0xdd1d ... 0xdd1f:
+ case 0xdd35:
+ case 0xdd8a ... 0xdd92:
+ case 0xddc5 ... 0xddc8:
+ case 0xde2b ... 0xde44:
+ case 0xdf4a ... 0xdf55:
+ case 0xe224 ... 0xe23b:
+ case 0xea01:
+ case 0xebc5:
+ case 0xebc8:
+ case 0xebcb ... 0xebcc:
+ case 0xed03 ... 0xed06:
+ case 0xf010 ... 0xf014:
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rt1318_sdw_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt1318_readable_register,
+ .volatile_reg = rt1318_volatile_register,
+ .max_register = 0x41081488,
+ .reg_defaults = rt1318_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt1318_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt1318_read_prop(struct sdw_slave *slave)
+{
+ struct sdw_slave_prop *prop = &slave->prop;
+ int nval;
+ int i, j;
+ u32 bit;
+ unsigned long addr;
+ struct sdw_dpn_prop *dpn;
+
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+ prop->is_sdca = true;
+
+ prop->paging_support = true;
+
+ /* first we need to allocate memory for set bits in port lists */
+ prop->source_ports = BIT(2);
+ prop->sink_ports = BIT(1);
+
+ nval = hweight32(prop->source_ports);
+ prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->src_dpn_prop), GFP_KERNEL);
+ if (!prop->src_dpn_prop)
+ return -ENOMEM;
+
+ i = 0;
+ dpn = prop->src_dpn_prop;
+ addr = prop->source_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[i].num = bit;
+ dpn[i].type = SDW_DPN_FULL;
+ dpn[i].simple_ch_prep_sm = true;
+ dpn[i].ch_prep_timeout = 10;
+ i++;
+ }
+
+ /* do this again for sink now */
+ nval = hweight32(prop->sink_ports);
+ prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+ if (!prop->sink_dpn_prop)
+ return -ENOMEM;
+
+ j = 0;
+ dpn = prop->sink_dpn_prop;
+ addr = prop->sink_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[j].num = bit;
+ dpn[j].type = SDW_DPN_FULL;
+ dpn[j].simple_ch_prep_sm = true;
+ dpn[j].ch_prep_timeout = 10;
+ j++;
+ }
+
+ /* set the timeout values */
+ prop->clk_stop_timeout = 20;
+
+ return 0;
+}
+
+static int rt1318_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev);
+
+ if (rt1318->hw_init)
+ return 0;
+
+ if (rt1318->first_hw_init) {
+ regcache_cache_only(rt1318->regmap, false);
+ regcache_cache_bypass(rt1318->regmap, true);
+ } else {
+ /*
+ * PM runtime is only enabled when a Slave reports as Attached
+ */
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
+ pm_runtime_use_autosuspend(&slave->dev);
+
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(&slave->dev);
+
+ pm_runtime_enable(&slave->dev);
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+
+ /* blind write */
+ regmap_multi_reg_write(rt1318->regmap, rt1318_blind_write,
+ ARRAY_SIZE(rt1318_blind_write));
+
+ if (rt1318->first_hw_init) {
+ regcache_cache_bypass(rt1318->regmap, false);
+ regcache_mark_dirty(rt1318->regmap);
+ }
+
+ /* Mark Slave initialization complete */
+ rt1318->first_hw_init = true;
+ rt1318->hw_init = true;
+
+ pm_runtime_mark_last_busy(&slave->dev);
+ pm_runtime_put_autosuspend(&slave->dev);
+
+ dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
+ return 0;
+}
+
+static int rt1318_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev);
+
+ /* Update the status */
+ rt1318->status = status;
+
+ if (status == SDW_SLAVE_UNATTACHED)
+ rt1318->hw_init = false;
+
+ /*
+ * Perform initialization only if slave status is present and
+ * hw_init flag is false
+ */
+ if (rt1318->hw_init || rt1318->status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt1318_io_init(&slave->dev, slave);
+}
+
+static int rt1318_classd_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt1318_sdw_priv *rt1318 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt1318->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23,
+ RT1318_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt1318->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23,
+ RT1318_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const char * const rt1318_rx_data_ch_select[] = {
+ "L,R",
+ "L,L",
+ "L,R",
+ "L,L+R",
+ "R,L",
+ "R,R",
+ "R,L+R",
+ "L+R,L",
+ "L+R,R",
+ "L+R,L+R",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1318_rx_data_ch_enum,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0,
+ rt1318_rx_data_ch_select);
+
+static const struct snd_kcontrol_new rt1318_snd_controls[] = {
+
+ /* UDMPU Cluster Selection */
+ SOC_ENUM("RX Channel Select", rt1318_rx_data_ch_enum),
+};
+
+static const struct snd_kcontrol_new rt1318_sto_dac =
+ SOC_DAPM_DOUBLE_R("Switch",
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R),
+ 0, 1, 1);
+
+static const struct snd_soc_dapm_widget rt1318_dapm_widgets[] = {
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Digital Interface */
+ SND_SOC_DAPM_SWITCH("DAC", SND_SOC_NOPM, 0, 0, &rt1318_sto_dac),
+
+ /* Output */
+ SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0,
+ rt1318_classd_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_OUTPUT("SPOL"),
+ SND_SOC_DAPM_OUTPUT("SPOR"),
+ /* Input */
+ SND_SOC_DAPM_PGA("FB Data", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SIGGEN("FB Gen"),
+};
+
+static const struct snd_soc_dapm_route rt1318_dapm_routes[] = {
+ { "DAC", "Switch", "DP1RX" },
+ { "CLASS D", NULL, "DAC" },
+ { "SPOL", NULL, "CLASS D" },
+ { "SPOR", NULL, "CLASS D" },
+
+ { "FB Data", NULL, "FB Gen" },
+ { "DP2TX", NULL, "FB Data" },
+};
+
+static int rt1318_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+ int direction)
+{
+ struct sdw_stream_data *stream;
+
+ if (!sdw_stream)
+ return 0;
+
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (!stream)
+ return -ENOMEM;
+
+ stream->sdw_stream = sdw_stream;
+
+ /* Use tx_mask or rx_mask to configure stream tag and set dma_data */
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ dai->playback_dma_data = stream;
+ else
+ dai->capture_dma_data = stream;
+
+ return 0;
+}
+
+static void rt1318_sdw_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct sdw_stream_data *stream;
+
+ stream = snd_soc_dai_get_dma_data(dai, substream);
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+ kfree(stream);
+}
+
+static int rt1318_sdw_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1318_sdw_priv *rt1318 =
+ snd_soc_component_get_drvdata(component);
+ struct sdw_stream_config stream_config;
+ struct sdw_port_config port_config;
+ enum sdw_data_direction direction;
+ struct sdw_stream_data *stream;
+ int retval, port, num_channels, ch_mask;
+ unsigned int sampling_rate;
+
+ dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+ stream = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!stream)
+ return -EINVAL;
+
+ if (!rt1318->sdw_slave)
+ return -EINVAL;
+
+ /* SoundWire specific configuration */
+ /* port 1 for playback */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ direction = SDW_DATA_DIR_RX;
+ port = 1;
+ } else {
+ direction = SDW_DATA_DIR_TX;
+ port = 2;
+ }
+
+ num_channels = params_channels(params);
+ ch_mask = (1 << num_channels) - 1;
+
+ stream_config.frame_rate = params_rate(params);
+ stream_config.ch_count = num_channels;
+ stream_config.bps = snd_pcm_format_width(params_format(params));
+ stream_config.direction = direction;
+
+ port_config.ch_mask = ch_mask;
+ port_config.num = port;
+
+ retval = sdw_stream_add_slave(rt1318->sdw_slave, &stream_config,
+ &port_config, 1, stream->sdw_stream);
+ if (retval) {
+ dev_err(dai->dev, "Unable to configure port\n");
+ return retval;
+ }
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 16000:
+ sampling_rate = RT1318_SDCA_RATE_16000HZ;
+ break;
+ case 32000:
+ sampling_rate = RT1318_SDCA_RATE_32000HZ;
+ break;
+ case 44100:
+ sampling_rate = RT1318_SDCA_RATE_44100HZ;
+ break;
+ case 48000:
+ sampling_rate = RT1318_SDCA_RATE_48000HZ;
+ break;
+ case 96000:
+ sampling_rate = RT1318_SDCA_RATE_96000HZ;
+ break;
+ case 192000:
+ sampling_rate = RT1318_SDCA_RATE_192000HZ;
+ break;
+ default:
+ dev_err(component->dev, "Rate %d is not supported\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ /* set sampling frequency */
+ regmap_write(rt1318->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+
+ return 0;
+}
+
+static int rt1318_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1318_sdw_priv *rt1318 =
+ snd_soc_component_get_drvdata(component);
+ struct sdw_stream_data *stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt1318->sdw_slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt1318->sdw_slave, stream->sdw_stream);
+ return 0;
+}
+
+/*
+ * slave_ops: callbacks for get_clock_stop_mode, clock_stop and
+ * port_prep are not defined for now
+ */
+static struct sdw_slave_ops rt1318_slave_ops = {
+ .read_prop = rt1318_read_prop,
+ .update_status = rt1318_update_status,
+};
+
+static int rt1318_sdw_component_probe(struct snd_soc_component *component)
+{
+ int ret;
+ struct rt1318_sdw_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ rt1318->component = component;
+
+ ret = pm_runtime_resume(component->dev);
+ dev_dbg(&rt1318->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_sdw_rt1318 = {
+ .probe = rt1318_sdw_component_probe,
+ .controls = rt1318_snd_controls,
+ .num_controls = ARRAY_SIZE(rt1318_snd_controls),
+ .dapm_widgets = rt1318_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt1318_dapm_widgets),
+ .dapm_routes = rt1318_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt1318_dapm_routes),
+ .endianness = 1,
+};
+
+static const struct snd_soc_dai_ops rt1318_aif_dai_ops = {
+ .hw_params = rt1318_sdw_hw_params,
+ .hw_free = rt1318_sdw_pcm_hw_free,
+ .set_stream = rt1318_set_sdw_stream,
+ .shutdown = rt1318_sdw_shutdown,
+};
+
+#define RT1318_STEREO_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define RT1318_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver rt1318_sdw_dai[] = {
+ {
+ .name = "rt1318-aif",
+ .playback = {
+ .stream_name = "DP1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT1318_STEREO_RATES,
+ .formats = RT1318_FORMATS,
+ },
+ .capture = {
+ .stream_name = "DP2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT1318_STEREO_RATES,
+ .formats = RT1318_FORMATS,
+ },
+ .ops = &rt1318_aif_dai_ops,
+ },
+};
+
+static int rt1318_sdw_init(struct device *dev, struct regmap *regmap,
+ struct sdw_slave *slave)
+{
+ struct rt1318_sdw_priv *rt1318;
+ int ret;
+
+ rt1318 = devm_kzalloc(dev, sizeof(*rt1318), GFP_KERNEL);
+ if (!rt1318)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt1318);
+ rt1318->sdw_slave = slave;
+ rt1318->regmap = regmap;
+
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt1318->hw_init = false;
+ rt1318->first_hw_init = false;
+
+ ret = devm_snd_soc_register_component(dev,
+ &soc_component_sdw_rt1318,
+ rt1318_sdw_dai,
+ ARRAY_SIZE(rt1318_sdw_dai));
+
+ dev_dbg(&slave->dev, "%s\n", __func__);
+
+ return ret;
+}
+
+static int rt1318_sdw_probe(struct sdw_slave *slave,
+ const struct sdw_device_id *id)
+{
+ struct regmap *regmap;
+
+ /* Regmap Initialization */
+ regmap = devm_regmap_init_sdw(slave, &rt1318_sdw_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt1318_sdw_init(&slave->dev, regmap, slave);
+}
+
+static int rt1318_sdw_remove(struct sdw_slave *slave)
+{
+ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev);
+
+ if (rt1318->first_hw_init)
+ pm_runtime_disable(&slave->dev);
+
+ return 0;
+}
+
+static const struct sdw_device_id rt1318_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x1318, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt1318_id);
+
+static int __maybe_unused rt1318_dev_suspend(struct device *dev)
+{
+ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev);
+
+ if (!rt1318->hw_init)
+ return 0;
+
+ regcache_cache_only(rt1318->regmap, true);
+ return 0;
+}
+
+#define RT1318_PROBE_TIMEOUT 5000
+
+static int __maybe_unused rt1318_dev_resume(struct device *dev)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev);
+ unsigned long time;
+
+ if (!rt1318->first_hw_init)
+ return 0;
+
+ if (!slave->unattach_request)
+ goto regmap_sync;
+
+ time = wait_for_completion_timeout(&slave->initialization_complete,
+ msecs_to_jiffies(RT1318_PROBE_TIMEOUT));
+ if (!time) {
+ dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ return -ETIMEDOUT;
+ }
+
+regmap_sync:
+ slave->unattach_request = 0;
+ regcache_cache_only(rt1318->regmap, false);
+ regcache_sync(rt1318->regmap);
+
+ return 0;
+}
+
+static const struct dev_pm_ops rt1318_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume)
+ SET_RUNTIME_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume, NULL)
+};
+
+static struct sdw_driver rt1318_sdw_driver = {
+ .driver = {
+ .name = "rt1318-sdca",
+ .owner = THIS_MODULE,
+ .pm = &rt1318_pm,
+ },
+ .probe = rt1318_sdw_probe,
+ .remove = rt1318_sdw_remove,
+ .ops = &rt1318_slave_ops,
+ .id_table = rt1318_id,
+};
+module_sdw_driver(rt1318_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT1318 driver SDCA SDW");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt1318-sdw.h b/sound/soc/codecs/rt1318-sdw.h
new file mode 100644
index 000000000000..4d7ac9c4bd8d
--- /dev/null
+++ b/sound/soc/codecs/rt1318-sdw.h
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt1318-sdw.h -- RT1318 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2022 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT1318_SDW_H__
+#define __RT1318_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/soc.h>
+
+/* imp-defined registers */
+#define RT1318_SAPU_SM 0x3203
+
+#define R1318_TCON 0xc203
+#define R1318_TCON_RELATED_1 0xc206
+
+#define R1318_SPK_TEMPERATRUE_PROTECTION_0 0xdb00
+#define R1318_SPK_TEMPERATRUE_PROTECTION_L_4 0xdb08
+#define R1318_SPK_TEMPERATRUE_PROTECTION_R_4 0xdd08
+
+#define R1318_SPK_TEMPERATRUE_PROTECTION_L_6 0xdb12
+#define R1318_SPK_TEMPERATRUE_PROTECTION_R_6 0xdd12
+
+#define RT1318_INIT_RECIPROCAL_REG_L_24 0xdbb5
+#define RT1318_INIT_RECIPROCAL_REG_L_23_16 0xdbb6
+#define RT1318_INIT_RECIPROCAL_REG_L_15_8 0xdbb7
+#define RT1318_INIT_RECIPROCAL_REG_L_7_0 0xdbb8
+#define RT1318_INIT_RECIPROCAL_REG_R_24 0xddb5
+#define RT1318_INIT_RECIPROCAL_REG_R_23_16 0xddb6
+#define RT1318_INIT_RECIPROCAL_REG_R_15_8 0xddb7
+#define RT1318_INIT_RECIPROCAL_REG_R_7_0 0xddb8
+
+#define RT1318_INIT_R0_RECIPROCAL_SYN_L_24 0xdbc5
+#define RT1318_INIT_R0_RECIPROCAL_SYN_L_23_16 0xdbc6
+#define RT1318_INIT_R0_RECIPROCAL_SYN_L_15_8 0xdbc7
+#define RT1318_INIT_R0_RECIPROCAL_SYN_L_7_0 0xdbc8
+#define RT1318_INIT_R0_RECIPROCAL_SYN_R_24 0xddc5
+#define RT1318_INIT_R0_RECIPROCAL_SYN_R_23_16 0xddc6
+#define RT1318_INIT_R0_RECIPROCAL_SYN_R_15_8 0xddc7
+#define RT1318_INIT_R0_RECIPROCAL_SYN_R_7_0 0xddc8
+
+#define RT1318_R0_COMPARE_FLAG_L 0xdb35
+#define RT1318_R0_COMPARE_FLAG_R 0xdd35
+
+#define RT1318_STP_INITIAL_RS_TEMP_H 0xdd93
+#define RT1318_STP_INITIAL_RS_TEMP_L 0xdd94
+
+/* RT1318 SDCA Control - function number */
+#define FUNC_NUM_SMART_AMP 0x04
+
+/* RT1318 SDCA entity */
+#define RT1318_SDCA_ENT_PDE23 0x31
+#define RT1318_SDCA_ENT_XU24 0x24
+#define RT1318_SDCA_ENT_FU21 0x03
+#define RT1318_SDCA_ENT_UDMPU21 0x02
+#define RT1318_SDCA_ENT_CS21 0x21
+#define RT1318_SDCA_ENT_SAPU 0x29
+
+/* RT1318 SDCA control */
+#define RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10
+#define RT1318_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT1318_SDCA_CTL_FU_MUTE 0x01
+#define RT1318_SDCA_CTL_FU_VOLUME 0x02
+#define RT1318_SDCA_CTL_UDMPU_CLUSTER 0x10
+#define RT1318_SDCA_CTL_SAPU_PROTECTION_MODE 0x10
+#define RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS 0x11
+
+/* RT1318 SDCA channel */
+#define CH_L 0x01
+#define CH_R 0x02
+
+/* sample frequency index */
+#define RT1318_SDCA_RATE_16000HZ 0x04
+#define RT1318_SDCA_RATE_32000HZ 0x07
+#define RT1318_SDCA_RATE_44100HZ 0x08
+#define RT1318_SDCA_RATE_48000HZ 0x09
+#define RT1318_SDCA_RATE_96000HZ 0x0b
+#define RT1318_SDCA_RATE_192000HZ 0x0d
+
+
+struct rt1318_sdw_priv {
+ struct snd_soc_component *component;
+ struct regmap *regmap;
+ struct sdw_slave *sdw_slave;
+ enum sdw_slave_status status;
+ struct sdw_bus_params params;
+ bool hw_init;
+ bool first_hw_init;
+};
+
+struct sdw_stream_data {
+ struct sdw_stream_runtime *sdw_stream;
+};
+
+#endif /* __RT1318_SDW_H__ */
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index a2ce52dafea8..cea26f3a02b6 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -1166,6 +1166,13 @@ static const struct dmi_system_id force_combo_jack_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Geminilake")
}
},
+ {
+ .ident = "Intel Kabylake R RVP",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Kabylake Client platform")
+ }
+ },
{ }
};
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index 2df95e792900..7e3eb65afe16 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -35,6 +35,8 @@ const char *rt5682_supply_names[RT5682_NUM_SUPPLIES] = {
"AVDD",
"MICVDD",
"VBAT",
+ "DBVDD",
+ "LDO1-IN",
};
EXPORT_SYMBOL_GPL(rt5682_supply_names);
diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
index 52ff0d9c36c5..d568c6993c33 100644
--- a/sound/soc/codecs/rt5682.h
+++ b/sound/soc/codecs/rt5682.h
@@ -1424,7 +1424,7 @@ enum {
RT5682_CLK_SEL_I2S2_ASRC,
};
-#define RT5682_NUM_SUPPLIES 3
+#define RT5682_NUM_SUPPLIES 5
struct rt5682_priv {
struct snd_soc_component *component;
diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c
index 466a37f3500c..f5e5dbc3b0f0 100644
--- a/sound/soc/codecs/rt5682s.c
+++ b/sound/soc/codecs/rt5682s.c
@@ -44,6 +44,8 @@ static const struct rt5682s_platform_data i2s_default_platform_data = {
static const char *rt5682s_supply_names[RT5682S_NUM_SUPPLIES] = {
[RT5682S_SUPPLY_AVDD] = "AVDD",
[RT5682S_SUPPLY_MICVDD] = "MICVDD",
+ [RT5682S_SUPPLY_DBVDD] = "DBVDD",
+ [RT5682S_SUPPLY_LDO1_IN] = "LDO1-IN",
};
static const struct reg_sequence patch_list[] = {
@@ -1981,7 +1983,7 @@ static int rt5682s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
unsigned int rx_mask, int slots, int slot_width)
{
struct snd_soc_component *component = dai->component;
- unsigned int cl, val = 0;
+ unsigned int cl, val = 0, tx_slotnum;
if (tx_mask || rx_mask)
snd_soc_component_update_bits(component,
@@ -1990,6 +1992,16 @@ static int rt5682s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
snd_soc_component_update_bits(component,
RT5682S_TDM_ADDA_CTRL_2, RT5682S_TDM_EN, 0);
+ /* Tx slot configuration */
+ tx_slotnum = hweight_long(tx_mask);
+ if (tx_slotnum) {
+ if (tx_slotnum > slots) {
+ dev_err(component->dev, "Invalid or oversized Tx slots.\n");
+ return -EINVAL;
+ }
+ val |= (tx_slotnum - 1) << RT5682S_TDM_ADC_DL_SFT;
+ }
+
switch (slots) {
case 4:
val |= RT5682S_TDM_TX_CH_4;
@@ -2010,7 +2022,8 @@ static int rt5682s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
}
snd_soc_component_update_bits(component, RT5682S_TDM_CTRL,
- RT5682S_TDM_TX_CH_MASK | RT5682S_TDM_RX_CH_MASK, val);
+ RT5682S_TDM_TX_CH_MASK | RT5682S_TDM_RX_CH_MASK |
+ RT5682S_TDM_ADC_DL_MASK, val);
switch (slot_width) {
case 8:
@@ -3078,6 +3091,14 @@ static void rt5682s_i2c_disable_regulators(void *data)
if (ret)
dev_err(dev, "Failed to disable supply AVDD: %d\n", ret);
+ ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_DBVDD].consumer);
+ if (ret)
+ dev_err(dev, "Failed to disable supply DBVDD: %d\n", ret);
+
+ ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_LDO1_IN].consumer);
+ if (ret)
+ dev_err(dev, "Failed to disable supply LDO1-IN: %d\n", ret);
+
usleep_range(1000, 1500);
ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_MICVDD].consumer);
@@ -3139,6 +3160,18 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c)
return ret;
}
+ ret = regulator_enable(rt5682s->supplies[RT5682S_SUPPLY_DBVDD].consumer);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to enable supply DBVDD: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_enable(rt5682s->supplies[RT5682S_SUPPLY_LDO1_IN].consumer);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to enable supply LDO1-IN: %d\n", ret);
+ return ret;
+ }
+
if (gpio_is_valid(rt5682s->pdata.ldo1_en)) {
if (devm_gpio_request_one(&i2c->dev, rt5682s->pdata.ldo1_en,
GPIOF_OUT_INIT_HIGH, "rt5682s"))
diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h
index 824dc6543c18..67f86a38a1cc 100644
--- a/sound/soc/codecs/rt5682s.h
+++ b/sound/soc/codecs/rt5682s.h
@@ -899,6 +899,7 @@
#define RT5682S_TDM_RX_CH_8 (0x3 << 8)
#define RT5682S_TDM_ADC_LCA_MASK (0x7 << 4)
#define RT5682S_TDM_ADC_LCA_SFT 4
+#define RT5682S_TDM_ADC_DL_MASK (0x3 << 0)
#define RT5682S_TDM_ADC_DL_SFT 0
/* TDM control 2 (0x007a) */
@@ -1437,6 +1438,8 @@ struct pll_calc_map {
enum {
RT5682S_SUPPLY_AVDD,
RT5682S_SUPPLY_MICVDD,
+ RT5682S_SUPPLY_DBVDD,
+ RT5682S_SUPPLY_LDO1_IN,
RT5682S_NUM_SUPPLIES,
};
diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c
index d30c0d24d90a..bf67de12d20b 100644
--- a/sound/soc/codecs/simple-mux.c
+++ b/sound/soc/codecs/simple-mux.c
@@ -55,6 +55,14 @@ static int simple_mux_control_put(struct snd_kcontrol *kcontrol,
e, NULL);
}
+static unsigned int simple_mux_read(struct snd_soc_component *component,
+ unsigned int reg)
+{
+ struct simple_mux *priv = snd_soc_component_get_drvdata(component);
+
+ return priv->mux;
+}
+
static const struct snd_kcontrol_new simple_mux_mux =
SOC_DAPM_ENUM_EXT("Muxer", simple_mux_enum, simple_mux_control_get, simple_mux_control_put);
@@ -76,6 +84,7 @@ static const struct snd_soc_component_driver simple_mux_component_driver = {
.num_dapm_widgets = ARRAY_SIZE(simple_mux_dapm_widgets),
.dapm_routes = simple_mux_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(simple_mux_dapm_routes),
+ .read = simple_mux_read,
};
static int simple_mux_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c
index baab320ef988..a969547708d4 100644
--- a/sound/soc/codecs/tlv320adc3xxx.c
+++ b/sound/soc/codecs/tlv320adc3xxx.c
@@ -1449,7 +1449,7 @@ static struct i2c_driver adc3xxx_i2c_driver = {
.of_match_table = tlv320adc3xxx_of_match,
},
.probe_new = adc3xxx_i2c_probe,
- .remove = adc3xxx_i2c_remove,
+ .remove = __exit_p(adc3xxx_i2c_remove),
.id_table = adc3xxx_i2c_id,
};
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 08938801daec..56e795a00e22 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -32,12 +32,12 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -45,7 +45,6 @@
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
-#include <sound/tlv320aic3x.h>
#include "tlv320aic3x.h"
@@ -57,8 +56,6 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
"DRVDD", /* ADC Analog and Output Driver Voltage */
};
-static LIST_HEAD(reset_list);
-
struct aic3x_priv;
struct aic3x_disable_nb {
@@ -66,6 +63,10 @@ struct aic3x_disable_nb {
struct aic3x_priv *aic3x;
};
+struct aic3x_setup_data {
+ unsigned int gpio_func[2];
+};
+
/* codec private data */
struct aic3x_priv {
struct snd_soc_component *component;
@@ -77,9 +78,9 @@ struct aic3x_priv {
unsigned int dai_fmt;
unsigned int tdm_delay;
unsigned int slot_width;
- struct list_head list;
int master;
- int gpio_reset;
+ struct gpio_desc *gpio_reset;
+ bool shared_reset;
int power;
u16 model;
@@ -1366,8 +1367,8 @@ static int aic3x_regulator_event(struct notifier_block *nb,
* Put codec to reset and require cache sync as at least one
* of the supplies was disabled
*/
- if (gpio_is_valid(aic3x->gpio_reset))
- gpio_set_value(aic3x->gpio_reset, 0);
+ if (aic3x->gpio_reset)
+ gpiod_set_value(aic3x->gpio_reset, 1);
regcache_mark_dirty(aic3x->regmap);
}
@@ -1387,9 +1388,9 @@ static int aic3x_set_power(struct snd_soc_component *component, int power)
goto out;
aic3x->power = 1;
- if (gpio_is_valid(aic3x->gpio_reset)) {
+ if (aic3x->gpio_reset) {
udelay(1);
- gpio_set_value(aic3x->gpio_reset, 1);
+ gpiod_set_value(aic3x->gpio_reset, 0);
}
/* Sync reg_cache with the hardware */
@@ -1595,19 +1596,6 @@ static int aic3x_init(struct snd_soc_component *component)
return 0;
}
-static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x)
-{
- struct aic3x_priv *a;
-
- list_for_each_entry(a, &reset_list, list) {
- if (gpio_is_valid(aic3x->gpio_reset) &&
- aic3x->gpio_reset == a->gpio_reset)
- return true;
- }
-
- return false;
-}
-
static int aic3x_component_probe(struct snd_soc_component *component)
{
struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
@@ -1748,7 +1736,6 @@ static const struct reg_sequence aic3007_class_d[] = {
int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver_data)
{
- struct aic3x_pdata *pdata = dev->platform_data;
struct aic3x_priv *aic3x;
struct aic3x_setup_data *ai3x_setup;
struct device_node *np = dev->of_node;
@@ -1768,28 +1755,11 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
regcache_cache_only(aic3x->regmap, true);
dev_set_drvdata(dev, aic3x);
- if (pdata) {
- aic3x->gpio_reset = pdata->gpio_reset;
- aic3x->setup = pdata->setup;
- aic3x->micbias_vg = pdata->micbias_vg;
- } else if (np) {
+ if (np) {
ai3x_setup = devm_kzalloc(dev, sizeof(*ai3x_setup), GFP_KERNEL);
if (!ai3x_setup)
return -ENOMEM;
- ret = of_get_named_gpio(np, "reset-gpios", 0);
- if (ret >= 0) {
- aic3x->gpio_reset = ret;
- } else {
- ret = of_get_named_gpio(np, "gpio-reset", 0);
- if (ret > 0) {
- dev_warn(dev, "Using deprecated property \"gpio-reset\", please update your DT");
- aic3x->gpio_reset = ret;
- } else {
- aic3x->gpio_reset = -1;
- }
- }
-
if (of_property_read_u32_array(np, "ai3x-gpio-func",
ai3x_setup->gpio_func, 2) >= 0) {
aic3x->setup = ai3x_setup;
@@ -1814,29 +1784,43 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
} else {
aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
}
-
- } else {
- aic3x->gpio_reset = -1;
}
aic3x->model = driver_data;
- if (gpio_is_valid(aic3x->gpio_reset) &&
- !aic3x_is_shared_reset(aic3x)) {
- ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
- if (ret != 0)
- goto err;
- gpio_direction_output(aic3x->gpio_reset, 0);
+ aic3x->gpio_reset = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ ret = PTR_ERR_OR_ZERO(aic3x->gpio_reset);
+ if (ret) {
+ if (ret != -EBUSY)
+ return ret;
+
+ /*
+ * Apparently there are setups where the codec is sharing
+ * its reset line. Try to get it non-exclusively, although
+ * the utility of this is unclear: how do we make sure that
+ * resetting one chip will not disturb the others that share
+ * the same line?
+ */
+ aic3x->gpio_reset = devm_gpiod_get(dev, "reset",
+ GPIOD_ASIS | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+ ret = PTR_ERR_OR_ZERO(aic3x->gpio_reset);
+ if (ret)
+ return ret;
+
+ aic3x->shared_reset = true;
}
+ gpiod_set_consumer_name(aic3x->gpio_reset, "tlv320aic3x reset");
+
for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
aic3x->supplies[i].supply = aic3x_supply_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(aic3x->supplies),
aic3x->supplies);
- if (ret != 0) {
+ if (ret) {
dev_err(dev, "Failed to request supplies: %d\n", ret);
- goto err_gpio;
+ return ret;
}
aic3x_configure_ocmv(dev, aic3x);
@@ -1845,26 +1829,14 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
ret = regmap_register_patch(aic3x->regmap, aic3007_class_d,
ARRAY_SIZE(aic3007_class_d));
if (ret != 0)
- dev_err(dev, "Failed to init class D: %d\n",
- ret);
+ dev_err(dev, "Failed to init class D: %d\n", ret);
}
ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic3x, &aic3x_dai, 1);
-
- if (ret != 0)
- goto err_gpio;
-
- INIT_LIST_HEAD(&aic3x->list);
- list_add(&aic3x->list, &reset_list);
+ if (ret)
+ return ret;
return 0;
-
-err_gpio:
- if (gpio_is_valid(aic3x->gpio_reset) &&
- !aic3x_is_shared_reset(aic3x))
- gpio_free(aic3x->gpio_reset);
-err:
- return ret;
}
EXPORT_SYMBOL(aic3x_probe);
@@ -1872,13 +1844,9 @@ void aic3x_remove(struct device *dev)
{
struct aic3x_priv *aic3x = dev_get_drvdata(dev);
- list_del(&aic3x->list);
-
- if (gpio_is_valid(aic3x->gpio_reset) &&
- !aic3x_is_shared_reset(aic3x)) {
- gpio_set_value(aic3x->gpio_reset, 0);
- gpio_free(aic3x->gpio_reset);
- }
+ /* Leave the codec in reset state */
+ if (aic3x->gpio_reset && !aic3x->shared_reset)
+ gpiod_set_value(aic3x->gpio_reset, 1);
}
EXPORT_SYMBOL(aic3x_remove);
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index 14298f9e6d9b..066e5a6322b8 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -298,4 +298,47 @@ enum {
#define AIC3X_BUTTON_DEBOUNCE_SHIFT 0
#define AIC3X_BUTTON_DEBOUNCE_MASK 3
+/* GPIO API */
+enum {
+ AIC3X_GPIO1_FUNC_DISABLED = 0,
+ AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX = 2,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5,
+ AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6,
+ AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7,
+ AIC3X_GPIO1_FUNC_INPUT = 8,
+ AIC3X_GPIO1_FUNC_OUTPUT = 9,
+ AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10,
+ AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11,
+ AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12,
+ AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13,
+ AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14,
+ AIC3X_GPIO1_FUNC_ALL_IRQ = 16
+};
+
+enum {
+ AIC3X_GPIO2_FUNC_DISABLED = 0,
+ AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2,
+ AIC3X_GPIO2_FUNC_INPUT = 3,
+ AIC3X_GPIO2_FUNC_OUTPUT = 4,
+ AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5,
+ AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8,
+ AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
+ AIC3X_GPIO2_FUNC_ALL_IRQ = 10,
+ AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
+ AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
+ AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13,
+ AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14,
+ AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15
+};
+
+enum aic3x_micbias_voltage {
+ AIC3X_MICBIAS_OFF = 0,
+ AIC3X_MICBIAS_2_0V = 1,
+ AIC3X_MICBIAS_2_5V = 2,
+ AIC3X_MICBIAS_AVDDV = 3,
+};
+
#endif /* _AIC3X_H */
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index e48768233e20..9c50ac356c89 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -700,8 +700,10 @@ static void headset_ramp(struct snd_soc_component *component, int ramp)
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
struct twl4030_board_params *board_params = twl4030->board_params;
/* Base values for ramp delay calculation: 2^19 - 2^26 */
- unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
- 8388608, 16777216, 33554432, 67108864};
+ static const unsigned int ramp_base[] = {
+ 524288, 1048576, 2097152, 4194304,
+ 8388608, 16777216, 33554432, 67108864
+ };
unsigned int delay;
hs_gain = twl4030_read(component, TWL4030_REG_HS_GAIN_SET);
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index c09c9ac51b3e..adaf886b0a9d 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -2099,6 +2099,9 @@ static int wm5102_probe(struct platform_device *pdev)
regmap_update_bits(arizona->regmap, wm5102_digital_vu[i],
WM5102_DIG_VU, WM5102_DIG_VU);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_idle(&pdev->dev);
+
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
"ADSP2 Compressed IRQ", wm5102_adsp2_irq,
wm5102);
@@ -2131,9 +2134,6 @@ static int wm5102_probe(struct platform_device *pdev)
goto err_spk_irqs;
}
- pm_runtime_enable(&pdev->dev);
- pm_runtime_idle(&pdev->dev);
-
return ret;
err_spk_irqs:
@@ -2142,6 +2142,7 @@ err_dsp_irq:
arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102);
err_jack_codec_dev:
+ pm_runtime_disable(&pdev->dev);
arizona_jack_codec_dev_remove(&wm5102->core);
return ret;
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index fc634c995834..e0b971620d0f 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -2457,6 +2457,9 @@ static int wm5110_probe(struct platform_device *pdev)
regmap_update_bits(arizona->regmap, wm5110_digital_vu[i],
WM5110_DIG_VU, WM5110_DIG_VU);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_idle(&pdev->dev);
+
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
"ADSP2 Compressed IRQ", wm5110_adsp2_irq,
wm5110);
@@ -2489,9 +2492,6 @@ static int wm5110_probe(struct platform_device *pdev)
goto err_spk_irqs;
}
- pm_runtime_enable(&pdev->dev);
- pm_runtime_idle(&pdev->dev);
-
return ret;
err_spk_irqs:
@@ -2500,6 +2500,7 @@ err_dsp_irq:
arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110);
err_jack_codec_dev:
+ pm_runtime_disable(&pdev->dev);
arizona_jack_codec_dev_remove(&wm5110->core);
return ret;
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 7dc6aaf65576..a4857024711d 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -971,9 +971,16 @@ static const struct i2c_device_id wm8961_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id);
+static const struct of_device_id wm8961_of_match[] __maybe_unused = {
+ { .compatible = "wlf,wm8961", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8961_of_match);
+
static struct i2c_driver wm8961_i2c_driver = {
.driver = {
.name = "wm8961",
+ .of_match_table = of_match_ptr(wm8961_of_match),
},
.probe_new = wm8961_i2c_probe,
.id_table = wm8961_i2c_id,
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 81049664387e..b4b4355c6728 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -1840,6 +1840,49 @@ SOC_SINGLE_TLV("SPKOUTR Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
4, 1, 0, inmix_tlv),
};
+static int tp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ int ret, reg, val, mask;
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret < 0) {
+ dev_err(component->dev, "Failed to resume device: %d\n", ret);
+ return ret;
+ }
+
+ reg = WM8962_ADDITIONAL_CONTROL_4;
+
+ if (!strcmp(w->name, "TEMP_HP")) {
+ mask = WM8962_TEMP_ENA_HP_MASK;
+ val = WM8962_TEMP_ENA_HP;
+ } else if (!strcmp(w->name, "TEMP_SPK")) {
+ mask = WM8962_TEMP_ENA_SPK_MASK;
+ val = WM8962_TEMP_ENA_SPK;
+ } else {
+ pm_runtime_put(component->dev);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMD:
+ val = 0;
+ fallthrough;
+ case SND_SOC_DAPM_POST_PMU:
+ ret = snd_soc_component_update_bits(component, reg, mask, val);
+ break;
+ default:
+ WARN(1, "Invalid event %d\n", event);
+ pm_runtime_put(component->dev);
+ return -EINVAL;
+ }
+
+ pm_runtime_put(component->dev);
+
+ return 0;
+}
+
static int cp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -2140,8 +2183,10 @@ SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DSP2", 1, WM8962_DSP2_POWER_MANAGEMENT,
WM8962_DSP2_ENA_SHIFT, 0, dsp2_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-SND_SOC_DAPM_SUPPLY("TEMP_HP", WM8962_ADDITIONAL_CONTROL_4, 2, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY("TEMP_SPK", WM8962_ADDITIONAL_CONTROL_4, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TEMP_HP", SND_SOC_NOPM, 0, 0, tp_event,
+ SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("TEMP_SPK", SND_SOC_NOPM, 0, 0, tp_event,
+ SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MIXER("INPGAL", WM8962_LEFT_INPUT_PGA_CONTROL, 4, 0,
inpgal, ARRAY_SIZE(inpgal)),
@@ -3763,6 +3808,11 @@ static int wm8962_i2c_probe(struct i2c_client *i2c)
if (ret < 0)
goto err_pm_runtime;
+ regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4,
+ WM8962_TEMP_ENA_HP_MASK, 0);
+ regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4,
+ WM8962_TEMP_ENA_SPK_MASK, 0);
+
regcache_cache_only(wm8962->regmap, true);
/* The drivers should power up as needed */
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index a682f8020eb6..aa2f55401a88 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -498,7 +498,7 @@ static int wm8978_configure_pll(struct snd_soc_component *component)
if (4 * f_opclk < 3 * f_mclk)
/* Have to use OPCLKDIV */
- opclk_div = (3 * f_mclk / 4 + f_opclk - 1) / f_opclk;
+ opclk_div = DIV_ROUND_UP(3 * f_mclk / 4, f_opclk);
else
opclk_div = 1;
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index 77136a521605..c0207e9a7d53 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -1161,6 +1161,9 @@ static int wm8997_probe(struct platform_device *pdev)
regmap_update_bits(arizona->regmap, wm8997_digital_vu[i],
WM8997_DIG_VU, WM8997_DIG_VU);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_idle(&pdev->dev);
+
arizona_init_common(arizona);
ret = arizona_init_vol_limit(arizona);
@@ -1179,14 +1182,12 @@ static int wm8997_probe(struct platform_device *pdev)
goto err_spk_irqs;
}
- pm_runtime_enable(&pdev->dev);
- pm_runtime_idle(&pdev->dev);
-
return ret;
err_spk_irqs:
arizona_free_spk_irqs(arizona);
err_jack_codec_dev:
+ pm_runtime_disable(&pdev->dev);
arizona_jack_codec_dev_remove(&wm8997->core);
return ret;
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 8a2e9771bb50..34a94b011518 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -1035,6 +1035,16 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
}
EXPORT_SYMBOL_GPL(wm_adsp_early_event);
+static int wm_adsp_pre_run(struct cs_dsp *cs_dsp)
+{
+ struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
+
+ if (!dsp->pre_run)
+ return 0;
+
+ return (*dsp->pre_run)(dsp);
+}
+
static int wm_adsp_event_post_run(struct cs_dsp *cs_dsp)
{
struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
@@ -2043,6 +2053,7 @@ static const struct cs_dsp_client_ops wm_adsp1_client_ops = {
static const struct cs_dsp_client_ops wm_adsp2_client_ops = {
.control_add = wm_adsp_control_add,
.control_remove = wm_adsp_control_remove,
+ .pre_run = wm_adsp_pre_run,
.post_run = wm_adsp_event_post_run,
.post_stop = wm_adsp_event_post_stop,
.watchdog_expired = wm_adsp_fatal_error,
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 375009a65828..dc2f7a096e26 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -36,6 +36,7 @@ struct wm_adsp {
int fw;
struct work_struct boot_work;
+ int (*pre_run)(struct wm_adsp *dsp);
bool preloaded;
bool fatal_error;
diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
index c7b10bbfba7e..966ba4909204 100644
--- a/sound/soc/codecs/wsa883x.c
+++ b/sound/soc/codecs/wsa883x.c
@@ -7,7 +7,7 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -1380,22 +1380,19 @@ static int wsa883x_probe(struct sdw_slave *pdev,
return -ENOMEM;
wsa883x->vdd = devm_regulator_get(dev, "vdd");
- if (IS_ERR(wsa883x->vdd)) {
- dev_err(dev, "No vdd regulator found\n");
- return PTR_ERR(wsa883x->vdd);
- }
+ if (IS_ERR(wsa883x->vdd))
+ return dev_err_probe(dev, PTR_ERR(wsa883x->vdd),
+ "No vdd regulator found\n");
ret = regulator_enable(wsa883x->vdd);
- if (ret) {
- dev_err(dev, "Failed to enable vdd regulator (%d)\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable vdd regulator\n");
wsa883x->sd_n = devm_gpiod_get_optional(&pdev->dev, "powerdown",
- GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+ GPIOD_FLAGS_BIT_NONEXCLUSIVE | GPIOD_OUT_HIGH);
if (IS_ERR(wsa883x->sd_n)) {
- dev_err(&pdev->dev, "Shutdown Control GPIO not found\n");
- ret = PTR_ERR(wsa883x->sd_n);
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(wsa883x->sd_n),
+ "Shutdown Control GPIO not found\n");
goto err;
}
@@ -1411,12 +1408,13 @@ static int wsa883x_probe(struct sdw_slave *pdev,
pdev->prop.simple_clk_stop_capable = true;
pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop;
pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
- gpiod_direction_output(wsa883x->sd_n, 1);
+ gpiod_direction_output(wsa883x->sd_n, 0);
wsa883x->regmap = devm_regmap_init_sdw(pdev, &wsa883x_regmap_config);
if (IS_ERR(wsa883x->regmap)) {
- dev_err(&pdev->dev, "regmap_init failed\n");
- ret = PTR_ERR(wsa883x->regmap);
+ gpiod_direction_output(wsa883x->sd_n, 1);
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(wsa883x->regmap),
+ "regmap_init failed\n");
goto err;
}
pm_runtime_set_autosuspend_delay(dev, 3000);