summaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/Kconfig44
-rw-r--r--sound/soc/codecs/Makefile12
-rw-r--r--sound/soc/codecs/ak4458.c57
-rw-r--r--sound/soc/codecs/cs42l42-i2c.c104
-rw-r--r--sound/soc/codecs/cs42l42.c284
-rw-r--r--sound/soc/codecs/cs42l42.h37
-rw-r--r--sound/soc/codecs/cs42l83-i2c.c240
-rw-r--r--sound/soc/codecs/cs43130.c11
-rw-r--r--sound/soc/codecs/da7219.c5
-rw-r--r--sound/soc/codecs/es8316.c24
-rwxr-xr-xsound/soc/codecs/es8326.c905
-rwxr-xr-xsound/soc/codecs/es8326.h182
-rw-r--r--sound/soc/codecs/hda.c3
-rw-r--r--sound/soc/codecs/hdac_hda.c29
-rw-r--r--sound/soc/codecs/hdac_hda.h2
-rw-r--r--sound/soc/codecs/hdmi-codec.c14
-rw-r--r--sound/soc/codecs/lpass-rx-macro.c18
-rw-r--r--sound/soc/codecs/lpass-tx-macro.c36
-rw-r--r--sound/soc/codecs/lpass-va-macro.c82
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.c19
-rw-r--r--sound/soc/codecs/max98088.c7
-rw-r--r--sound/soc/codecs/max98373-sdw.c2
-rw-r--r--sound/soc/codecs/max98390.c80
-rw-r--r--sound/soc/codecs/max98396.c102
-rw-r--r--sound/soc/codecs/max98396.h14
-rw-r--r--sound/soc/codecs/mt6359-accdet.c6
-rw-r--r--sound/soc/codecs/mt6660.c8
-rw-r--r--sound/soc/codecs/nau8825.c103
-rw-r--r--sound/soc/codecs/nau8825.h17
-rw-r--r--sound/soc/codecs/rt1308-sdw.c2
-rw-r--r--sound/soc/codecs/rt1316-sdw.c2
-rw-r--r--sound/soc/codecs/rt5682-sdw.c2
-rw-r--r--sound/soc/codecs/rt5682s.c265
-rw-r--r--sound/soc/codecs/rt5682s.h2
-rw-r--r--sound/soc/codecs/rt700-sdw.c2
-rw-r--r--sound/soc/codecs/rt711-sdca-sdw.c2
-rw-r--r--sound/soc/codecs/rt715-sdca-sdw.c2
-rw-r--r--sound/soc/codecs/rt715-sdw.c2
-rw-r--r--sound/soc/codecs/sigmadsp.c4
-rw-r--r--sound/soc/codecs/src4xxx-i2c.c47
-rw-r--r--sound/soc/codecs/src4xxx.c518
-rw-r--r--sound/soc/codecs/src4xxx.h113
-rw-r--r--sound/soc/codecs/ssm2518.c34
-rw-r--r--sound/soc/codecs/sti-sas.c10
-rw-r--r--sound/soc/codecs/tas2562.c94
-rw-r--r--sound/soc/codecs/tas2764.c181
-rw-r--r--sound/soc/codecs/tas2764.h23
-rw-r--r--sound/soc/codecs/tfa989x.c4
-rw-r--r--sound/soc/codecs/tlv320adcx140.c59
-rw-r--r--sound/soc/codecs/tlv320adcx140.h3
-rw-r--r--sound/soc/codecs/tlv320aic26.c2
-rw-r--r--sound/soc/codecs/ts3a227e.c61
-rw-r--r--sound/soc/codecs/uda134x.c2
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.c12
-rw-r--r--sound/soc/codecs/wcd9335.c16
-rw-r--r--sound/soc/codecs/wcd934x.c2
-rw-r--r--sound/soc/codecs/wcd938x.c1
-rw-r--r--sound/soc/codecs/wm5102.c6
-rw-r--r--sound/soc/codecs/wm5110.c6
-rw-r--r--sound/soc/codecs/wm8997.c6
-rw-r--r--sound/soc/codecs/wm_adsp.c4
-rw-r--r--sound/soc/codecs/wsa883x.c28
62 files changed, 3318 insertions, 646 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index d16b4efb88a7..e3b90c425faf 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -98,6 +98,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_DA9055
imply SND_SOC_DMIC
imply SND_SOC_ES8316
+ imply SND_SOC_ES8326
imply SND_SOC_ES8328_SPI
imply SND_SOC_ES8328_I2C
imply SND_SOC_ES7134
@@ -205,6 +206,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_SIMPLE_AMPLIFIER
imply SND_SOC_SIMPLE_MUX
imply SND_SOC_SPDIF
+ imply SND_SOC_SRC4XXX_I2C
imply SND_SOC_SSM2305
imply SND_SOC_SSM2518
imply SND_SOC_SSM2602_SPI
@@ -608,7 +610,7 @@ config SND_SOC_BT_SCO
config SND_SOC_CPCAP
tristate "Motorola CPCAP codec"
- depends on MFD_CPCAP
+ depends on MFD_CPCAP || COMPILE_TEST
config SND_SOC_CQ0093VC
tristate
@@ -690,9 +692,15 @@ config SND_SOC_CS35L45_I2C
Enable support for Cirrus Logic CS35L45 smart speaker amplifier
with I2C control.
+config SND_SOC_CS42L42_CORE
+ tristate
+
config SND_SOC_CS42L42
- tristate "Cirrus Logic CS42L42 CODEC"
+ tristate "Cirrus Logic CS42L42 CODEC (I2C)"
depends on I2C
+ select REGMAP
+ select REGMAP_I2C
+ select SND_SOC_CS42L42_CORE
config SND_SOC_CS42L51
tristate
@@ -714,6 +722,13 @@ config SND_SOC_CS42L73
tristate "Cirrus Logic CS42L73 CODEC"
depends on I2C
+config SND_SOC_CS42L83
+ tristate "Cirrus Logic CS42L83 CODEC"
+ depends on I2C
+ select REGMAP
+ select REGMAP_I2C
+ select SND_SOC_CS42L42_CORE
+
config SND_SOC_CS4234
tristate "Cirrus Logic CS4234 CODEC"
depends on I2C
@@ -913,6 +928,10 @@ config SND_SOC_ES8316
tristate "Everest Semi ES8316 CODEC"
depends on I2C
+config SND_SOC_ES8326
+ tristate "Everest Semi ES8326 CODEC"
+ depends on I2C
+
config SND_SOC_ES8328
tristate
@@ -966,7 +985,7 @@ config SND_SOC_LM49453
config SND_SOC_LOCHNAGAR_SC
tristate "Lochnagar Sound Card"
- depends on MFD_LOCHNAGAR
+ depends on MFD_LOCHNAGAR || COMPILE_TEST
help
This driver support the sound card functionality of the Cirrus
Logic Lochnagar audio development board.
@@ -1191,8 +1210,7 @@ config SND_SOC_RK3328
config SND_SOC_RK817
tristate "Rockchip RK817 audio CODEC"
- depends on MFD_RK808
- select REGMAP_I2C
+ depends on MFD_RK808 || COMPILE_TEST
config SND_SOC_RL6231
tristate
@@ -1471,6 +1489,18 @@ config SND_SOC_SIMPLE_MUX
config SND_SOC_SPDIF
tristate "S/PDIF CODEC"
+config SND_SOC_SRC4XXX_I2C
+ tristate "Texas Instruments SRC4XXX DIR/DIT and SRC codecs"
+ depends on I2C
+ select SND_SOC_SRC4XXX
+ help
+ Enable support for the TI SRC4XXX family of codecs. These include the
+ scr4392 which has digital receivers, transmitters, and
+ a sample rate converter, including numerous ports.
+
+config SND_SOC_SRC4XXX
+ tristate
+
config SND_SOC_SSM2305
tristate "Analog Devices SSM2305 Class-D Amplifier"
help
@@ -1726,8 +1756,10 @@ config SND_SOC_WCD_MBHC
config SND_SOC_WCD934X
tristate "WCD9340/WCD9341 Codec"
depends on COMMON_CLK
+ depends on SLIMBUS
+ select REGMAP_SLIMBUS
select SND_SOC_WCD_MBHC
- depends on MFD_WCD934X
+ depends on MFD_WCD934X || COMPILE_TEST
help
The WCD9340/9341 is a audio codec IC Integrated in
Qualcomm SoCs like SDM845.
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 92fd441d426a..9170ee1447dd 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -65,11 +65,13 @@ snd-soc-cs35l45-objs := cs35l45.o
snd-soc-cs35l45-spi-objs := cs35l45-spi.o
snd-soc-cs35l45-i2c-objs := cs35l45-i2c.o
snd-soc-cs42l42-objs := cs42l42.o
+snd-soc-cs42l42-i2c-objs := cs42l42-i2c.o
snd-soc-cs42l51-objs := cs42l51.o
snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
snd-soc-cs42l52-objs := cs42l52.o
snd-soc-cs42l56-objs := cs42l56.o
snd-soc-cs42l73-objs := cs42l73.o
+snd-soc-cs42l83-i2c-objs := cs42l83-i2c.o
snd-soc-cs4234-objs := cs4234.o
snd-soc-cs4265-objs := cs4265.o
snd-soc-cs4270-objs := cs4270.o
@@ -100,6 +102,7 @@ snd-soc-dmic-objs := dmic.o
snd-soc-es7134-objs := es7134.o
snd-soc-es7241-objs := es7241.o
snd-soc-es8316-objs := es8316.o
+snd-soc-es8326-objs := es8326.o
snd-soc-es8328-objs := es8328.o
snd-soc-es8328-i2c-objs := es8328-i2c.o
snd-soc-es8328-spi-objs := es8328-spi.o
@@ -231,6 +234,8 @@ snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o
snd-soc-si476x-objs := si476x.o
snd-soc-spdif-tx-objs := spdif_transmitter.o
snd-soc-spdif-rx-objs := spdif_receiver.o
+snd-soc-src4xxx-objs := src4xxx.o
+snd-soc-src4xxx-i2c-objs := src4xxx-i2c.o
snd-soc-ssm2305-objs := ssm2305.o
snd-soc-ssm2518-objs := ssm2518.o
snd-soc-ssm2602-objs := ssm2602.o
@@ -419,12 +424,14 @@ obj-$(CONFIG_SND_SOC_CS35L45_TABLES) += snd-soc-cs35l45-tables.o
obj-$(CONFIG_SND_SOC_CS35L45) += snd-soc-cs35l45.o
obj-$(CONFIG_SND_SOC_CS35L45_SPI) += snd-soc-cs35l45-spi.o
obj-$(CONFIG_SND_SOC_CS35L45_I2C) += snd-soc-cs35l45-i2c.o
-obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o
+obj-$(CONFIG_SND_SOC_CS42L42_CORE) += snd-soc-cs42l42.o
+obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42-i2c.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o
obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o
obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o
+obj-$(CONFIG_SND_SOC_CS42L83) += snd-soc-cs42l83-i2c.o
obj-$(CONFIG_SND_SOC_CS4234) += snd-soc-cs4234.o
obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
@@ -455,6 +462,7 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
obj-$(CONFIG_SND_SOC_ES7134) += snd-soc-es7134.o
obj-$(CONFIG_SND_SOC_ES7241) += snd-soc-es7241.o
obj-$(CONFIG_SND_SOC_ES8316) += snd-soc-es8316.o
+obj-$(CONFIG_SND_SOC_ES8326) += snd-soc-es8326.o
obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o
obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
@@ -579,6 +587,8 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o
obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o
obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
+obj-$(CONFIG_SND_SOC_SRC4XXX) += snd-soc-src4xxx.o
+obj-$(CONFIG_SND_SOC_SRC4XXX_I2C) += snd-soc-src4xxx-i2c.o
obj-$(CONFIG_SND_SOC_SSM2305) += snd-soc-ssm2305.o
obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index f2d519eb1eec..1db73552c746 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -447,6 +447,13 @@ static int ak4458_hw_params(struct snd_pcm_substream *substream,
snd_soc_component_update_bits(component, AK4458_0B_CONTROL7,
AK4458_DCHAIN_MASK, dchn);
+ if (ak4458->drvdata->type == AK4497) {
+ ret = snd_soc_component_update_bits(component, AK4458_09_DSD2,
+ 0x4, (ak4458->dsd_path << 2));
+ if (ret < 0)
+ return ret;
+ }
+
ret = ak4458_rstn_control(component, 0);
if (ret)
return ret;
@@ -629,48 +636,6 @@ static void ak4458_reset(struct ak4458_priv *ak4458, bool active)
}
}
-static int ak4458_init(struct snd_soc_component *component)
-{
- struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
- int ret;
-
- /* External Mute ON */
- if (ak4458->mute_gpiod)
- gpiod_set_value_cansleep(ak4458->mute_gpiod, 1);
-
- ak4458_reset(ak4458, false);
-
- ret = snd_soc_component_update_bits(component, AK4458_00_CONTROL1,
- 0x80, 0x80); /* ACKS bit = 1; 10000000 */
- if (ret < 0)
- return ret;
-
- if (ak4458->drvdata->type == AK4497) {
- ret = snd_soc_component_update_bits(component, AK4458_09_DSD2,
- 0x4, (ak4458->dsd_path << 2));
- if (ret < 0)
- return ret;
- }
-
- return ak4458_rstn_control(component, 1);
-}
-
-static int ak4458_probe(struct snd_soc_component *component)
-{
- struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
-
- ak4458->fs = 48000;
-
- return ak4458_init(component);
-}
-
-static void ak4458_remove(struct snd_soc_component *component)
-{
- struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
-
- ak4458_reset(ak4458, true);
-}
-
#ifdef CONFIG_PM
static int __maybe_unused ak4458_runtime_suspend(struct device *dev)
{
@@ -714,8 +679,6 @@ static int __maybe_unused ak4458_runtime_resume(struct device *dev)
#endif /* CONFIG_PM */
static const struct snd_soc_component_driver soc_codec_dev_ak4458 = {
- .probe = ak4458_probe,
- .remove = ak4458_remove,
.controls = ak4458_snd_controls,
.num_controls = ARRAY_SIZE(ak4458_snd_controls),
.dapm_widgets = ak4458_dapm_widgets,
@@ -728,8 +691,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak4458 = {
};
static const struct snd_soc_component_driver soc_codec_dev_ak4497 = {
- .probe = ak4458_probe,
- .remove = ak4458_remove,
.controls = ak4497_snd_controls,
.num_controls = ARRAY_SIZE(ak4497_snd_controls),
.dapm_widgets = ak4497_dapm_widgets,
@@ -820,12 +781,16 @@ static int ak4458_i2c_probe(struct i2c_client *i2c)
pm_runtime_enable(&i2c->dev);
regcache_cache_only(ak4458->regmap, true);
+ ak4458_reset(ak4458, false);
return 0;
}
static void ak4458_i2c_remove(struct i2c_client *i2c)
{
+ struct ak4458_priv *ak4458 = i2c_get_clientdata(i2c);
+
+ ak4458_reset(ak4458, true);
pm_runtime_disable(&i2c->dev);
}
diff --git a/sound/soc/codecs/cs42l42-i2c.c b/sound/soc/codecs/cs42l42-i2c.c
new file mode 100644
index 000000000000..67b253287daf
--- /dev/null
+++ b/sound/soc/codecs/cs42l42-i2c.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * cs42l42-i2c.c -- CS42L42 ALSA SoC audio driver for I2C
+ *
+ * Copyright 2016, 2022 Cirrus Logic, Inc.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "cs42l42.h"
+
+static int cs42l42_i2c_probe(struct i2c_client *i2c_client)
+{
+ struct device *dev = &i2c_client->dev;
+ struct cs42l42_private *cs42l42;
+ struct regmap *regmap;
+ int ret;
+
+ cs42l42 = devm_kzalloc(dev, sizeof(*cs42l42), GFP_KERNEL);
+ if (!cs42l42)
+ return -ENOMEM;
+
+ regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&i2c_client->dev, PTR_ERR(regmap),
+ "regmap_init() failed\n");
+
+ cs42l42->devid = CS42L42_CHIP_ID;
+ cs42l42->dev = dev;
+ cs42l42->regmap = regmap;
+ cs42l42->irq = i2c_client->irq;
+
+ ret = cs42l42_common_probe(cs42l42, &cs42l42_soc_component, &cs42l42_dai);
+ if (ret)
+ return ret;
+
+ return cs42l42_init(cs42l42);
+}
+
+static void cs42l42_i2c_remove(struct i2c_client *i2c_client)
+{
+ struct cs42l42_private *cs42l42 = dev_get_drvdata(&i2c_client->dev);
+
+ cs42l42_common_remove(cs42l42);
+}
+
+static int __maybe_unused cs42l42_i2c_resume(struct device *dev)
+{
+ int ret;
+
+ ret = cs42l42_resume(dev);
+ if (ret)
+ return ret;
+
+ cs42l42_resume_restore(dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops cs42l42_i2c_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_i2c_resume)
+};
+
+static const struct of_device_id __maybe_unused cs42l42_of_match[] = {
+ { .compatible = "cirrus,cs42l42", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cs42l42_of_match);
+
+static const struct acpi_device_id __maybe_unused cs42l42_acpi_match[] = {
+ {"10134242", 0,},
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, cs42l42_acpi_match);
+
+static const struct i2c_device_id cs42l42_id[] = {
+ {"cs42l42", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs42l42_id);
+
+static struct i2c_driver cs42l42_i2c_driver = {
+ .driver = {
+ .name = "cs42l42",
+ .pm = &cs42l42_i2c_pm_ops,
+ .of_match_table = of_match_ptr(cs42l42_of_match),
+ .acpi_match_table = ACPI_PTR(cs42l42_acpi_match),
+ },
+ .id_table = cs42l42_id,
+ .probe_new = cs42l42_i2c_probe,
+ .remove = cs42l42_i2c_remove,
+};
+
+module_i2c_driver(cs42l42_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L42 I2C driver");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE);
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 53274ea84ebd..2fefbcf7bd13 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -12,10 +12,9 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
-#include <linux/kernel.h>
+#include <linux/types.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -37,6 +36,14 @@
#include "cs42l42.h"
#include "cirrus_legacy.h"
+static const char * const cs42l42_supply_names[] = {
+ "VA",
+ "VP",
+ "VCP",
+ "VD_FILT",
+ "VL",
+};
+
static const struct reg_default cs42l42_reg_defaults[] = {
{ CS42L42_FRZ_CTL, 0x00 },
{ CS42L42_SRC_CTL, 0x10 },
@@ -164,7 +171,7 @@ static const struct reg_default cs42l42_reg_defaults[] = {
{ CS42L42_ASP_RX_DAI1_CH2_BIT_LSB, 0x00 },
};
-static bool cs42l42_readable_register(struct device *dev, unsigned int reg)
+bool cs42l42_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case CS42L42_PAGE_REGISTER:
@@ -323,8 +330,9 @@ static bool cs42l42_readable_register(struct device *dev, unsigned int reg)
return false;
}
}
+EXPORT_SYMBOL_NS_GPL(cs42l42_readable_register, SND_SOC_CS42L42_CORE);
-static bool cs42l42_volatile_register(struct device *dev, unsigned int reg)
+bool cs42l42_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case CS42L42_DEVID_AB:
@@ -355,8 +363,9 @@ static bool cs42l42_volatile_register(struct device *dev, unsigned int reg)
return false;
}
}
+EXPORT_SYMBOL_NS_GPL(cs42l42_volatile_register, SND_SOC_CS42L42_CORE);
-static const struct regmap_range_cfg cs42l42_page_range = {
+const struct regmap_range_cfg cs42l42_page_range = {
.name = "Pages",
.range_min = 0,
.range_max = CS42L42_MAX_REGISTER,
@@ -366,8 +375,9 @@ static const struct regmap_range_cfg cs42l42_page_range = {
.window_start = 0,
.window_len = 256,
};
+EXPORT_SYMBOL_NS_GPL(cs42l42_page_range, SND_SOC_CS42L42_CORE);
-static const struct regmap_config cs42l42_regmap = {
+const struct regmap_config cs42l42_regmap = {
.reg_bits = 8,
.val_bits = 8,
@@ -385,6 +395,7 @@ static const struct regmap_config cs42l42_regmap = {
.use_single_read = true,
.use_single_write = true,
};
+EXPORT_SYMBOL_NS_GPL(cs42l42_regmap, SND_SOC_CS42L42_CORE);
static DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 100, true);
static DECLARE_TLV_DB_SCALE(mixer_tlv, -6300, 100, true);
@@ -395,7 +406,7 @@ static int cs42l42_slow_start_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
u8 val;
- /* all bits of SLOW_START_EN much change together */
+ /* all bits of SLOW_START_EN must change together */
switch (ucontrol->value.integer.value[0]) {
case 0:
val = 0;
@@ -571,7 +582,7 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_
return 0;
}
-static const struct snd_soc_component_driver soc_component_dev_cs42l42 = {
+const struct snd_soc_component_driver cs42l42_soc_component = {
.set_jack = cs42l42_set_jack,
.dapm_widgets = cs42l42_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(cs42l42_dapm_widgets),
@@ -582,6 +593,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l42 = {
.idle_bias_on = 1,
.endianness = 1,
};
+EXPORT_SYMBOL_NS_GPL(cs42l42_soc_component, SND_SOC_CS42L42_CORE);
/* Switch to SCLK. Atomic delay after the write to allow the switch to complete. */
static const struct reg_sequence cs42l42_to_sclk_seq[] = {
@@ -639,18 +651,12 @@ static const struct cs42l42_pll_params pll_ratio_table[] = {
{ 24576000, 1, 0x03, 0x40, 0x000000, 0x03, 0x10, 12288000, 128, 1}
};
-static int cs42l42_pll_config(struct snd_soc_component *component)
+static int cs42l42_pll_config(struct snd_soc_component *component, unsigned int clk)
{
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
int i;
- u32 clk;
u32 fsync;
- if (!cs42l42->sclk)
- clk = cs42l42->bclk;
- else
- clk = cs42l42->sclk;
-
/* Don't reconfigure if there is an audio stream running */
if (cs42l42->stream_use) {
if (pll_ratio_table[cs42l42->pll_config].sclk == clk)
@@ -885,22 +891,30 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
unsigned int channels = params_channels(params);
unsigned int width = (params_width(params) / 8) - 1;
+ unsigned int slot_width = 0;
unsigned int val = 0;
+ unsigned int bclk;
int ret;
cs42l42->srate = params_rate(params);
- cs42l42->bclk = snd_soc_params_to_bclk(params);
- /* I2S frame always has 2 channels even for mono audio */
- if (channels == 1)
- cs42l42->bclk *= 2;
+ if (cs42l42->bclk_ratio) {
+ /* machine driver has set the BCLK/samp-rate ratio */
+ bclk = cs42l42->bclk_ratio * params_rate(params);
+ } else if (cs42l42->sclk) {
+ /* machine driver has set the SCLK */
+ bclk = cs42l42->sclk;
+ } else {
+ /*
+ * Assume 24-bit samples are in 32-bit slots, to prevent SCLK being
+ * more than assumed (which would result in overclocking).
+ */
+ if (params_width(params) == 24)
+ slot_width = 32;
- /*
- * Assume 24-bit samples are in 32-bit slots, to prevent SCLK being
- * more than assumed (which would result in overclocking).
- */
- if (params_width(params) == 24)
- cs42l42->bclk = (cs42l42->bclk / 3) * 4;
+ /* I2S frame always has multiple of 2 channels */
+ bclk = snd_soc_tdm_params_to_bclk(params, slot_width, 0, 2);
+ }
switch (substream->stream) {
case SNDRV_PCM_STREAM_CAPTURE:
@@ -940,7 +954,7 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
break;
}
- ret = cs42l42_pll_config(component);
+ ret = cs42l42_pll_config(component, bclk);
if (ret)
return ret;
@@ -973,6 +987,17 @@ static int cs42l42_set_sysclk(struct snd_soc_dai *dai,
return -EINVAL;
}
+static int cs42l42_set_bclk_ratio(struct snd_soc_dai *dai,
+ unsigned int bclk_ratio)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
+
+ cs42l42->bclk_ratio = bclk_ratio;
+
+ return 0;
+}
+
static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
{
struct snd_soc_component *component = dai->component;
@@ -1076,10 +1101,11 @@ static const struct snd_soc_dai_ops cs42l42_ops = {
.hw_params = cs42l42_pcm_hw_params,
.set_fmt = cs42l42_set_dai_fmt,
.set_sysclk = cs42l42_set_sysclk,
+ .set_bclk_ratio = cs42l42_set_bclk_ratio,
.mute_stream = cs42l42_mute_stream,
};
-static struct snd_soc_dai_driver cs42l42_dai = {
+struct snd_soc_dai_driver cs42l42_dai = {
.name = "cs42l42",
.playback = {
.stream_name = "Playback",
@@ -1099,6 +1125,7 @@ static struct snd_soc_dai_driver cs42l42_dai = {
.symmetric_sample_bits = 1,
.ops = &cs42l42_ops,
};
+EXPORT_SYMBOL_NS_GPL(cs42l42_dai, SND_SOC_CS42L42_CORE);
static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42)
{
@@ -1172,14 +1199,11 @@ static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42)
cs42l42->hs_type = CS42L42_PLUG_OMTP;
hs_det_sw = CS42L42_HSDET_SW_TYPE2;
break;
- case CS42L42_HSDET_COMP_TYPE3:
+ /* Detect Type 3 and Type 4 Headsets as Headphones */
+ default:
cs42l42->hs_type = CS42L42_PLUG_HEADPHONE;
hs_det_sw = CS42L42_HSDET_SW_TYPE3;
break;
- default:
- cs42l42->hs_type = CS42L42_PLUG_INVALID;
- hs_det_sw = CS42L42_HSDET_SW_TYPE4;
- break;
}
}
@@ -1619,7 +1643,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
unsigned int i;
mutex_lock(&cs42l42->irq_lock);
- if (cs42l42->suspended) {
+ if (cs42l42->suspended || !cs42l42->init_done) {
mutex_unlock(&cs42l42->irq_lock);
return IRQ_NONE;
}
@@ -2094,7 +2118,7 @@ static const struct reg_sequence __maybe_unused cs42l42_shutdown_seq[] = {
REG_SEQ0(CS42L42_PWR_CTL1, 0xFF)
};
-static int __maybe_unused cs42l42_suspend(struct device *dev)
+int cs42l42_suspend(struct device *dev)
{
struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
unsigned int reg;
@@ -2154,8 +2178,9 @@ static int __maybe_unused cs42l42_suspend(struct device *dev)
return 0;
}
+EXPORT_SYMBOL_NS_GPL(cs42l42_suspend, SND_SOC_CS42L42_CORE);
-static int __maybe_unused cs42l42_resume(struct device *dev)
+int cs42l42_resume(struct device *dev)
{
struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
int ret;
@@ -2177,6 +2202,16 @@ static int __maybe_unused cs42l42_resume(struct device *dev)
gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);
+ dev_dbg(dev, "System resume powered up\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs42l42_resume, SND_SOC_CS42L42_CORE);
+
+void cs42l42_resume_restore(struct device *dev)
+{
+ struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
+
regcache_cache_only(cs42l42->regmap, false);
regcache_mark_dirty(cs42l42->regmap);
@@ -2189,40 +2224,40 @@ static int __maybe_unused cs42l42_resume(struct device *dev)
mutex_unlock(&cs42l42->irq_lock);
dev_dbg(dev, "System resumed\n");
+}
+EXPORT_SYMBOL_NS_GPL(cs42l42_resume_restore, SND_SOC_CS42L42_CORE);
+
+static int __maybe_unused cs42l42_i2c_resume(struct device *dev)
+{
+ int ret;
+
+ ret = cs42l42_resume(dev);
+ if (ret)
+ return ret;
+
+ cs42l42_resume_restore(dev);
return 0;
}
-static int cs42l42_i2c_probe(struct i2c_client *i2c_client)
+int cs42l42_common_probe(struct cs42l42_private *cs42l42,
+ const struct snd_soc_component_driver *component_drv,
+ struct snd_soc_dai_driver *dai)
{
- struct cs42l42_private *cs42l42;
- int ret, i, devid;
- unsigned int reg;
-
- cs42l42 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l42_private),
- GFP_KERNEL);
- if (!cs42l42)
- return -ENOMEM;
+ int ret, i;
- cs42l42->dev = &i2c_client->dev;
- i2c_set_clientdata(i2c_client, cs42l42);
+ dev_set_drvdata(cs42l42->dev, cs42l42);
mutex_init(&cs42l42->irq_lock);
- cs42l42->regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap);
- if (IS_ERR(cs42l42->regmap)) {
- ret = PTR_ERR(cs42l42->regmap);
- dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
- return ret;
- }
-
+ BUILD_BUG_ON(ARRAY_SIZE(cs42l42_supply_names) != ARRAY_SIZE(cs42l42->supplies));
for (i = 0; i < ARRAY_SIZE(cs42l42->supplies); i++)
cs42l42->supplies[i].supply = cs42l42_supply_names[i];
- ret = devm_regulator_bulk_get(&i2c_client->dev,
+ ret = devm_regulator_bulk_get(cs42l42->dev,
ARRAY_SIZE(cs42l42->supplies),
cs42l42->supplies);
if (ret != 0) {
- dev_err(&i2c_client->dev,
+ dev_err(cs42l42->dev,
"Failed to request supplies: %d\n", ret);
return ret;
}
@@ -2230,13 +2265,13 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client)
ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies),
cs42l42->supplies);
if (ret != 0) {
- dev_err(&i2c_client->dev,
+ dev_err(cs42l42->dev,
"Failed to enable supplies: %d\n", ret);
return ret;
}
/* Reset the Device */
- cs42l42->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+ cs42l42->reset_gpio = devm_gpiod_get_optional(cs42l42->dev,
"reset", GPIOD_OUT_LOW);
if (IS_ERR(cs42l42->reset_gpio)) {
ret = PTR_ERR(cs42l42->reset_gpio);
@@ -2244,50 +2279,74 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client)
}
if (cs42l42->reset_gpio) {
- dev_dbg(&i2c_client->dev, "Found reset GPIO\n");
+ dev_dbg(cs42l42->dev, "Found reset GPIO\n");
gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
}
usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);
/* Request IRQ if one was specified */
- if (i2c_client->irq) {
- ret = request_threaded_irq(i2c_client->irq,
+ if (cs42l42->irq) {
+ ret = request_threaded_irq(cs42l42->irq,
NULL, cs42l42_irq_thread,
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
"cs42l42", cs42l42);
- if (ret == -EPROBE_DEFER) {
- goto err_disable_noirq;
- } else if (ret != 0) {
- dev_err(&i2c_client->dev,
- "Failed to request IRQ: %d\n", ret);
+ if (ret) {
+ dev_err_probe(cs42l42->dev, ret,
+ "Failed to request IRQ\n");
goto err_disable_noirq;
}
}
+ /* Register codec now so it can EPROBE_DEFER */
+ ret = devm_snd_soc_register_component(cs42l42->dev, component_drv, dai, 1);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ if (cs42l42->irq)
+ free_irq(cs42l42->irq, cs42l42);
+
+err_disable_noirq:
+ gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
+err_disable_noreset:
+ regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs42l42_common_probe, SND_SOC_CS42L42_CORE);
+
+int cs42l42_init(struct cs42l42_private *cs42l42)
+{
+ unsigned int reg;
+ int devid, ret;
+
/* initialize codec */
devid = cirrus_read_device_id(cs42l42->regmap, CS42L42_DEVID_AB);
if (devid < 0) {
ret = devid;
- dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret);
+ dev_err(cs42l42->dev, "Failed to read device ID: %d\n", ret);
goto err_disable;
}
- if (devid != CS42L42_CHIP_ID) {
+ if (devid != cs42l42->devid) {
ret = -ENODEV;
- dev_err(&i2c_client->dev,
- "CS42L42 Device ID (%X). Expected %X\n",
- devid, CS42L42_CHIP_ID);
+ dev_err(cs42l42->dev,
+ "CS42L%x Device ID (%X). Expected %X\n",
+ cs42l42->devid & 0xff, devid, cs42l42->devid);
goto err_disable;
}
ret = regmap_read(cs42l42->regmap, CS42L42_REVID, &reg);
if (ret < 0) {
- dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+ dev_err(cs42l42->dev, "Get Revision ID failed\n");
goto err_shutdown;
}
- dev_info(&i2c_client->dev,
- "Cirrus Logic CS42L42, Revision: %02X\n", reg & 0xFF);
+ dev_info(cs42l42->dev,
+ "Cirrus Logic CS42L%x, Revision: %02X\n",
+ cs42l42->devid & 0xff, reg & 0xFF);
/* Power up the codec */
regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL1,
@@ -2306,22 +2365,22 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client)
(1 << CS42L42_ADC_PDN_SHIFT) |
(0 << CS42L42_PDN_ALL_SHIFT));
- ret = cs42l42_handle_device_data(&i2c_client->dev, cs42l42);
+ ret = cs42l42_handle_device_data(cs42l42->dev, cs42l42);
if (ret != 0)
goto err_shutdown;
/* Setup headset detection */
cs42l42_setup_hs_type_detect(cs42l42);
+ /*
+ * Set init_done before unmasking interrupts so any triggered
+ * immediately will be handled.
+ */
+ cs42l42->init_done = true;
+
/* Mask/Unmask Interrupts */
cs42l42_set_interrupt_masks(cs42l42);
- /* Register codec for machine driver */
- ret = devm_snd_soc_register_component(&i2c_client->dev,
- &soc_component_dev_cs42l42, &cs42l42_dai, 1);
- if (ret < 0)
- goto err_shutdown;
-
return 0;
err_shutdown:
@@ -2330,76 +2389,35 @@ err_shutdown:
regmap_write(cs42l42->regmap, CS42L42_PWR_CTL1, 0xff);
err_disable:
- if (i2c_client->irq)
- free_irq(i2c_client->irq, cs42l42);
+ if (cs42l42->irq)
+ free_irq(cs42l42->irq, cs42l42);
-err_disable_noirq:
gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
-err_disable_noreset:
regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies),
cs42l42->supplies);
return ret;
}
+EXPORT_SYMBOL_NS_GPL(cs42l42_init, SND_SOC_CS42L42_CORE);
-static void cs42l42_i2c_remove(struct i2c_client *i2c_client)
+void cs42l42_common_remove(struct cs42l42_private *cs42l42)
{
- struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client);
-
- if (i2c_client->irq)
- free_irq(i2c_client->irq, cs42l42);
+ if (cs42l42->irq)
+ free_irq(cs42l42->irq, cs42l42);
/*
* The driver might not have control of reset and power supplies,
* so ensure that the chip internals are powered down.
*/
- regmap_write(cs42l42->regmap, CS42L42_CODEC_INT_MASK, 0xff);
- regmap_write(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, 0xff);
- regmap_write(cs42l42->regmap, CS42L42_PWR_CTL1, 0xff);
+ if (cs42l42->init_done) {
+ regmap_write(cs42l42->regmap, CS42L42_CODEC_INT_MASK, 0xff);
+ regmap_write(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, 0xff);
+ regmap_write(cs42l42->regmap, CS42L42_PWR_CTL1, 0xff);
+ }
gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies);
}
-
-static const struct dev_pm_ops cs42l42_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_resume)
-};
-
-#ifdef CONFIG_OF
-static const struct of_device_id cs42l42_of_match[] = {
- { .compatible = "cirrus,cs42l42", },
- {}
-};
-MODULE_DEVICE_TABLE(of, cs42l42_of_match);
-#endif
-
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id cs42l42_acpi_match[] = {
- {"10134242", 0,},
- {}
-};
-MODULE_DEVICE_TABLE(acpi, cs42l42_acpi_match);
-#endif
-
-static const struct i2c_device_id cs42l42_id[] = {
- {"cs42l42", 0},
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, cs42l42_id);
-
-static struct i2c_driver cs42l42_i2c_driver = {
- .driver = {
- .name = "cs42l42",
- .pm = &cs42l42_pm_ops,
- .of_match_table = of_match_ptr(cs42l42_of_match),
- .acpi_match_table = ACPI_PTR(cs42l42_acpi_match),
- },
- .id_table = cs42l42_id,
- .probe_new = cs42l42_i2c_probe,
- .remove = cs42l42_i2c_remove,
-};
-
-module_i2c_driver(cs42l42_i2c_driver);
+EXPORT_SYMBOL_NS_GPL(cs42l42_common_remove, SND_SOC_CS42L42_CORE);
MODULE_DESCRIPTION("ASoC CS42L42 driver");
MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h
index 5f50970375d4..a72136664112 100644
--- a/sound/soc/codecs/cs42l42.h
+++ b/sound/soc/codecs/cs42l42.h
@@ -12,17 +12,16 @@
#ifndef __CS42L42_H__
#define __CS42L42_H__
+#include <dt-bindings/sound/cs42l42.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <sound/jack.h>
#include <sound/cs42l42.h>
-
-static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = {
- "VA",
- "VP",
- "VCP",
- "VD_FILT",
- "VL",
-};
+#include <sound/soc-component.h>
+#include <sound/soc-dai.h>
struct cs42l42_private {
struct regmap *regmap;
@@ -32,9 +31,11 @@ struct cs42l42_private {
struct completion pdn_done;
struct snd_soc_jack *jack;
struct mutex irq_lock;
+ int devid;
+ int irq;
int pll_config;
- int bclk;
u32 sclk;
+ u32 bclk_ratio;
u32 srate;
u8 plug_state;
u8 hs_type;
@@ -50,6 +51,24 @@ struct cs42l42_private {
u8 stream_use;
bool hp_adc_up_pending;
bool suspended;
+ bool init_done;
};
+extern const struct regmap_range_cfg cs42l42_page_range;
+extern const struct regmap_config cs42l42_regmap;
+extern const struct snd_soc_component_driver cs42l42_soc_component;
+extern struct snd_soc_dai_driver cs42l42_dai;
+
+bool cs42l42_readable_register(struct device *dev, unsigned int reg);
+bool cs42l42_volatile_register(struct device *dev, unsigned int reg);
+
+int cs42l42_suspend(struct device *dev);
+int cs42l42_resume(struct device *dev);
+void cs42l42_resume_restore(struct device *dev);
+int cs42l42_common_probe(struct cs42l42_private *cs42l42,
+ const struct snd_soc_component_driver *component_drv,
+ struct snd_soc_dai_driver *dai);
+int cs42l42_init(struct cs42l42_private *cs42l42);
+void cs42l42_common_remove(struct cs42l42_private *cs42l42);
+
#endif /* __CS42L42_H__ */
diff --git a/sound/soc/codecs/cs42l83-i2c.c b/sound/soc/codecs/cs42l83-i2c.c
new file mode 100644
index 000000000000..f90d43996a51
--- /dev/null
+++ b/sound/soc/codecs/cs42l83-i2c.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * cs42l83-i2c.c -- CS42L83 ALSA SoC audio driver for I2C
+ *
+ * Based on cs42l42-i2c.c:
+ * Copyright 2016, 2022 Cirrus Logic, Inc.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "cs42l42.h"
+
+static const struct reg_default cs42l83_reg_defaults[] = {
+ { CS42L42_FRZ_CTL, 0x00 },
+ { CS42L42_SRC_CTL, 0x10 },
+ { CS42L42_MCLK_CTL, 0x00 }, /* <- only deviation from CS42L42 */
+ { CS42L42_SFTRAMP_RATE, 0xA4 },
+ { CS42L42_SLOW_START_ENABLE, 0x70 },
+ { CS42L42_I2C_DEBOUNCE, 0x88 },
+ { CS42L42_I2C_STRETCH, 0x03 },
+ { CS42L42_I2C_TIMEOUT, 0xB7 },
+ { CS42L42_PWR_CTL1, 0xFF },
+ { CS42L42_PWR_CTL2, 0x84 },
+ { CS42L42_PWR_CTL3, 0x20 },
+ { CS42L42_RSENSE_CTL1, 0x40 },
+ { CS42L42_RSENSE_CTL2, 0x00 },
+ { CS42L42_OSC_SWITCH, 0x00 },
+ { CS42L42_RSENSE_CTL3, 0x1B },
+ { CS42L42_TSENSE_CTL, 0x1B },
+ { CS42L42_TSRS_INT_DISABLE, 0x00 },
+ { CS42L42_HSDET_CTL1, 0x77 },
+ { CS42L42_HSDET_CTL2, 0x00 },
+ { CS42L42_HS_SWITCH_CTL, 0xF3 },
+ { CS42L42_HS_CLAMP_DISABLE, 0x00 },
+ { CS42L42_MCLK_SRC_SEL, 0x00 },
+ { CS42L42_SPDIF_CLK_CFG, 0x00 },
+ { CS42L42_FSYNC_PW_LOWER, 0x00 },
+ { CS42L42_FSYNC_PW_UPPER, 0x00 },
+ { CS42L42_FSYNC_P_LOWER, 0xF9 },
+ { CS42L42_FSYNC_P_UPPER, 0x00 },
+ { CS42L42_ASP_CLK_CFG, 0x00 },
+ { CS42L42_ASP_FRM_CFG, 0x10 },
+ { CS42L42_FS_RATE_EN, 0x00 },
+ { CS42L42_IN_ASRC_CLK, 0x00 },
+ { CS42L42_OUT_ASRC_CLK, 0x00 },
+ { CS42L42_PLL_DIV_CFG1, 0x00 },
+ { CS42L42_ADC_OVFL_INT_MASK, 0x01 },
+ { CS42L42_MIXER_INT_MASK, 0x0F },
+ { CS42L42_SRC_INT_MASK, 0x0F },
+ { CS42L42_ASP_RX_INT_MASK, 0x1F },
+ { CS42L42_ASP_TX_INT_MASK, 0x0F },
+ { CS42L42_CODEC_INT_MASK, 0x03 },
+ { CS42L42_SRCPL_INT_MASK, 0x7F },
+ { CS42L42_VPMON_INT_MASK, 0x01 },
+ { CS42L42_PLL_LOCK_INT_MASK, 0x01 },
+ { CS42L42_TSRS_PLUG_INT_MASK, 0x0F },
+ { CS42L42_PLL_CTL1, 0x00 },
+ { CS42L42_PLL_DIV_FRAC0, 0x00 },
+ { CS42L42_PLL_DIV_FRAC1, 0x00 },
+ { CS42L42_PLL_DIV_FRAC2, 0x00 },
+ { CS42L42_PLL_DIV_INT, 0x40 },
+ { CS42L42_PLL_CTL3, 0x10 },
+ { CS42L42_PLL_CAL_RATIO, 0x80 },
+ { CS42L42_PLL_CTL4, 0x03 },
+ { CS42L42_LOAD_DET_EN, 0x00 },
+ { CS42L42_HSBIAS_SC_AUTOCTL, 0x03 },
+ { CS42L42_WAKE_CTL, 0xC0 },
+ { CS42L42_ADC_DISABLE_MUTE, 0x00 },
+ { CS42L42_TIPSENSE_CTL, 0x02 },
+ { CS42L42_MISC_DET_CTL, 0x03 },
+ { CS42L42_MIC_DET_CTL1, 0x1F },
+ { CS42L42_MIC_DET_CTL2, 0x2F },
+ { CS42L42_DET_INT1_MASK, 0xE0 },
+ { CS42L42_DET_INT2_MASK, 0xFF },
+ { CS42L42_HS_BIAS_CTL, 0xC2 },
+ { CS42L42_ADC_CTL, 0x00 },
+ { CS42L42_ADC_VOLUME, 0x00 },
+ { CS42L42_ADC_WNF_HPF_CTL, 0x71 },
+ { CS42L42_DAC_CTL1, 0x00 },
+ { CS42L42_DAC_CTL2, 0x02 },
+ { CS42L42_HP_CTL, 0x0D },
+ { CS42L42_CLASSH_CTL, 0x07 },
+ { CS42L42_MIXER_CHA_VOL, 0x3F },
+ { CS42L42_MIXER_ADC_VOL, 0x3F },
+ { CS42L42_MIXER_CHB_VOL, 0x3F },
+ { CS42L42_EQ_COEF_IN0, 0x00 },
+ { CS42L42_EQ_COEF_IN1, 0x00 },
+ { CS42L42_EQ_COEF_IN2, 0x00 },
+ { CS42L42_EQ_COEF_IN3, 0x00 },
+ { CS42L42_EQ_COEF_RW, 0x00 },
+ { CS42L42_EQ_COEF_OUT0, 0x00 },
+ { CS42L42_EQ_COEF_OUT1, 0x00 },
+ { CS42L42_EQ_COEF_OUT2, 0x00 },
+ { CS42L42_EQ_COEF_OUT3, 0x00 },
+ { CS42L42_EQ_INIT_STAT, 0x00 },
+ { CS42L42_EQ_START_FILT, 0x00 },
+ { CS42L42_EQ_MUTE_CTL, 0x00 },
+ { CS42L42_SP_RX_CH_SEL, 0x04 },
+ { CS42L42_SP_RX_ISOC_CTL, 0x04 },
+ { CS42L42_SP_RX_FS, 0x8C },
+ { CS42l42_SPDIF_CH_SEL, 0x0E },
+ { CS42L42_SP_TX_ISOC_CTL, 0x04 },
+ { CS42L42_SP_TX_FS, 0xCC },
+ { CS42L42_SPDIF_SW_CTL1, 0x3F },
+ { CS42L42_SRC_SDIN_FS, 0x40 },
+ { CS42L42_SRC_SDOUT_FS, 0x40 },
+ { CS42L42_SPDIF_CTL1, 0x01 },
+ { CS42L42_SPDIF_CTL2, 0x00 },
+ { CS42L42_SPDIF_CTL3, 0x00 },
+ { CS42L42_SPDIF_CTL4, 0x42 },
+ { CS42L42_ASP_TX_SZ_EN, 0x00 },
+ { CS42L42_ASP_TX_CH_EN, 0x00 },
+ { CS42L42_ASP_TX_CH_AP_RES, 0x0F },
+ { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 },
+ { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 },
+ { CS42L42_ASP_TX_HIZ_DLY_CFG, 0x00 },
+ { CS42L42_ASP_TX_CH2_BIT_MSB, 0x00 },
+ { CS42L42_ASP_TX_CH2_BIT_LSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_EN, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x03 },
+ { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x03 },
+ { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH3_AP_RES, 0x03 },
+ { CS42L42_ASP_RX_DAI0_CH3_BIT_MSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH3_BIT_LSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH4_AP_RES, 0x03 },
+ { CS42L42_ASP_RX_DAI0_CH4_BIT_MSB, 0x00 },
+ { CS42L42_ASP_RX_DAI0_CH4_BIT_LSB, 0x00 },
+ { CS42L42_ASP_RX_DAI1_CH1_AP_RES, 0x03 },
+ { CS42L42_ASP_RX_DAI1_CH1_BIT_MSB, 0x00 },
+ { CS42L42_ASP_RX_DAI1_CH1_BIT_LSB, 0x00 },
+ { CS42L42_ASP_RX_DAI1_CH2_AP_RES, 0x03 },
+ { CS42L42_ASP_RX_DAI1_CH2_BIT_MSB, 0x00 },
+ { CS42L42_ASP_RX_DAI1_CH2_BIT_LSB, 0x00 },
+};
+
+/*
+ * This is all the same as for CS42L42 but we
+ * replace the on-reset register defaults.
+ */
+const struct regmap_config cs42l83_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .readable_reg = cs42l42_readable_register,
+ .volatile_reg = cs42l42_volatile_register,
+
+ .ranges = &cs42l42_page_range,
+ .num_ranges = 1,
+
+ .max_register = CS42L42_MAX_REGISTER,
+ .reg_defaults = cs42l83_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(cs42l83_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int cs42l83_i2c_probe(struct i2c_client *i2c_client)
+{
+ struct device *dev = &i2c_client->dev;
+ struct cs42l42_private *cs42l83;
+ struct regmap *regmap;
+ int ret;
+
+ cs42l83 = devm_kzalloc(dev, sizeof(*cs42l83), GFP_KERNEL);
+ if (!cs42l83)
+ return -ENOMEM;
+
+ regmap = devm_regmap_init_i2c(i2c_client, &cs42l83_regmap);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&i2c_client->dev, PTR_ERR(regmap),
+ "regmap_init() failed\n");
+
+ cs42l83->devid = CS42L83_CHIP_ID;
+ cs42l83->dev = dev;
+ cs42l83->regmap = regmap;
+ cs42l83->irq = i2c_client->irq;
+
+ ret = cs42l42_common_probe(cs42l83, &cs42l42_soc_component, &cs42l42_dai);
+ if (ret)
+ return ret;
+
+ return cs42l42_init(cs42l83);
+}
+
+static void cs42l83_i2c_remove(struct i2c_client *i2c_client)
+{
+ struct cs42l42_private *cs42l83 = dev_get_drvdata(&i2c_client->dev);
+
+ cs42l42_common_remove(cs42l83);
+}
+
+static int __maybe_unused cs42l83_i2c_resume(struct device *dev)
+{
+ int ret;
+
+ ret = cs42l42_resume(dev);
+ if (ret)
+ return ret;
+
+ cs42l42_resume_restore(dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops cs42l83_i2c_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l83_i2c_resume)
+};
+
+static const struct of_device_id __maybe_unused cs42l83_of_match[] = {
+ { .compatible = "cirrus,cs42l83", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cs42l83_of_match);
+
+static struct i2c_driver cs42l83_i2c_driver = {
+ .driver = {
+ .name = "cs42l83",
+ .pm = &cs42l83_i2c_pm_ops,
+ .of_match_table = of_match_ptr(cs42l83_of_match),
+ },
+ .probe_new = cs42l83_i2c_probe,
+ .remove = cs42l83_i2c_remove,
+};
+
+module_i2c_driver(cs42l83_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L83 I2C driver");
+MODULE_AUTHOR("Martin Povišer <povik+lin@cutebit.org>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE);
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c
index 411b95143a2e..db39abb2a31b 100644
--- a/sound/soc/codecs/cs43130.c
+++ b/sound/soc/codecs/cs43130.c
@@ -1666,10 +1666,9 @@ static int cs43130_show_dc(struct device *dev, char *buf, u8 ch)
struct cs43130_private *cs43130 = i2c_get_clientdata(client);
if (!cs43130->hpload_done)
- return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n");
+ return sysfs_emit(buf, "NO_HPLOAD\n");
else
- return scnprintf(buf, PAGE_SIZE, "%u\n",
- cs43130->hpload_dc[ch]);
+ return sysfs_emit(buf, "%u\n", cs43130->hpload_dc[ch]);
}
static ssize_t hpload_dc_l_show(struct device *dev,
@@ -1705,8 +1704,8 @@ static int cs43130_show_ac(struct device *dev, char *buf, u8 ch)
if (cs43130->hpload_done && cs43130->ac_meas) {
for (i = 0; i < ARRAY_SIZE(cs43130_ac_freq); i++) {
- tmp = scnprintf(buf + j, PAGE_SIZE - j, "%u\n",
- cs43130->hpload_ac[i][ch]);
+ tmp = sysfs_emit_at(buf, j, "%u\n",
+ cs43130->hpload_ac[i][ch]);
if (!tmp)
break;
@@ -1715,7 +1714,7 @@ static int cs43130_show_ac(struct device *dev, char *buf, u8 ch)
return j;
} else {
- return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n");
+ return sysfs_emit(buf, "NO_HPLOAD\n");
}
}
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 50ecf30e6136..4746c8700451 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -2196,6 +2196,7 @@ static int da7219_register_dai_clks(struct snd_soc_component *component)
dai_clk_lookup = clkdev_hw_create(dai_clk_hw, init.name,
"%s", dev_name(dev));
if (!dai_clk_lookup) {
+ clk_hw_unregister(dai_clk_hw);
ret = -ENOMEM;
goto err;
} else {
@@ -2217,12 +2218,12 @@ static int da7219_register_dai_clks(struct snd_soc_component *component)
return 0;
err:
- do {
+ while (--i >= 0) {
if (da7219->dai_clks_lookup[i])
clkdev_drop(da7219->dai_clks_lookup[i]);
clk_hw_unregister(&da7219->dai_clks_hw[i]);
- } while (i-- > 0);
+ }
if (np)
kfree(da7219->clk_hw_data);
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index de7185f73e1e..056c3082fe02 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -767,9 +767,31 @@ static void es8316_remove(struct snd_soc_component *component)
clk_disable_unprepare(es8316->mclk);
}
+static int es8316_resume(struct snd_soc_component *component)
+{
+ struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(es8316->regmap, false);
+ regcache_sync(es8316->regmap);
+
+ return 0;
+}
+
+static int es8316_suspend(struct snd_soc_component *component)
+{
+ struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(es8316->regmap, true);
+ regcache_mark_dirty(es8316->regmap);
+
+ return 0;
+}
+
static const struct snd_soc_component_driver soc_component_dev_es8316 = {
.probe = es8316_probe,
.remove = es8316_remove,
+ .resume = es8316_resume,
+ .suspend = es8316_suspend,
.set_jack = es8316_set_jack,
.controls = es8316_snd_controls,
.num_controls = ARRAY_SIZE(es8316_snd_controls),
@@ -793,6 +815,8 @@ static const struct regmap_access_table es8316_volatile_table = {
static const struct regmap_config es8316_regmap = {
.reg_bits = 8,
.val_bits = 8,
+ .use_single_read = true,
+ .use_single_write = true,
.max_register = 0x53,
.volatile_table = &es8316_volatile_table,
.cache_type = REGCACHE_RBTREE,
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
new file mode 100755
index 000000000000..87c1cc16592b
--- /dev/null
+++ b/sound/soc/codecs/es8326.c
@@ -0,0 +1,905 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// es8326.c -- es8326 ALSA SoC audio driver
+// Copyright Everest Semiconductor Co., Ltd
+//
+// Authors: David Yang <yangxiaohua@everest-semi.com>
+//
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "es8326.h"
+
+struct es8326_priv {
+ struct clk *mclk;
+ struct i2c_client *i2c;
+ struct regmap *regmap;
+ struct snd_soc_component *component;
+ struct delayed_work jack_detect_work;
+ struct delayed_work button_press_work;
+ struct snd_soc_jack *jack;
+ int irq;
+ /* The lock protects the situation that an irq is generated
+ * while enabling or disabling or during an irq.
+ */
+ struct mutex lock;
+ u8 mic1_src;
+ u8 mic2_src;
+ u8 jack_pol;
+ u8 interrupt_src;
+ u8 interrupt_clk;
+ bool jd_inverted;
+ unsigned int sysclk;
+};
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9550, 50, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_analog_pga_tlv, 0, 300, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_pga_tlv, 0, 600, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(softramp_rate, 0, 100, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(drc_target_tlv, -3200, 200, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(drc_recovery_tlv, -125, 250, 0);
+
+static const char *const winsize[] = {
+ "0.25db/2 LRCK",
+ "0.25db/4 LRCK",
+ "0.25db/8 LRCK",
+ "0.25db/16 LRCK",
+ "0.25db/32 LRCK",
+ "0.25db/64 LRCK",
+ "0.25db/128 LRCK",
+ "0.25db/256 LRCK",
+ "0.25db/512 LRCK",
+ "0.25db/1024 LRCK",
+ "0.25db/2048 LRCK",
+ "0.25db/4096 LRCK",
+ "0.25db/8192 LRCK",
+ "0.25db/16384 LRCK",
+ "0.25db/32768 LRCK",
+ "0.25db/65536 LRCK",
+};
+
+static const char *const dacpol_txt[] = {
+ "Normal", "R Invert", "L Invert", "L + R Invert" };
+
+static const struct soc_enum dacpol =
+ SOC_ENUM_SINGLE(ES8326_DAC_DSM, 4, 4, dacpol_txt);
+static const struct soc_enum alc_winsize =
+ SOC_ENUM_SINGLE(ES8326_ADC_RAMPRATE, 4, 16, winsize);
+static const struct soc_enum drc_winsize =
+ SOC_ENUM_SINGLE(ES8326_DRC_WINSIZE, 4, 16, winsize);
+
+static const struct snd_kcontrol_new es8326_snd_controls[] = {
+ SOC_SINGLE_TLV("DAC Playback Volume", ES8326_DAC_VOL, 0, 0xbf, 0, dac_vol_tlv),
+ SOC_ENUM("Playback Polarity", dacpol),
+ SOC_SINGLE_TLV("DAC Ramp Rate", ES8326_DAC_RAMPRATE, 0, 0x0f, 0, softramp_rate),
+ SOC_SINGLE_TLV("DRC Recovery Level", ES8326_DRC_RECOVERY, 0, 4, 0, drc_recovery_tlv),
+ SOC_ENUM("DRC Winsize", drc_winsize),
+ SOC_SINGLE_TLV("DRC Target Level", ES8326_DRC_WINSIZE, 0, 0x0f, 0, drc_target_tlv),
+
+ SOC_DOUBLE_R_TLV("ADC Capture Volume", ES8326_ADC1_VOL, ES8326_ADC2_VOL, 0, 0xff, 0,
+ adc_vol_tlv),
+ SOC_DOUBLE_TLV("ADC PGA Volume", ES8326_ADC_SCALE, 4, 0, 5, 0, adc_pga_tlv),
+ SOC_SINGLE_TLV("ADC PGA Gain Volume", ES8326_PGAGAIN, 0, 10, 0, adc_analog_pga_tlv),
+ SOC_SINGLE_TLV("ADC Ramp Rate", ES8326_ADC_RAMPRATE, 0, 0x0f, 0, softramp_rate),
+ SOC_SINGLE("ALC Capture Switch", ES8326_ALC_RECOVERY, 3, 1, 0),
+ SOC_SINGLE_TLV("ALC Capture Recovery Level", ES8326_ALC_LEVEL,
+ 0, 4, 0, drc_recovery_tlv),
+ SOC_ENUM("ALC Capture Winsize", alc_winsize),
+ SOC_SINGLE_TLV("ALC Capture Target Level", ES8326_ALC_LEVEL,
+ 0, 0x0f, 0, drc_target_tlv),
+
+};
+
+static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("MIC3"),
+ SND_SOC_DAPM_INPUT("MIC4"),
+
+ SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+
+ /* Digital Interface */
+ SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+ /* ADC Digital Mute */
+ SND_SOC_DAPM_PGA("ADC L1", ES8326_ADC_MUTE, 0, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("ADC R1", ES8326_ADC_MUTE, 1, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("ADC L2", ES8326_ADC_MUTE, 2, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("ADC R2", ES8326_ADC_MUTE, 3, 1, NULL, 0),
+
+ /* Analog Power Supply*/
+ SND_SOC_DAPM_DAC("Right DAC", NULL, ES8326_ANA_PDN, 0, 1),
+ SND_SOC_DAPM_DAC("Left DAC", NULL, ES8326_ANA_PDN, 1, 1),
+ SND_SOC_DAPM_SUPPLY("Analog Power", ES8326_ANA_PDN, 7, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("IBias Power", ES8326_ANA_PDN, 6, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC Vref", ES8326_ANA_PDN, 5, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC Vref", ES8326_ANA_PDN, 4, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Vref Power", ES8326_ANA_PDN, 3, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS1", ES8326_ANA_MICBIAS, 2, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS2", ES8326_ANA_MICBIAS, 3, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX, 7, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX, 3, 0, NULL, 0),
+
+ /* Headphone Charge Pump and Output */
+ SND_SOC_DAPM_SUPPLY("HPOR Cal", ES8326_HP_CAL, 7, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("HPOL Cal", ES8326_HP_CAL, 3, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8326_HP_DRIVER,
+ 3, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Headphone Driver Bias", ES8326_HP_DRIVER,
+ 2, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Headphone LDO", ES8326_HP_DRIVER,
+ 1, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Headphone Reference", ES8326_HP_DRIVER,
+ 0, 1, NULL, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL,
+ ES8326_HPOR_SHIFT, 7, 7, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL,
+ 0, 7, 7, 0),
+
+ SND_SOC_DAPM_OUTPUT("HPOL"),
+ SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_route es8326_dapm_routes[] = {
+ {"ADC L1", NULL, "MIC1"},
+ {"ADC R1", NULL, "MIC2"},
+ {"ADC L2", NULL, "MIC3"},
+ {"ADC R2", NULL, "MIC4"},
+
+ {"ADC L", NULL, "ADC L1"},
+ {"ADC R", NULL, "ADC R1"},
+ {"ADC L", NULL, "ADC L2"},
+ {"ADC R", NULL, "ADC R2"},
+
+ {"I2S OUT", NULL, "ADC L"},
+ {"I2S OUT", NULL, "ADC R"},
+
+ {"I2S OUT", NULL, "Analog Power"},
+ {"I2S OUT", NULL, "ADC Vref"},
+ {"I2S OUT", NULL, "Vref Power"},
+ {"I2S OUT", NULL, "IBias Power"},
+ {"I2S IN", NULL, "Analog Power"},
+ {"I2S IN", NULL, "DAC Vref"},
+ {"I2S IN", NULL, "Vref Power"},
+ {"I2S IN", NULL, "IBias Power"},
+
+ {"Right DAC", NULL, "I2S IN"},
+ {"Left DAC", NULL, "I2S IN"},
+
+ {"LHPMIX", NULL, "Left DAC"},
+ {"RHPMIX", NULL, "Right DAC"},
+
+ {"HPOR", NULL, "HPOR Cal"},
+ {"HPOL", NULL, "HPOL Cal"},
+ {"HPOR", NULL, "HPOR Supply"},
+ {"HPOL", NULL, "HPOL Supply"},
+ {"HPOL", NULL, "Headphone Charge Pump"},
+ {"HPOR", NULL, "Headphone Charge Pump"},
+ {"HPOL", NULL, "Headphone Driver Bias"},
+ {"HPOR", NULL, "Headphone Driver Bias"},
+ {"HPOL", NULL, "Headphone LDO"},
+ {"HPOR", NULL, "Headphone LDO"},
+ {"HPOL", NULL, "Headphone Reference"},
+ {"HPOR", NULL, "Headphone Reference"},
+
+ {"HPOL", NULL, "LHPMIX"},
+ {"HPOR", NULL, "RHPMIX"},
+};
+
+static const struct regmap_range es8326_volatile_ranges[] = {
+ regmap_reg_range(ES8326_HP_DETECT, ES8326_HP_DETECT),
+};
+
+static const struct regmap_access_table es8326_volatile_table = {
+ .yes_ranges = es8326_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(es8326_volatile_ranges),
+};
+
+static const struct regmap_config es8326_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xff,
+ .volatile_table = &es8326_volatile_table,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+struct _coeff_div {
+ u16 fs;
+ u32 rate;
+ u32 mclk;
+ u8 reg4;
+ u8 reg5;
+ u8 reg6;
+ u8 reg7;
+ u8 reg8;
+ u8 reg9;
+ u8 rega;
+ u8 regb;
+};
+
+/* codec hifi mclk clock divider coefficients */
+/* {ratio, LRCK, MCLK, REG04, REG05, REG06, REG07, REG08, REG09, REG10, REG11} */
+static const struct _coeff_div coeff_div[] = {
+ {32, 8000, 256000, 0x60, 0x00, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+ {32, 16000, 512000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+ {32, 44100, 1411200, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {32, 48000, 1536000, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {36, 8000, 288000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+ {36, 16000, 576000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+ {48, 8000, 384000, 0x60, 0x02, 0x1F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+ {48, 16000, 768000, 0x20, 0x02, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+ {48, 48000, 2304000, 0x00, 0x02, 0x0D, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {64, 8000, 512000, 0x60, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+ {64, 16000, 1024000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+
+ {64, 44100, 2822400, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {64, 48000, 3072000, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {72, 8000, 576000, 0x20, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+ {72, 16000, 1152000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x23, 0x47},
+ {96, 8000, 768000, 0x60, 0x02, 0x1D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+ {96, 16000, 1536000, 0x20, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+ {100, 48000, 4800000, 0x04, 0x04, 0x3F, 0x6D, 0x38, 0x08, 0x4f, 0x1f},
+ {125, 48000, 6000000, 0x04, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+ {128, 8000, 1024000, 0x60, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+ {128, 16000, 2048000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+ {128, 44100, 5644800, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {128, 48000, 6144000, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {144, 8000, 1152000, 0x20, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+ {144, 16000, 2304000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+ {192, 8000, 1536000, 0x60, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+ {192, 16000, 3072000, 0x20, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
+ {200, 48000, 9600000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {250, 48000, 12000000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+ {256, 8000, 2048000, 0x60, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+ {256, 16000, 4096000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+ {256, 44100, 11289600, 0x00, 0x00, 0x10, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {256, 48000, 12288000, 0x00, 0x00, 0x30, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {288, 8000, 2304000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x23, 0x47},
+ {384, 8000, 3072000, 0x60, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+ {384, 16000, 6144000, 0x20, 0x02, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+ {384, 48000, 18432000, 0x00, 0x02, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {400, 48000, 19200000, 0x09, 0x04, 0x0f, 0x6d, 0x3a, 0x0A, 0x4F, 0x1F},
+ {500, 48000, 24000000, 0x18, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {512, 8000, 4096000, 0x60, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+ {512, 16000, 8192000, 0x20, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+
+ {512, 44100, 22579200, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {512, 48000, 24576000, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {768, 8000, 6144000, 0x60, 0x02, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+ {768, 16000, 12288000, 0x20, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+ {800, 48000, 38400000, 0x00, 0x18, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
+ {1024, 8000, 8192000, 0x60, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+ {1024, 16000, 16384000, 0x20, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+ {1152, 16000, 18432000, 0x20, 0x08, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+ {1536, 8000, 12288000, 0x60, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+
+ {1536, 16000, 24576000, 0x20, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+ {1625, 8000, 13000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+ {1625, 16000, 26000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+ {2048, 8000, 16384000, 0x60, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+ {2304, 8000, 18432000, 0x40, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x5F},
+ {3072, 8000, 24576000, 0x60, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+ {3250, 8000, 26000000, 0x0C, 0x18, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+ if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int es8326_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *codec = codec_dai->component;
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec);
+
+ es8326->sysclk = freq;
+
+ return 0;
+}
+
+static int es8326_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ u8 iface = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFP:
+ snd_soc_component_update_bits(component, ES8326_RESET,
+ ES8326_MASTER_MODE_EN, ES8326_MASTER_MODE_EN);
+ break;
+ case SND_SOC_DAIFMT_CBC_CFC:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ dev_err(component->dev, "Codec driver does not support right justified\n");
+ return -EINVAL;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface |= ES8326_DAIFMT_LEFT_J;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ iface |= ES8326_DAIFMT_DSP_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ iface |= ES8326_DAIFMT_DSP_B;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component, ES8326_FMT, ES8326_DAIFMT_MASK, iface);
+
+ return 0;
+}
+
+static int es8326_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+ u8 srate = 0;
+ int coeff;
+
+ coeff = get_coeff(es8326->sysclk, params_rate(params));
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ srate |= ES8326_S16_LE;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ srate |= ES8326_S20_3_LE;
+ break;
+ case SNDRV_PCM_FORMAT_S18_3LE:
+ srate |= ES8326_S18_LE;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ srate |= ES8326_S24_LE;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ srate |= ES8326_S32_LE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set iface & srate */
+ snd_soc_component_update_bits(component, ES8326_FMT, ES8326_DATA_LEN_MASK, srate);
+
+ if (coeff >= 0) {
+ regmap_write(es8326->regmap, ES8326_CLK_DIV1,
+ coeff_div[coeff].reg4);
+ regmap_write(es8326->regmap, ES8326_CLK_DIV2,
+ coeff_div[coeff].reg5);
+ regmap_write(es8326->regmap, ES8326_CLK_DLL,
+ coeff_div[coeff].reg6);
+ regmap_write(es8326->regmap, ES8326_CLK_MUX,
+ coeff_div[coeff].reg7);
+ regmap_write(es8326->regmap, ES8326_CLK_ADC_SEL,
+ coeff_div[coeff].reg8);
+ regmap_write(es8326->regmap, ES8326_CLK_DAC_SEL,
+ coeff_div[coeff].reg9);
+ regmap_write(es8326->regmap, ES8326_CLK_ADC_OSR,
+ coeff_div[coeff].rega);
+ regmap_write(es8326->regmap, ES8326_CLK_DAC_OSR,
+ coeff_div[coeff].regb);
+ } else {
+ dev_warn(component->dev, "Clock coefficients do not match");
+ }
+
+ return 0;
+}
+
+static int es8326_set_bias_level(struct snd_soc_component *codec,
+ enum snd_soc_bias_level level)
+{
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec);
+ int ret;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ ret = clk_prepare_enable(es8326->mclk);
+ if (ret)
+ return ret;
+ regmap_write(es8326->regmap, ES8326_RESET, ES8326_PWRUP_SEQ_EN);
+ regmap_write(es8326->regmap, ES8326_INTOUT_IO, 0x45);
+ regmap_write(es8326->regmap, ES8326_SDINOUT1_IO,
+ (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT));
+ regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
+ regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05);
+ regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x02);
+ regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x40);
+ regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0xAA);
+ regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ break;
+ case SND_SOC_BIAS_OFF:
+ clk_disable_unprepare(es8326->mclk);
+ regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x11);
+ regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_OFF);
+ regmap_write(es8326->regmap, ES8326_PGA_PDN, 0xF8);
+ regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x00);
+ regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x08);
+ regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT);
+ regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
+ regmap_write(es8326->regmap, ES8326_RESET,
+ ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN);
+ break;
+ }
+
+ return 0;
+}
+
+#define es8326_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops es8326_ops = {
+ .hw_params = es8326_pcm_hw_params,
+ .set_fmt = es8326_set_dai_fmt,
+ .set_sysclk = es8326_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver es8326_dai = {
+ .name = "ES8326 HiFi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = es8326_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = es8326_FORMATS,
+ },
+ .ops = &es8326_ops,
+ .symmetric_rate = 1,
+};
+
+static void es8326_enable_micbias(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+ snd_soc_dapm_mutex_lock(dapm);
+ snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1");
+ snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS2");
+ snd_soc_dapm_sync_unlocked(dapm);
+ snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static void es8326_disable_micbias(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+ snd_soc_dapm_mutex_lock(dapm);
+ snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS2");
+ snd_soc_dapm_sync_unlocked(dapm);
+ snd_soc_dapm_mutex_unlock(dapm);
+}
+
+/*
+ * For button detection, set the following in soundcard
+ * snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ * snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+ * snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+ */
+static void es8326_jack_button_handler(struct work_struct *work)
+{
+ struct es8326_priv *es8326 =
+ container_of(work, struct es8326_priv, button_press_work.work);
+ struct snd_soc_component *comp = es8326->component;
+ unsigned int iface;
+ static int button_to_report, press_count;
+ static int prev_button, cur_button;
+
+ if (!(es8326->jack->status & SND_JACK_HEADSET)) /* Jack unplugged */
+ return;
+
+ mutex_lock(&es8326->lock);
+ iface = snd_soc_component_read(comp, ES8326_HP_DETECT);
+ switch (iface) {
+ case 0x93:
+ /* pause button detected */
+ cur_button = SND_JACK_BTN_0;
+ break;
+ case 0x6f:
+ /* button volume up */
+ cur_button = SND_JACK_BTN_1;
+ break;
+ case 0x27:
+ /* button volume down */
+ cur_button = SND_JACK_BTN_2;
+ break;
+ case 0x1e:
+ /* button released or not pressed */
+ cur_button = 0;
+ break;
+ default:
+ break;
+ }
+
+ if ((prev_button == cur_button) && (cur_button != 0)) {
+ press_count++;
+ if (press_count > 10) {
+ /* report a press every 500ms */
+ snd_soc_jack_report(es8326->jack, cur_button,
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
+ press_count = 0;
+ }
+ button_to_report = cur_button;
+ queue_delayed_work(system_wq, &es8326->button_press_work,
+ msecs_to_jiffies(50));
+ } else if (prev_button != cur_button) {
+ /* mismatch, detect again */
+ prev_button = cur_button;
+ queue_delayed_work(system_wq, &es8326->button_press_work,
+ msecs_to_jiffies(50));
+ } else {
+ /* released or no pressed */
+ if (button_to_report != 0) {
+ snd_soc_jack_report(es8326->jack, button_to_report,
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
+ snd_soc_jack_report(es8326->jack, 0,
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
+ button_to_report = 0;
+ }
+ }
+ mutex_unlock(&es8326->lock);
+}
+
+static void es8326_jack_detect_handler(struct work_struct *work)
+{
+ struct es8326_priv *es8326 =
+ container_of(work, struct es8326_priv, jack_detect_work.work);
+ struct snd_soc_component *comp = es8326->component;
+ unsigned int iface;
+
+ mutex_lock(&es8326->lock);
+ iface = snd_soc_component_read(comp, ES8326_HP_DETECT);
+ dev_dbg(comp->dev, "gpio flag %#04x", iface);
+ if ((iface & ES8326_HPINSERT_FLAG) == 0) {
+ /* Jack unplugged or spurious IRQ */
+ dev_dbg(comp->dev, "No headset detected");
+ if (es8326->jack->status & SND_JACK_HEADPHONE) {
+ snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
+ snd_soc_component_write(comp, ES8326_ADC1_SRC, es8326->mic2_src);
+ es8326_disable_micbias(comp);
+ }
+ } else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) {
+ if (es8326->jack->status & SND_JACK_HEADSET) {
+ /* detect button */
+ queue_delayed_work(system_wq, &es8326->button_press_work, 10);
+ } else {
+ if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) {
+ dev_dbg(comp->dev, "Headset detected");
+ snd_soc_jack_report(es8326->jack,
+ SND_JACK_HEADSET, SND_JACK_HEADSET);
+ snd_soc_component_write(comp,
+ ES8326_ADC1_SRC, es8326->mic1_src);
+ } else {
+ dev_dbg(comp->dev, "Headphone detected");
+ snd_soc_jack_report(es8326->jack,
+ SND_JACK_HEADPHONE, SND_JACK_HEADSET);
+ }
+ }
+ }
+ mutex_unlock(&es8326->lock);
+}
+
+static irqreturn_t es8326_irq(int irq, void *dev_id)
+{
+ struct es8326_priv *es8326 = dev_id;
+ struct snd_soc_component *comp = es8326->component;
+
+ if (!es8326->jack)
+ goto out;
+
+ es8326_enable_micbias(comp);
+
+ if (es8326->jack->status & SND_JACK_HEADSET)
+ queue_delayed_work(system_wq, &es8326->jack_detect_work,
+ msecs_to_jiffies(10));
+ else
+ queue_delayed_work(system_wq, &es8326->jack_detect_work,
+ msecs_to_jiffies(300));
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int es8326_resume(struct snd_soc_component *component)
+{
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+ unsigned int reg;
+
+ regcache_cache_only(es8326->regmap, false);
+ regcache_sync(es8326->regmap);
+
+ regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON);
+ /* Two channel ADC */
+ regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x02);
+ regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00);
+ regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x1F);
+ regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xC8);
+ regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x88);
+ regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x20);
+ regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x08);
+ regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x22);
+ regmap_write(es8326->regmap, ES8326_ADC1_SRC, es8326->mic1_src);
+ regmap_write(es8326->regmap, ES8326_ADC2_SRC, es8326->mic2_src);
+ regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88);
+ regmap_write(es8326->regmap, ES8326_HP_DET,
+ ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol);
+ regmap_write(es8326->regmap, ES8326_INT_SOURCE, es8326->interrupt_src);
+ regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk);
+ regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON);
+ snd_soc_component_update_bits(component, ES8326_PGAGAIN,
+ ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL);
+
+ regmap_read(es8326->regmap, ES8326_CHIP_VERSION, &reg);
+ if ((reg & ES8326_VERSION_B) == 1) {
+ regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0xDD);
+ regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F);
+ regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x0F);
+ /* enable button detect */
+ regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xA0);
+ }
+
+ es8326_irq(es8326->irq, es8326);
+ return 0;
+}
+
+static int es8326_suspend(struct snd_soc_component *component)
+{
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+ cancel_delayed_work_sync(&es8326->jack_detect_work);
+ es8326_disable_micbias(component);
+
+ regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_OFF);
+ regcache_cache_only(es8326->regmap, true);
+ regcache_mark_dirty(es8326->regmap);
+
+ return 0;
+}
+
+static int es8326_probe(struct snd_soc_component *component)
+{
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ es8326->component = component;
+ es8326->jd_inverted = device_property_read_bool(component->dev,
+ "everest,jack-detect-inverted");
+
+ ret = device_property_read_u8(component->dev, "everest,mic1-src", &es8326->mic1_src);
+ if (ret != 0) {
+ dev_dbg(component->dev, "mic1-src return %d", ret);
+ es8326->mic1_src = ES8326_ADC_AMIC;
+ }
+ dev_dbg(component->dev, "mic1-src %x", es8326->mic1_src);
+
+ ret = device_property_read_u8(component->dev, "everest,mic2-src", &es8326->mic2_src);
+ if (ret != 0) {
+ dev_dbg(component->dev, "mic2-src return %d", ret);
+ es8326->mic2_src = ES8326_ADC_DMIC;
+ }
+ dev_dbg(component->dev, "mic2-src %x", es8326->mic2_src);
+
+ ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol);
+ if (ret != 0) {
+ dev_dbg(component->dev, "jack-pol return %d", ret);
+ es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP;
+ }
+ dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol);
+
+ ret = device_property_read_u8(component->dev, "everest,interrupt-src", &es8326->jack_pol);
+ if (ret != 0) {
+ dev_dbg(component->dev, "interrupt-src return %d", ret);
+ es8326->interrupt_src = ES8326_HP_DET_SRC_PIN9;
+ }
+ dev_dbg(component->dev, "interrupt-src %x", es8326->interrupt_src);
+
+ ret = device_property_read_u8(component->dev, "everest,interrupt-clk", &es8326->jack_pol);
+ if (ret != 0) {
+ dev_dbg(component->dev, "interrupt-clk return %d", ret);
+ es8326->interrupt_clk = 0x45;
+ }
+ dev_dbg(component->dev, "interrupt-clk %x", es8326->interrupt_clk);
+
+ es8326_resume(component);
+ return 0;
+}
+
+static void es8326_enable_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *jack)
+{
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&es8326->lock);
+ if (es8326->jd_inverted)
+ snd_soc_component_update_bits(component, ES8326_HP_DET,
+ ES8326_HP_DET_JACK_POL, ~es8326->jack_pol);
+ es8326->jack = jack;
+
+ mutex_unlock(&es8326->lock);
+ es8326_irq(es8326->irq, es8326);
+}
+
+static void es8326_disable_jack_detect(struct snd_soc_component *component)
+{
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "Enter into %s\n", __func__);
+ if (!es8326->jack)
+ return; /* Already disabled (or never enabled) */
+ cancel_delayed_work_sync(&es8326->jack_detect_work);
+
+ mutex_lock(&es8326->lock);
+ if (es8326->jack->status & SND_JACK_MICROPHONE) {
+ es8326_disable_micbias(component);
+ snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
+ }
+ es8326->jack = NULL;
+ mutex_unlock(&es8326->lock);
+}
+
+static int es8326_set_jack(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *data)
+{
+ if (jack)
+ es8326_enable_jack_detect(component, jack);
+ else
+ es8326_disable_jack_detect(component);
+
+ return 0;
+}
+
+static void es8326_remove(struct snd_soc_component *component)
+{
+ es8326_disable_jack_detect(component);
+ es8326_set_bias_level(component, SND_SOC_BIAS_OFF);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_es8326 = {
+ .probe = es8326_probe,
+ .remove = es8326_remove,
+ .resume = es8326_resume,
+ .suspend = es8326_suspend,
+ .set_bias_level = es8326_set_bias_level,
+ .set_jack = es8326_set_jack,
+ .dapm_widgets = es8326_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(es8326_dapm_widgets),
+ .dapm_routes = es8326_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(es8326_dapm_routes),
+ .controls = es8326_snd_controls,
+ .num_controls = ARRAY_SIZE(es8326_snd_controls),
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static int es8326_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct es8326_priv *es8326;
+ int ret;
+
+ es8326 = devm_kzalloc(&i2c->dev, sizeof(struct es8326_priv), GFP_KERNEL);
+ if (!es8326)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, es8326);
+ es8326->i2c = i2c;
+ mutex_init(&es8326->lock);
+ es8326->regmap = devm_regmap_init_i2c(i2c, &es8326_regmap_config);
+ if (IS_ERR(es8326->regmap)) {
+ ret = PTR_ERR(es8326->regmap);
+ dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+ return ret;
+ }
+
+ es8326->irq = i2c->irq;
+ INIT_DELAYED_WORK(&es8326->jack_detect_work,
+ es8326_jack_detect_handler);
+ INIT_DELAYED_WORK(&es8326->button_press_work,
+ es8326_jack_button_handler);
+ /* ES8316 is level-based while ES8326 is edge-based */
+ ret = devm_request_threaded_irq(&i2c->dev, es8326->irq, NULL, es8326_irq,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "es8326", es8326);
+ if (ret) {
+ dev_warn(&i2c->dev, "Failed to request IRQ: %d: %d\n",
+ es8326->irq, ret);
+ es8326->irq = -ENXIO;
+ }
+
+ es8326->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+ if (IS_ERR(es8326->mclk)) {
+ dev_err(&i2c->dev, "unable to get mclk\n");
+ return PTR_ERR(es8326->mclk);
+ }
+ if (!es8326->mclk)
+ dev_warn(&i2c->dev, "assuming static mclk\n");
+
+ ret = clk_prepare_enable(es8326->mclk);
+ if (ret) {
+ dev_err(&i2c->dev, "unable to enable mclk\n");
+ return ret;
+ }
+ return devm_snd_soc_register_component(&i2c->dev,
+ &soc_component_dev_es8326,
+ &es8326_dai, 1);
+}
+
+static const struct i2c_device_id es8326_i2c_id[] = {
+ {"es8326", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, es8326_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id es8326_of_match[] = {
+ { .compatible = "everest,es8326", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, es8326_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id es8326_acpi_match[] = {
+ {"ESSX8326", 0},
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, es8326_acpi_match);
+#endif
+
+static struct i2c_driver es8326_i2c_driver = {
+ .driver = {
+ .name = "es8326",
+ .acpi_match_table = ACPI_PTR(es8326_acpi_match),
+ .of_match_table = of_match_ptr(es8326_of_match),
+ },
+ .probe = es8326_i2c_probe,
+ .id_table = es8326_i2c_id,
+};
+module_i2c_driver(es8326_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC es8326 driver");
+MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h
new file mode 100755
index 000000000000..8e5ffe5ee10d
--- /dev/null
+++ b/sound/soc/codecs/es8326.h
@@ -0,0 +1,182 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * es8326.h -- es8326 ALSA SoC audio driver
+ * Copyright Everest Semiconductor Co.,Ltd
+ *
+ * Authors: David Yang <yangxiaohua@everest-semi.com>
+ */
+
+#ifndef _ES8326_H
+#define _ES8326_H
+
+#define CONFIG_HHTECH_MINIPMP 1
+
+/* ES8326 register space */
+#define ES8326_RESET 0x00
+#define ES8326_CLK_CTL 0x01
+#define ES8326_CLK_INV 0x02
+#define ES8326_CLK_RESAMPLE 0x03
+#define ES8326_CLK_DIV1 0x04
+#define ES8326_CLK_DIV2 0x05
+#define ES8326_CLK_DLL 0x06
+#define ES8326_CLK_MUX 0x07
+#define ES8326_CLK_ADC_SEL 0x08
+#define ES8326_CLK_DAC_SEL 0x09
+#define ES8326_CLK_ADC_OSR 0x0a
+#define ES8326_CLK_DAC_OSR 0x0b
+#define ES8326_CLK_DIV_CPC 0x0c
+#define ES8326_CLK_DIV_BCLK 0x0d
+#define ES8326_CLK_TRI 0x0e
+#define ES8326_CLK_DIV_LRCK 0x0f
+#define ES8326_CLK_VMIDS1 0x10
+#define ES8326_CLK_VMIDS2 0x11
+#define ES8326_CLK_CAL_TIME 0x12
+#define ES8326_FMT 0x13
+
+#define ES8326_DAC_MUTE 0x14
+#define ES8326_ADC_MUTE 0x15
+#define ES8326_ANA_PDN 0x16
+#define ES8326_PGA_PDN 0x17
+#define ES8326_VMIDSEL 0x18
+#define ES8326_ANA_LP 0x19
+#define ES8326_ANA_DMS 0x1a
+#define ES8326_ANA_MICBIAS 0x1b
+#define ES8326_ANA_VSEL 0x1c
+#define ES8326_SYS_BIAS 0x1d
+#define ES8326_BIAS_SW1 0x1e
+#define ES8326_BIAS_SW2 0x1f
+#define ES8326_BIAS_SW3 0x20
+#define ES8326_BIAS_SW4 0x21
+#define ES8326_VMIDLOW 0x22
+#define ES8326_PGAGAIN 0x23
+#define ES8326_HP_DRIVER 0x24
+#define ES8326_DAC2HPMIX 0x25
+#define ES8326_HP_VOL 0x26
+#define ES8326_HP_CAL 0x27
+#define ES8326_HP_DRIVER_REF 0x28
+#define ES8326_ADC_SCALE 0x29
+#define ES8326_ADC1_SRC 0x2a
+#define ES8326_ADC2_SRC 0x2b
+#define ES8326_ADC1_VOL 0x2c
+#define ES8326_ADC2_VOL 0x2d
+#define ES8326_ADC_RAMPRATE 0x2e
+#define ES8326_ALC_RECOVERY 0x32
+#define ES8326_ALC_LEVEL 0x33
+#define ES8326_ADC_HPFS1 0x34
+#define ES8326_ADC_HPFS2 0x35
+#define ES8326_ADC_EQ 0x36
+#define ES8326_HP_OFFSET_CAL 0x4A
+#define ES8326_HPL_OFFSET_INI 0x4B
+#define ES8326_HPR_OFFSET_INI 0x4C
+#define ES8326_DAC_DSM 0x4D
+#define ES8326_DAC_RAMPRATE 0x4E
+#define ES8326_DAC_VPPSCALE 0x4F
+#define ES8326_DAC_VOL 0x50
+#define ES8326_DRC_RECOVERY 0x53
+#define ES8326_DRC_WINSIZE 0x54
+#define ES8326_HPJACK_TIMER 0x56
+#define ES8326_HP_DET 0x57
+#define ES8326_INT_SOURCE 0x58
+#define ES8326_INTOUT_IO 0x59
+#define ES8326_SDINOUT1_IO 0x5A
+#define ES8326_SDINOUT23_IO 0x5B
+#define ES8326_JACK_PULSE 0x5C
+
+#define ES8326_PULLUP_CTL 0xF9
+#define ES8326_HP_DETECT 0xFB
+#define ES8326_CHIP_ID1 0xFD
+#define ES8326_CHIP_ID2 0xFE
+#define ES8326_CHIP_VERSION 0xFF
+
+/* ES8326_RESET */
+#define ES8326_CSM_ON (1 << 7)
+#define ES8326_MASTER_MODE_EN (1 << 6)
+#define ES8326_PWRUP_SEQ_EN (1 << 5)
+#define ES8326_CODEC_RESET (0x0f << 0)
+#define ES8326_CSM_OFF (0 << 7)
+
+/* ES8326_CLK_CTL */
+#define ES8326_CLK_ON (0x7f << 0)
+#define ES8326_CLK_OFF (0 << 0)
+
+/* ES8326_CLK_INV */
+#define ES8326_BCLK_AS_MCLK (1 << 3)
+
+/* ES8326_FMT */
+#define ES8326_S24_LE (0 << 2)
+#define ES8326_S20_3_LE (1 << 2)
+#define ES8326_S18_LE (2 << 2)
+#define ES8326_S16_LE (3 << 2)
+#define ES8326_S32_LE (4 << 2)
+#define ES8326_DATA_LEN_MASK (7 << 2)
+
+#define ES8326_DAIFMT_MASK ((1 << 5) | (3 << 0))
+#define ES8326_DAIFMT_I2S 0
+#define ES8326_DAIFMT_LEFT_J (1 << 0)
+#define ES8326_DAIFMT_DSP_A (3 << 0)
+#define ES8326_DAIFMT_DSP_B ((1 << 5) | (3 << 0))
+
+/* ES8326_PGAGAIN */
+#define ES8326_MIC_SEL_MASK (3 << 4)
+#define ES8326_MIC1_SEL (1 << 4)
+#define ES8326_MIC2_SEL (1 << 5)
+
+/* ES8326_HP_CAL */
+#define ES8326_HPOR_SHIFT 4
+
+/* ES8326_ADC1_SRC */
+#define ES8326_ADC1_SHIFT 0
+#define ES8326_ADC2_SHIFT 4
+#define ES8326_ADC_SRC_ANA 0
+#define ES8326_ADC_SRC_ANA_INV_SW0 1
+#define ES8326_ADC_SRC_ANA_INV_SW1 2
+#define ES8326_ADC_SRC_DMIC_MCLK 3
+#define ES8326_ADC_SRC_DMIC_SDIN2 4
+#define ES8326_ADC_SRC_DMIC_SDIN2_INV 5
+#define ES8326_ADC_SRC_DMIC_SDIN3 6
+#define ES8326_ADC_SRC_DMIC_SDIN3_INV 7
+
+#define ES8326_ADC_AMIC ((ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC2_SHIFT) \
+ | (ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC1_SHIFT))
+#define ES8326_ADC_DMIC ((ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC2_SHIFT) \
+ | (ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC1_SHIFT))
+/* ES8326_ADC2_SRC */
+#define ES8326_ADC3_SHIFT 0
+#define ES8326_ADC4_SHIFT 3
+
+/* ES8326_HP_DET */
+#define ES8326_HP_DET_SRC_PIN27 (1 << 5)
+#define ES8326_HP_DET_SRC_PIN9 (1 << 4)
+#define ES8326_HP_DET_JACK_POL (1 << 3)
+#define ES8326_HP_DET_BUTTON_POL (1 << 2)
+#define ES8326_HP_TYPE_OMTP (3 << 0)
+#define ES8326_HP_TYPE_CTIA (2 << 0)
+#define ES8326_HP_TYPE_AUTO (1 << 0)
+#define ES8326_HP_TYPE_AUTO_INV (0 << 0)
+
+/* ES8326_SDINOUT1_IO */
+#define ES8326_IO_INPUT (0 << 0)
+#define ES8326_IO_SDIN_SLOT0 (1 << 0)
+#define ES8326_IO_SDIN_SLOT1 (2 << 0)
+#define ES8326_IO_SDIN_SLOT2 (3 << 0)
+#define ES8326_IO_SDIN_SLOT7 (8 << 0)
+#define ES8326_IO_DMIC_CLK (9 << 0)
+#define ES8326_IO_DMIC_CLK_INV (0x0a << 0)
+#define ES8326_IO_SDOUT2 (0x0b << 0)
+#define ES8326_IO_LOW (0x0e << 0)
+#define ES8326_IO_HIGH (0x0f << 0)
+#define ES8326_ADC2DAC (1 << 3)
+#define ES8326_SDINOUT1_SHIFT 4
+
+/* ES8326_SDINOUT23_IO */
+#define ES8326_SDINOUT2_SHIFT 4
+#define ES8326_SDINOUT3_SHIFT 0
+
+/* ES8326_HP_DETECT */
+#define ES8326_HPINSERT_FLAG (1 << 1)
+#define ES8326_HPBUTTON_FLAG (1 << 0)
+
+/* ES8326_CHIP_VERSION 0xFF */
+#define ES8326_VERSION_B (1 << 0)
+
+#endif
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
index ad20a3dff9b7..61e8e9be6b8d 100644
--- a/sound/soc/codecs/hda.c
+++ b/sound/soc/codecs/hda.c
@@ -224,9 +224,6 @@ static int hda_codec_probe(struct snd_soc_component *component)
goto err;
}
- /* configure codec for 1:1 PCM:DAI mapping */
- codec->mst_no_extra_pcms = 1;
-
ret = snd_hda_codec_parse_pcms(codec);
if (ret < 0) {
dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 8debcee59224..8af434e14bfb 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -246,7 +246,7 @@ static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream,
return -EINVAL;
hda_stream = &pcm->stream[substream->stream];
- snd_hda_codec_cleanup(&hda_pvt->codec, hda_stream, substream);
+ snd_hda_codec_cleanup(hda_pvt->codec, hda_stream, substream);
return 0;
}
@@ -264,7 +264,7 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream,
int ret = 0;
hda_pvt = snd_soc_component_get_drvdata(component);
- hdev = &hda_pvt->codec.core;
+ hdev = &hda_pvt->codec->core;
pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
if (!pcm)
return -EINVAL;
@@ -274,7 +274,7 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream,
stream = hda_pvt->pcm[dai->id].stream_tag[substream->stream];
format_val = hda_pvt->pcm[dai->id].format_val[substream->stream];
- ret = snd_hda_codec_prepare(&hda_pvt->codec, hda_stream,
+ ret = snd_hda_codec_prepare(hda_pvt->codec, hda_stream,
stream, format_val, substream);
if (ret < 0)
dev_err(&hdev->dev, "codec prepare failed %d\n", ret);
@@ -299,7 +299,7 @@ static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
hda_stream = &pcm->stream[substream->stream];
- return hda_stream->ops.open(hda_stream, &hda_pvt->codec, substream);
+ return hda_stream->ops.open(hda_stream, hda_pvt->codec, substream);
}
static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
@@ -317,7 +317,7 @@ static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
hda_stream = &pcm->stream[substream->stream];
- hda_stream->ops.close(hda_stream, &hda_pvt->codec, substream);
+ hda_stream->ops.close(hda_stream, hda_pvt->codec, substream);
snd_hda_codec_pcm_put(pcm);
}
@@ -325,7 +325,7 @@ static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
struct snd_soc_dai *dai)
{
- struct hda_codec *hcodec = &hda_pvt->codec;
+ struct hda_codec *hcodec = hda_pvt->codec;
struct hda_pcm *cpcm;
const char *pcm_name;
@@ -394,8 +394,8 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
snd_soc_component_get_drvdata(component);
struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(component);
- struct hdac_device *hdev = &hda_pvt->codec.core;
- struct hda_codec *hcodec = &hda_pvt->codec;
+ struct hdac_device *hdev = &hda_pvt->codec->core;
+ struct hda_codec *hcodec = hda_pvt->codec;
struct hdac_ext_link *hlink;
hda_codec_patch_t patch;
int ret;
@@ -461,9 +461,6 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
dev_dbg(&hdev->dev, "no patch file found\n");
}
- /* configure codec for 1:1 PCM:DAI mapping */
- hcodec->mst_no_extra_pcms = 1;
-
ret = snd_hda_codec_parse_pcms(hcodec);
if (ret < 0) {
dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
@@ -515,8 +512,8 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
{
struct hdac_hda_priv *hda_pvt =
snd_soc_component_get_drvdata(component);
- struct hdac_device *hdev = &hda_pvt->codec.core;
- struct hda_codec *codec = &hda_pvt->codec;
+ struct hdac_device *hdev = &hda_pvt->codec->core;
+ 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));
@@ -584,7 +581,6 @@ static const struct snd_soc_component_driver hdac_hda_codec = {
static int hdac_hda_dev_probe(struct hdac_device *hdev)
{
struct hdac_ext_link *hlink;
- struct hdac_hda_priv *hda_pvt;
int ret;
/* hold the ref while we probe */
@@ -595,10 +591,6 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev)
}
snd_hdac_ext_bus_link_get(hdev->bus, hlink);
- hda_pvt = hdac_to_hda_priv(hdev);
- if (!hda_pvt)
- return -ENOMEM;
-
/* ASoC specific initialization */
ret = devm_snd_soc_register_component(&hdev->dev,
&hdac_hda_codec, hdac_hda_dais,
@@ -608,7 +600,6 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev)
return ret;
}
- dev_set_drvdata(&hdev->dev, hda_pvt);
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
return ret;
diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h
index d0efc5e254ae..fc19c34ca00e 100644
--- a/sound/soc/codecs/hdac_hda.h
+++ b/sound/soc/codecs/hdac_hda.h
@@ -23,7 +23,7 @@ struct hdac_hda_pcm {
};
struct hdac_hda_priv {
- struct hda_codec codec;
+ struct hda_codec *codec;
struct hdac_hda_pcm pcm[HDAC_LAST_DAI_ID];
bool need_display_power;
};
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 5679102de91f..0b1cdb2d6049 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -20,10 +20,6 @@
#define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1
-struct hdmi_codec_channel_map_table {
- unsigned char map; /* ALSA API channel map position */
-};
-
/*
* CEA speaker placement for HDMI 1.4:
*
@@ -827,7 +823,7 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai)
if (ret)
return ret;
- daifmt = kzalloc(sizeof(*daifmt), GFP_KERNEL);
+ daifmt = devm_kzalloc(dai->dev, sizeof(*daifmt), GFP_KERNEL);
if (!daifmt)
return -ENOMEM;
@@ -894,17 +890,10 @@ static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai)
return 0;
}
-static int hdmi_codec_dai_remove(struct snd_soc_dai *dai)
-{
- kfree(dai->playback_dma_data);
- return 0;
-}
-
static const struct snd_soc_dai_driver hdmi_i2s_dai = {
.name = "i2s-hifi",
.id = DAI_ID_I2S,
.probe = hdmi_dai_probe,
- .remove = hdmi_codec_dai_remove,
.playback = {
.stream_name = "I2S Playback",
.channels_min = 2,
@@ -929,7 +918,6 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
.name = "spdif-hifi",
.id = DAI_ID_SPDIF,
.probe = hdmi_dai_spdif_probe,
- .remove = hdmi_codec_dai_remove,
.playback = {
.stream_name = "SPDIF Playback",
.channels_min = 2,
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
index 3143f9cd7277..a9ef9d5ffcc5 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -596,7 +596,6 @@ struct rx_macro {
int rx_port_value[RX_MACRO_PORTS_MAX];
u16 prim_int_users[INTERP_MAX];
int rx_mclk_users;
- bool reset_swr;
int clsh_users;
int rx_mclk_cnt;
bool is_ear_mode_on;
@@ -3442,18 +3441,15 @@ static int swclk_gate_enable(struct clk_hw *hw)
}
rx_macro_mclk_enable(rx, true);
- if (rx->reset_swr)
- regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
- CDC_RX_SWR_RESET_MASK,
- CDC_RX_SWR_RESET);
+ regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
+ CDC_RX_SWR_RESET_MASK,
+ CDC_RX_SWR_RESET);
regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
CDC_RX_SWR_CLK_EN_MASK, 1);
- if (rx->reset_swr)
- regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
- CDC_RX_SWR_RESET_MASK, 0);
- rx->reset_swr = false;
+ regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
+ CDC_RX_SWR_RESET_MASK, 0);
return 0;
}
@@ -3579,7 +3575,6 @@ static int rx_macro_probe(struct platform_device *pdev)
dev_set_drvdata(dev, rx);
- rx->reset_swr = true;
rx->dev = dev;
/* set MCLK and NPL rates */
@@ -3659,6 +3654,8 @@ static int rx_macro_remove(struct platform_device *pdev)
static const struct of_device_id rx_macro_dt_match[] = {
{ .compatible = "qcom,sc7280-lpass-rx-macro" },
{ .compatible = "qcom,sm8250-lpass-rx-macro" },
+ { .compatible = "qcom,sm8450-lpass-rx-macro" },
+ { .compatible = "qcom,sc8280xp-lpass-rx-macro" },
{ }
};
MODULE_DEVICE_TABLE(of, rx_macro_dt_match);
@@ -3701,7 +3698,6 @@ static int __maybe_unused rx_macro_runtime_resume(struct device *dev)
}
regcache_cache_only(rx->regmap, false);
regcache_sync(rx->regmap);
- rx->reset_swr = true;
return 0;
err_fsgen:
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
index 55503ba480bb..ee15cf6b98bb 100644
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -259,7 +259,7 @@ struct tx_macro {
struct tx_mute_work tx_mute_dwork[NUM_DECIMATORS];
unsigned long active_ch_mask[TX_MACRO_MAX_DAIS];
unsigned long active_ch_cnt[TX_MACRO_MAX_DAIS];
- unsigned long active_decimator[TX_MACRO_MAX_DAIS];
+ int active_decimator[TX_MACRO_MAX_DAIS];
struct regmap *regmap;
struct clk *mclk;
struct clk *npl;
@@ -268,7 +268,6 @@ struct tx_macro {
struct clk *fsgen;
struct clk_hw hw;
bool dec_active[NUM_DECIMATORS];
- bool reset_swr;
int tx_mclk_users;
u16 dmic_clk_div;
bool bcs_enable;
@@ -823,17 +822,23 @@ static int tx_macro_tx_mixer_put(struct snd_kcontrol *kcontrol,
struct tx_macro *tx = snd_soc_component_get_drvdata(component);
if (enable) {
+ if (tx->active_decimator[dai_id] == dec_id)
+ return 0;
+
set_bit(dec_id, &tx->active_ch_mask[dai_id]);
tx->active_ch_cnt[dai_id]++;
tx->active_decimator[dai_id] = dec_id;
} else {
+ if (tx->active_decimator[dai_id] == -1)
+ return 0;
+
tx->active_ch_cnt[dai_id]--;
clear_bit(dec_id, &tx->active_ch_mask[dai_id]);
tx->active_decimator[dai_id] = -1;
}
snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update);
- return 0;
+ return 1;
}
static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
@@ -1019,9 +1024,12 @@ static int tx_macro_dec_mode_put(struct snd_kcontrol *kcontrol,
int path = e->shift_l;
struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+ if (tx->dec_mode[path] == value)
+ return 0;
+
tx->dec_mode[path] = value;
- return 0;
+ return 1;
}
static int tx_macro_get_bcs(struct snd_kcontrol *kcontrol,
@@ -1118,6 +1126,10 @@ static int tx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
struct tx_macro *tx = snd_soc_component_get_drvdata(component);
u16 decimator;
+ /* active decimator not set yet */
+ if (tx->active_decimator[dai->id] == -1)
+ return 0;
+
decimator = tx->active_decimator[dai->id];
if (mute)
@@ -1702,18 +1714,14 @@ static int swclk_gate_enable(struct clk_hw *hw)
}
tx_macro_mclk_enable(tx, true);
- if (tx->reset_swr)
- regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
- CDC_TX_SWR_RESET_MASK,
- CDC_TX_SWR_RESET_ENABLE);
+ regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+ CDC_TX_SWR_RESET_MASK, CDC_TX_SWR_RESET_ENABLE);
regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
CDC_TX_SWR_CLK_EN_MASK,
CDC_TX_SWR_CLK_ENABLE);
- if (tx->reset_swr)
- regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
- CDC_TX_SWR_RESET_MASK, 0x0);
- tx->reset_swr = false;
+ regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+ CDC_TX_SWR_RESET_MASK, 0x0);
return 0;
}
@@ -1855,7 +1863,6 @@ static int tx_macro_probe(struct platform_device *pdev)
dev_set_drvdata(dev, tx);
- tx->reset_swr = true;
tx->dev = dev;
/* set MCLK and NPL rates */
@@ -1970,7 +1977,6 @@ static int __maybe_unused tx_macro_runtime_resume(struct device *dev)
regcache_cache_only(tx->regmap, false);
regcache_sync(tx->regmap);
- tx->reset_swr = true;
return 0;
err_fsgen:
@@ -1988,6 +1994,8 @@ static const struct dev_pm_ops tx_macro_pm_ops = {
static const struct of_device_id tx_macro_dt_match[] = {
{ .compatible = "qcom,sc7280-lpass-tx-macro" },
{ .compatible = "qcom,sm8250-lpass-tx-macro" },
+ { .compatible = "qcom,sm8450-lpass-tx-macro" },
+ { .compatible = "qcom,sc8280xp-lpass-tx-macro" },
{ }
};
MODULE_DEVICE_TABLE(of, tx_macro_dt_match);
diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c
index 1ea10dc70748..b0b6cf29cba3 100644
--- a/sound/soc/codecs/lpass-va-macro.c
+++ b/sound/soc/codecs/lpass-va-macro.c
@@ -23,7 +23,12 @@
#define CDC_VA_MCLK_CONTROL_EN BIT(0)
#define CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL (0x0004)
#define CDC_VA_FS_CONTROL_EN BIT(0)
+#define CDC_VA_FS_COUNTER_CLR BIT(1)
#define CDC_VA_CLK_RST_CTRL_SWR_CONTROL (0x0008)
+#define CDC_VA_SWR_RESET_MASK BIT(1)
+#define CDC_VA_SWR_RESET_ENABLE BIT(1)
+#define CDC_VA_SWR_CLK_EN_MASK BIT(0)
+#define CDC_VA_SWR_CLK_ENABLE BIT(0)
#define CDC_VA_TOP_CSR_TOP_CFG0 (0x0080)
#define CDC_VA_FS_BROADCAST_EN BIT(1)
#define CDC_VA_TOP_CSR_DMIC0_CTL (0x0084)
@@ -65,6 +70,8 @@
#define CDC_VA_TOP_CSR_SWR_MIC_CTL0 (0x00D0)
#define CDC_VA_TOP_CSR_SWR_MIC_CTL1 (0x00D4)
#define CDC_VA_TOP_CSR_SWR_MIC_CTL2 (0x00D8)
+#define CDC_VA_SWR_MIC_CLK_SEL_0_1_MASK (0xEE)
+#define CDC_VA_SWR_MIC_CLK_SEL_0_1_DIV1 (0xCC)
#define CDC_VA_TOP_CSR_SWR_CTRL (0x00DC)
#define CDC_VA_INP_MUX_ADC_MUX0_CFG0 (0x0100)
#define CDC_VA_INP_MUX_ADC_MUX0_CFG1 (0x0104)
@@ -193,6 +200,7 @@ struct va_macro {
unsigned long active_ch_mask[VA_MACRO_MAX_DAIS];
unsigned long active_ch_cnt[VA_MACRO_MAX_DAIS];
u16 dmic_clk_div;
+ bool has_swr_master;
int dec_mode[VA_MACRO_NUM_DECIMATORS];
struct regmap *regmap;
@@ -215,6 +223,18 @@ struct va_macro {
#define to_va_macro(_hw) container_of(_hw, struct va_macro, hw)
+struct va_macro_data {
+ bool has_swr_master;
+};
+
+static const struct va_macro_data sm8250_va_data = {
+ .has_swr_master = false,
+};
+
+static const struct va_macro_data sm8450_va_data = {
+ .has_swr_master = true,
+};
+
static bool va_is_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -324,6 +344,9 @@ static bool va_is_rw_register(struct device *dev, unsigned int reg)
case CDC_VA_TOP_CSR_DMIC2_CTL:
case CDC_VA_TOP_CSR_DMIC3_CTL:
case CDC_VA_TOP_CSR_DMIC_CFG:
+ case CDC_VA_TOP_CSR_SWR_MIC_CTL0:
+ case CDC_VA_TOP_CSR_SWR_MIC_CTL1:
+ case CDC_VA_TOP_CSR_SWR_MIC_CTL2:
case CDC_VA_TOP_CSR_DEBUG_BUS:
case CDC_VA_TOP_CSR_DEBUG_EN:
case CDC_VA_TOP_CSR_TX_I2S_CTL:
@@ -423,9 +446,12 @@ static int va_clk_rsc_fs_gen_request(struct va_macro *va, bool enable)
regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_MCLK_CONTROL,
CDC_VA_MCLK_CONTROL_EN,
CDC_VA_MCLK_CONTROL_EN);
-
+ /* clear the fs counter */
regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL,
- CDC_VA_FS_CONTROL_EN,
+ CDC_VA_FS_CONTROL_EN | CDC_VA_FS_COUNTER_CLR,
+ CDC_VA_FS_CONTROL_EN | CDC_VA_FS_COUNTER_CLR);
+ regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL,
+ CDC_VA_FS_CONTROL_EN | CDC_VA_FS_COUNTER_CLR,
CDC_VA_FS_CONTROL_EN);
regmap_update_bits(regmap, CDC_VA_TOP_CSR_TOP_CFG0,
@@ -1302,12 +1328,36 @@ static const struct snd_soc_component_driver va_macro_component_drv = {
static int fsgen_gate_enable(struct clk_hw *hw)
{
- return va_macro_mclk_enable(to_va_macro(hw), true);
+ struct va_macro *va = to_va_macro(hw);
+ struct regmap *regmap = va->regmap;
+ int ret;
+
+ ret = va_macro_mclk_enable(va, true);
+ if (!va->has_swr_master)
+ return ret;
+
+ regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
+ CDC_VA_SWR_RESET_MASK, CDC_VA_SWR_RESET_ENABLE);
+
+ regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
+ CDC_VA_SWR_CLK_EN_MASK,
+ CDC_VA_SWR_CLK_ENABLE);
+ regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
+ CDC_VA_SWR_RESET_MASK, 0x0);
+
+ return ret;
}
static void fsgen_gate_disable(struct clk_hw *hw)
{
- va_macro_mclk_enable(to_va_macro(hw), false);
+ struct va_macro *va = to_va_macro(hw);
+ struct regmap *regmap = va->regmap;
+
+ if (va->has_swr_master)
+ regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
+ CDC_VA_SWR_CLK_EN_MASK, 0x0);
+
+ va_macro_mclk_enable(va, false);
}
static int fsgen_gate_is_enabled(struct clk_hw *hw)
@@ -1401,6 +1451,7 @@ undefined_rate:
static int va_macro_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ const struct va_macro_data *data;
struct va_macro *va;
void __iomem *base;
u32 sample_rate = 0;
@@ -1455,6 +1506,9 @@ static int va_macro_probe(struct platform_device *pdev)
dev_set_drvdata(dev, va);
+ data = of_device_get_match_data(dev);
+ va->has_swr_master = data->has_swr_master;
+
/* mclk rate */
clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ);
@@ -1480,6 +1534,20 @@ static int va_macro_probe(struct platform_device *pdev)
goto err_clkout;
}
+ if (va->has_swr_master) {
+ /* Set default CLK div to 1 */
+ regmap_update_bits(va->regmap, CDC_VA_TOP_CSR_SWR_MIC_CTL0,
+ CDC_VA_SWR_MIC_CLK_SEL_0_1_MASK,
+ CDC_VA_SWR_MIC_CLK_SEL_0_1_DIV1);
+ regmap_update_bits(va->regmap, CDC_VA_TOP_CSR_SWR_MIC_CTL1,
+ CDC_VA_SWR_MIC_CLK_SEL_0_1_MASK,
+ CDC_VA_SWR_MIC_CLK_SEL_0_1_DIV1);
+ regmap_update_bits(va->regmap, CDC_VA_TOP_CSR_SWR_MIC_CTL2,
+ CDC_VA_SWR_MIC_CLK_SEL_0_1_MASK,
+ CDC_VA_SWR_MIC_CLK_SEL_0_1_DIV1);
+
+ }
+
ret = devm_snd_soc_register_component(dev, &va_macro_component_drv,
va_macro_dais,
ARRAY_SIZE(va_macro_dais));
@@ -1554,8 +1622,10 @@ static const struct dev_pm_ops va_macro_pm_ops = {
};
static const struct of_device_id va_macro_dt_match[] = {
- { .compatible = "qcom,sc7280-lpass-va-macro" },
- { .compatible = "qcom,sm8250-lpass-va-macro" },
+ { .compatible = "qcom,sc7280-lpass-va-macro", .data = &sm8250_va_data },
+ { .compatible = "qcom,sm8250-lpass-va-macro", .data = &sm8250_va_data },
+ { .compatible = "qcom,sm8450-lpass-va-macro", .data = &sm8450_va_data },
+ { .compatible = "qcom,sc8280xp-lpass-va-macro", .data = &sm8450_va_data },
{}
};
MODULE_DEVICE_TABLE(of, va_macro_dt_match);
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index 27da6c6c3c5a..5e0abefe7cce 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -338,7 +338,6 @@ struct wsa_macro {
int ec_hq[WSA_MACRO_RX1 + 1];
u16 prim_int_users[WSA_MACRO_RX1 + 1];
u16 wsa_mclk_users;
- bool reset_swr;
unsigned long active_ch_mask[WSA_MACRO_MAX_DAIS];
unsigned long active_ch_cnt[WSA_MACRO_MAX_DAIS];
int rx_port_value[WSA_MACRO_RX_MAX];
@@ -2271,23 +2270,16 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
wsa_macro_mclk_enable(wsa, true);
/* reset swr ip */
- if (wsa->reset_swr)
- regmap_update_bits(regmap,
- CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
- CDC_WSA_SWR_RST_EN_MASK,
- CDC_WSA_SWR_RST_ENABLE);
+ regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+ CDC_WSA_SWR_RST_EN_MASK, CDC_WSA_SWR_RST_ENABLE);
regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
CDC_WSA_SWR_CLK_EN_MASK,
CDC_WSA_SWR_CLK_ENABLE);
/* Bring out of reset */
- if (wsa->reset_swr)
- regmap_update_bits(regmap,
- CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
- CDC_WSA_SWR_RST_EN_MASK,
- CDC_WSA_SWR_RST_DISABLE);
- wsa->reset_swr = false;
+ regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
+ CDC_WSA_SWR_RST_EN_MASK, CDC_WSA_SWR_RST_DISABLE);
} else {
regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
CDC_WSA_SWR_CLK_EN_MASK, 0);
@@ -2431,7 +2423,6 @@ static int wsa_macro_probe(struct platform_device *pdev)
dev_set_drvdata(dev, wsa);
- wsa->reset_swr = true;
wsa->dev = dev;
/* set MCLK and NPL rates */
@@ -2561,6 +2552,8 @@ static const struct dev_pm_ops wsa_macro_pm_ops = {
static const struct of_device_id wsa_macro_dt_match[] = {
{.compatible = "qcom,sc7280-lpass-wsa-macro"},
{.compatible = "qcom,sm8250-lpass-wsa-macro"},
+ {.compatible = "qcom,sm8450-lpass-wsa-macro"},
+ {.compatible = "qcom,sc8280xp-lpass-wsa-macro" },
{}
};
MODULE_DEVICE_TABLE(of, wsa_macro_dt_match);
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 5435a49604cf..405ec16be2b6 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -474,6 +474,9 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = {
max98088_mic2pre_get, max98088_mic2pre_set,
max98088_micboost_tlv),
+ SOC_SINGLE("Noise Gate Threshold", M98088_REG_40_MICAGC_THRESH,
+ 4, 15, 0),
+
SOC_SINGLE("INA Volume", M98088_REG_37_LVL_INA, 0, 7, 1),
SOC_SINGLE("INB Volume", M98088_REG_38_LVL_INB, 0, 7, 1),
@@ -1746,7 +1749,6 @@ MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
static int max98088_i2c_probe(struct i2c_client *i2c)
{
struct max98088_priv *max98088;
- int ret;
const struct i2c_device_id *id;
max98088 = devm_kzalloc(&i2c->dev, sizeof(struct max98088_priv),
@@ -1769,9 +1771,8 @@ static int max98088_i2c_probe(struct i2c_client *i2c)
i2c_set_clientdata(i2c, max98088);
max98088->pdata = i2c->dev.platform_data;
- ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_max98088,
+ return devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_max98088,
&max98088_dai[0], 2);
- return ret;
}
#if defined(CONFIG_OF)
diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c
index 97b64477dde6..899965b19d12 100644
--- a/sound/soc/codecs/max98373-sdw.c
+++ b/sound/soc/codecs/max98373-sdw.c
@@ -281,6 +281,8 @@ static __maybe_unused int max98373_resume(struct device *dev)
msecs_to_jiffies(MAX98373_PROBE_TIMEOUT));
if (!time) {
dev_err(dev, "Initialization not complete, timed out\n");
+ sdw_show_ping_status(slave->bus, true);
+
return -ETIMEDOUT;
}
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
index 5c08166a8dc6..7a5260ff8d6b 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -161,8 +161,6 @@ static struct reg_default max98390_reg_defaults[] = {
{MAX98390_R23FF_GLOBAL_EN, 0x00},
};
-static int max98390_dsm_calibrate(struct snd_soc_component *component);
-
static int max98390_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_component *component = codec_dai->component;
@@ -635,10 +633,48 @@ static int max98390_dsm_calib_get(struct snd_kcontrol *kcontrol,
static int max98390_dsm_calib_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct max98390_priv *max98390 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ unsigned int rdc, rdc_cal_result, rdc_integer, rdc_factor, temp, val;
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ regmap_read(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, &val);
+ if (!val) {
+ /* Enable the codec for the duration of calibration readout */
+ regmap_update_bits(max98390->regmap, MAX98390_R203A_AMP_EN,
+ MAX98390_AMP_EN_MASK, 1);
+ regmap_update_bits(max98390->regmap, MAX98390_R23FF_GLOBAL_EN,
+ MAX98390_GLOBAL_EN_MASK, 1);
+ }
+
+ regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE1, &rdc);
+ regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE0, &rdc_cal_result);
+ regmap_read(max98390->regmap, MAX98390_MEAS_ADC_CH2_READ, &temp);
+
+ if (!val) {
+ /* Disable the codec if it was disabled */
+ regmap_update_bits(max98390->regmap, MAX98390_R23FF_GLOBAL_EN,
+ MAX98390_GLOBAL_EN_MASK, 0);
+ regmap_update_bits(max98390->regmap, MAX98390_R203A_AMP_EN,
+ MAX98390_AMP_EN_MASK, 0);
+ }
+
+ snd_soc_dapm_mutex_unlock(dapm);
- max98390_dsm_calibrate(component);
+ rdc_cal_result |= (rdc << 8) & 0x0000FFFF;
+ if (rdc_cal_result)
+ max98390->ref_rdc_value = 268435456U / rdc_cal_result;
+
+ max98390->ambient_temp_value = temp * 52 - 1188;
+
+ rdc_integer = rdc_cal_result * 937 / 65536;
+ rdc_factor = ((rdc_cal_result * 937 * 100) / 65536) - (rdc_integer * 100);
+
+ dev_info(component->dev,
+ "rdc resistance about %d.%02d ohm, reg=0x%X temp reg=0x%X\n",
+ rdc_integer, rdc_factor, rdc_cal_result, temp);
return 0;
}
@@ -819,40 +855,6 @@ err:
return ret;
}
-static int max98390_dsm_calibrate(struct snd_soc_component *component)
-{
- unsigned int rdc, rdc_cal_result, temp;
- unsigned int rdc_integer, rdc_factor;
- struct max98390_priv *max98390 =
- snd_soc_component_get_drvdata(component);
-
- regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x81);
- regmap_write(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, 0x01);
-
- regmap_read(max98390->regmap,
- THERMAL_RDC_RD_BACK_BYTE1, &rdc);
- regmap_read(max98390->regmap,
- THERMAL_RDC_RD_BACK_BYTE0, &rdc_cal_result);
- rdc_cal_result |= (rdc << 8) & 0x0000FFFF;
- if (rdc_cal_result)
- max98390->ref_rdc_value = 268435456U / rdc_cal_result;
-
- regmap_read(max98390->regmap, MAX98390_MEAS_ADC_CH2_READ, &temp);
- max98390->ambient_temp_value = temp * 52 - 1188;
-
- rdc_integer = rdc_cal_result * 937 / 65536;
- rdc_factor = ((rdc_cal_result * 937 * 100) / 65536)
- - (rdc_integer * 100);
-
- dev_info(component->dev, "rdc resistance about %d.%02d ohm, reg=0x%X temp reg=0x%X\n",
- rdc_integer, rdc_factor, rdc_cal_result, temp);
-
- regmap_write(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, 0x00);
- regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x80);
-
- return 0;
-}
-
static void max98390_init_regs(struct snd_soc_component *component)
{
struct max98390_priv *max98390 =
diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c
index 364b4b7ee033..a7b6a23f2cd8 100644
--- a/sound/soc/codecs/max98396.c
+++ b/sound/soc/codecs/max98396.c
@@ -1483,6 +1483,87 @@ static int max98396_probe(struct snd_soc_component *component)
MAX98396_CLK_MON_AUTO_RESTART_MASK,
MAX98396_CLK_MON_AUTO_RESTART_MASK);
+ regmap_update_bits(max98396->regmap,
+ MAX98396_R203F_ENABLE_CTRLS,
+ MAX98396_CTRL_DMON_STUCK_EN_MASK,
+ max98396->dmon_stuck_enable ?
+ MAX98396_CTRL_DMON_STUCK_EN_MASK : 0);
+
+ regmap_update_bits(max98396->regmap,
+ MAX98396_R203F_ENABLE_CTRLS,
+ MAX98396_CTRL_DMON_MAG_EN_MASK,
+ max98396->dmon_mag_enable ?
+ MAX98396_CTRL_DMON_MAG_EN_MASK : 0);
+
+ switch (max98396->dmon_duration) {
+ case 64:
+ regmap_update_bits(max98396->regmap,
+ MAX98396_R2039_DATA_MON_CTRL,
+ MAX98396_DMON_DURATION_MASK, 0);
+ break;
+ case 256:
+ regmap_update_bits(max98396->regmap,
+ MAX98396_R2039_DATA_MON_CTRL,
+ MAX98396_DMON_DURATION_MASK, 1);
+ break;
+ case 1024:
+ regmap_update_bits(max98396->regmap,
+ MAX98396_R2039_DATA_MON_CTRL,
+ MAX98396_DMON_DURATION_MASK, 2);
+ break;
+ case 4096:
+ regmap_update_bits(max98396->regmap,
+ MAX98396_R2039_DATA_MON_CTRL,
+ MAX98396_DMON_DURATION_MASK, 3);
+ break;
+ default:
+ dev_err(component->dev, "Invalid DMON duration %d\n",
+ max98396->dmon_duration);
+ }
+
+ switch (max98396->dmon_stuck_threshold) {
+ case 15:
+ regmap_update_bits(max98396->regmap,
+ MAX98396_R2039_DATA_MON_CTRL,
+ MAX98396_DMON_STUCK_THRESH_MASK,
+ 0 << MAX98396_DMON_STUCK_THRESH_SHIFT);
+ break;
+ case 13:
+ regmap_update_bits(max98396->regmap,
+ MAX98396_R2039_DATA_MON_CTRL,
+ MAX98396_DMON_STUCK_THRESH_MASK,
+ 1 << MAX98396_DMON_STUCK_THRESH_SHIFT);
+ break;
+ case 22:
+ regmap_update_bits(max98396->regmap,
+ MAX98396_R2039_DATA_MON_CTRL,
+ MAX98396_DMON_STUCK_THRESH_MASK,
+ 2 << MAX98396_DMON_STUCK_THRESH_SHIFT);
+ break;
+ case 9:
+ regmap_update_bits(max98396->regmap,
+ MAX98396_R2039_DATA_MON_CTRL,
+ MAX98396_DMON_STUCK_THRESH_MASK,
+ 3 << MAX98396_DMON_STUCK_THRESH_SHIFT);
+ break;
+ default:
+ dev_err(component->dev, "Invalid DMON stuck threshold %d\n",
+ max98396->dmon_stuck_threshold);
+ }
+
+ switch (max98396->dmon_mag_threshold) {
+ case 2 ... 5:
+ regmap_update_bits(max98396->regmap,
+ MAX98396_R2039_DATA_MON_CTRL,
+ MAX98396_DMON_STUCK_THRESH_MASK,
+ (5 - max98396->dmon_mag_threshold)
+ << MAX98396_DMON_MAG_THRESH_SHIFT);
+ break;
+ default:
+ dev_err(component->dev, "Invalid DMON magnitude threshold %d\n",
+ max98396->dmon_mag_threshold);
+ }
+
/* Speaker Amplifier PCM RX Enable by default */
regmap_update_bits(max98396->regmap,
MAX98396_R205E_PCM_RX_EN,
@@ -1614,6 +1695,27 @@ static void max98396_read_device_property(struct device *dev,
max98396->bypass_slot = value & 0xF;
else
max98396->bypass_slot = 0;
+
+ max98396->dmon_stuck_enable =
+ device_property_read_bool(dev, "adi,dmon-stuck-enable");
+
+ if (!device_property_read_u32(dev, "adi,dmon-stuck-threshold-bits", &value))
+ max98396->dmon_stuck_threshold = value;
+ else
+ max98396->dmon_stuck_threshold = 15;
+
+ max98396->dmon_mag_enable =
+ device_property_read_bool(dev, "adi,dmon-magnitude-enable");
+
+ if (!device_property_read_u32(dev, "adi,dmon-magnitude-threshold-bits", &value))
+ max98396->dmon_mag_threshold = value;
+ else
+ max98396->dmon_mag_threshold = 5;
+
+ if (!device_property_read_u32(dev, "adi,dmon-duration-ms", &value))
+ max98396->dmon_duration = value;
+ else
+ max98396->dmon_duration = 64;
}
static void max98396_core_supplies_disable(void *priv)
diff --git a/sound/soc/codecs/max98396.h b/sound/soc/codecs/max98396.h
index 7278c779989a..d396aa3e698b 100644
--- a/sound/soc/codecs/max98396.h
+++ b/sound/soc/codecs/max98396.h
@@ -212,8 +212,17 @@
#define MAX98396_CLK_MON_AUTO_RESTART_MASK (0x1 << 0)
#define MAX98396_CLK_MON_AUTO_RESTART_SHIFT (0)
+/* MAX98396_R2039_DATA_MON_CTRL */
+#define MAX98396_DMON_MAG_THRESH_SHIFT (4)
+#define MAX98396_DMON_MAG_THRESH_MASK (0x3 << MAX98396_DMON_MAG_THRESH_SHIFT)
+#define MAX98396_DMON_STUCK_THRESH_SHIFT (2)
+#define MAX98396_DMON_STUCK_THRESH_MASK (0x3 << MAX98396_DMON_STUCK_THRESH_SHIFT)
+#define MAX98396_DMON_DURATION_MASK (0x3)
+
/* MAX98396_R203F_ENABLE_CTRLS */
#define MAX98396_CTRL_CMON_EN_SHIFT (0)
+#define MAX98396_CTRL_DMON_STUCK_EN_MASK (0x1 << 1)
+#define MAX98396_CTRL_DMON_MAG_EN_MASK (0x1 << 2)
/* MAX98396_R2041_PCM_MODE_CFG */
#define MAX98396_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3)
@@ -305,6 +314,11 @@ struct max98396_priv {
unsigned int i_slot;
unsigned int spkfb_slot;
unsigned int bypass_slot;
+ bool dmon_stuck_enable;
+ unsigned int dmon_stuck_threshold;
+ bool dmon_mag_enable;
+ unsigned int dmon_mag_threshold;
+ unsigned int dmon_duration;
bool interleave_mode;
bool tdm_mode;
int tdm_max_samplerate;
diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c
index c190628e2905..7f624854948c 100644
--- a/sound/soc/codecs/mt6359-accdet.c
+++ b/sound/soc/codecs/mt6359-accdet.c
@@ -965,7 +965,7 @@ static int mt6359_accdet_probe(struct platform_device *pdev)
mutex_init(&priv->res_lock);
priv->accdet_irq = platform_get_irq(pdev, 0);
- if (priv->accdet_irq) {
+ if (priv->accdet_irq >= 0) {
ret = devm_request_threaded_irq(&pdev->dev, priv->accdet_irq,
NULL, mt6359_accdet_irq,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
@@ -979,7 +979,7 @@ static int mt6359_accdet_probe(struct platform_device *pdev)
if (priv->caps & ACCDET_PMIC_EINT0) {
priv->accdet_eint0 = platform_get_irq(pdev, 1);
- if (priv->accdet_eint0) {
+ if (priv->accdet_eint0 >= 0) {
ret = devm_request_threaded_irq(&pdev->dev,
priv->accdet_eint0,
NULL, mt6359_accdet_irq,
@@ -994,7 +994,7 @@ static int mt6359_accdet_probe(struct platform_device *pdev)
}
} else if (priv->caps & ACCDET_PMIC_EINT1) {
priv->accdet_eint1 = platform_get_irq(pdev, 2);
- if (priv->accdet_eint1) {
+ if (priv->accdet_eint1 >= 0) {
ret = devm_request_threaded_irq(&pdev->dev,
priv->accdet_eint1,
NULL, mt6359_accdet_irq,
diff --git a/sound/soc/codecs/mt6660.c b/sound/soc/codecs/mt6660.c
index 4971cd0b90f8..554c33e8b62f 100644
--- a/sound/soc/codecs/mt6660.c
+++ b/sound/soc/codecs/mt6660.c
@@ -503,13 +503,17 @@ 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);
+ }
+
return ret;
+
probe_fail:
_mt6660_chip_power_on(chip, 0);
mutex_destroy(&chip->io_lock);
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index 1b63ff55d430..3eac7c92df88 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -1425,10 +1425,107 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return 0;
}
+/**
+ * nau8825_set_tdm_slot - configure DAI TDM.
+ * @dai: DAI
+ * @tx_mask: bitmask representing active TX slots.
+ * @rx_mask: bitmask representing active RX slots.
+ * @slots: Number of slots in use.
+ * @slot_width: Width in bits for each slot.
+ *
+ * Configures a DAI for TDM operation. Support TDM 4/8 slots.
+ * The limitation is DAC and ADC need shift 4 slots at 8 slots mode.
+ */
+static int nau8825_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;
+ struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+ unsigned int ctrl_val = 0, ctrl_offset = 0, value = 0, dac_s, adc_s;
+
+ if (slots != 4 && slots != 8) {
+ dev_err(nau8825->dev, "Only support 4 or 8 slots!\n");
+ return -EINVAL;
+ }
+
+ /* The driver is limited to 1-channel for ADC, and 2-channel for DAC on TDM mode */
+ if (hweight_long((unsigned long) tx_mask) != 1 ||
+ hweight_long((unsigned long) rx_mask) != 2) {
+ dev_err(nau8825->dev,
+ "The limitation is 1-channel for ADC, and 2-channel for DAC on TDM mode.\n");
+ return -EINVAL;
+ }
+
+ if (((tx_mask & 0xf) && (tx_mask & 0xf0)) ||
+ ((rx_mask & 0xf) && (rx_mask & 0xf0)) ||
+ ((tx_mask & 0xf) && (rx_mask & 0xf0)) ||
+ ((rx_mask & 0xf) && (tx_mask & 0xf0))) {
+ dev_err(nau8825->dev,
+ "Slot assignment of DAC and ADC need to set same interval.\n");
+ return -EINVAL;
+ }
+
+ /* The offset of fixed 4 slots for 8 slots support */
+ if (rx_mask & 0xf0) {
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
+ NAU8825_I2S_PCM_TS_EN_MASK, NAU8825_I2S_PCM_TS_EN);
+ regmap_read(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1, &value);
+ ctrl_val |= NAU8825_TDM_OFFSET_EN;
+ ctrl_offset = 4 * slot_width;
+ if (!(value & NAU8825_I2S_PCMB_MASK))
+ ctrl_offset += 1;
+ dac_s = (rx_mask & 0xf0) >> 4;
+ adc_s = fls((tx_mask & 0xf0) >> 4);
+ } else {
+ dac_s = rx_mask & 0xf;
+ adc_s = fls(tx_mask & 0xf);
+ }
+
+ ctrl_val |= NAU8825_TDM_MODE;
+
+ switch (dac_s) {
+ case 0x3:
+ ctrl_val |= 1 << NAU8825_TDM_DACR_RX_SFT;
+ break;
+ case 0x5:
+ ctrl_val |= 2 << NAU8825_TDM_DACR_RX_SFT;
+ break;
+ case 0x6:
+ ctrl_val |= 1 << NAU8825_TDM_DACL_RX_SFT;
+ ctrl_val |= 2 << NAU8825_TDM_DACR_RX_SFT;
+ break;
+ case 0x9:
+ ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT;
+ break;
+ case 0xa:
+ ctrl_val |= 1 << NAU8825_TDM_DACL_RX_SFT;
+ ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT;
+ break;
+ case 0xc:
+ ctrl_val |= 2 << NAU8825_TDM_DACL_RX_SFT;
+ ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ctrl_val |= adc_s - 1;
+
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_TDM_CTRL,
+ NAU8825_TDM_MODE | NAU8825_TDM_OFFSET_EN |
+ NAU8825_TDM_DACL_RX_MASK | NAU8825_TDM_DACR_RX_MASK |
+ NAU8825_TDM_TX_MASK, ctrl_val);
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_LEFT_TIME_SLOT,
+ NAU8825_TSLOT_L0_MASK, ctrl_offset);
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops nau8825_dai_ops = {
.startup = nau8825_dai_startup,
.hw_params = nau8825_hw_params,
.set_fmt = nau8825_set_dai_fmt,
+ .set_tdm_slot = nau8825_set_tdm_slot,
};
#define NAU8825_RATES SNDRV_PCM_RATE_8000_192000
@@ -1983,6 +2080,10 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
/* Disable short Frame Sync detection logic */
regmap_update_bits(regmap, NAU8825_REG_LEFT_TIME_SLOT,
NAU8825_DIS_FS_SHORT_DET, NAU8825_DIS_FS_SHORT_DET);
+ /* ADCDAT IO drive strength control */
+ regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP,
+ NAU8825_ADCOUT_DS_MASK,
+ nau8825->adcout_ds << NAU8825_ADCOUT_DS_SFT);
}
static const struct regmap_config nau8825_regmap_config = {
@@ -2521,6 +2622,7 @@ static void nau8825_print_device_properties(struct nau8825 *nau8825)
nau8825->jack_eject_debounce);
dev_dbg(dev, "crosstalk-enable: %d\n",
nau8825->xtalk_enable);
+ dev_dbg(dev, "adcout-drive-strong: %d\n", nau8825->adcout_ds);
}
static int nau8825_read_device_properties(struct device *dev,
@@ -2587,6 +2689,7 @@ static int nau8825_read_device_properties(struct device *dev,
nau8825->jack_eject_debounce = 0;
nau8825->xtalk_enable = device_property_read_bool(dev,
"nuvoton,crosstalk-enable");
+ nau8825->adcout_ds = device_property_read_bool(dev, "nuvoton,adcout-drive-strong");
nau8825->mclk = devm_clk_get(dev, "mclk");
if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) {
diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h
index 887bbff03ec6..d84191a7beb2 100644
--- a/sound/soc/codecs/nau8825.h
+++ b/sound/soc/codecs/nau8825.h
@@ -225,6 +225,15 @@
#define NAU8825_JKDET_PULL_EN (1 << 9) /* 0 - enable pull, 1 - disable */
#define NAU8825_JKDET_OUTPUT_EN (1 << 8) /* 0 - enable input, 1 - enable output */
+/* TDM_CTRL (0x1b) */
+#define NAU8825_TDM_MODE (0x1 << 15)
+#define NAU8825_TDM_OFFSET_EN (0x1 << 14)
+#define NAU8825_TDM_DACL_RX_SFT 6
+#define NAU8825_TDM_DACL_RX_MASK (0x3 << NAU8825_TDM_DACL_RX_SFT)
+#define NAU8825_TDM_DACR_RX_SFT 4
+#define NAU8825_TDM_DACR_RX_MASK (0x3 << NAU8825_TDM_DACR_RX_SFT)
+#define NAU8825_TDM_TX_MASK 0x3
+
/* I2S_PCM_CTRL1 (0x1c) */
#define NAU8825_I2S_BP_SFT 7
#define NAU8825_I2S_BP_MASK (1 << NAU8825_I2S_BP_SFT)
@@ -249,6 +258,9 @@
#define NAU8825_I2S_TRISTATE (1 << 15) /* 0 - normal mode, 1 - Hi-Z output */
#define NAU8825_I2S_LRC_DIV_SFT 12
#define NAU8825_I2S_LRC_DIV_MASK (0x3 << NAU8825_I2S_LRC_DIV_SFT)
+#define NAU8825_I2S_PCM_TS_EN_SFT 10
+#define NAU8825_I2S_PCM_TS_EN_MASK (1 << NAU8825_I2S_PCM_TS_EN_SFT)
+#define NAU8825_I2S_PCM_TS_EN (1 << NAU8825_I2S_PCM_TS_EN_SFT)
#define NAU8825_I2S_MS_SFT 3
#define NAU8825_I2S_MS_MASK (1 << NAU8825_I2S_MS_SFT)
#define NAU8825_I2S_MS_MASTER (1 << NAU8825_I2S_MS_SFT)
@@ -259,6 +271,8 @@
#define NAU8825_FS_ERR_CMP_SEL_SFT 14
#define NAU8825_FS_ERR_CMP_SEL_MASK (0x3 << NAU8825_FS_ERR_CMP_SEL_SFT)
#define NAU8825_DIS_FS_SHORT_DET (1 << 13)
+#define NAU8825_TSLOT_L0_MASK 0x3ff
+#define NAU8825_TSLOT_R0_MASK 0x3ff
/* BIQ_CTRL (0x20) */
#define NAU8825_BIQ_WRT_SFT 4
@@ -418,6 +432,8 @@
#define NAU8825_POWERUP_HP_DRV_L (1 << 0)
/* CHARGE_PUMP (0x80) */
+#define NAU8825_ADCOUT_DS_SFT 12
+#define NAU8825_ADCOUT_DS_MASK (1 << NAU8825_ADCOUT_DS_SFT)
#define NAU8825_JAMNODCLOW (1 << 10)
#define NAU8825_POWER_DOWN_DACR (1 << 9)
#define NAU8825_POWER_DOWN_DACL (1 << 8)
@@ -477,6 +493,7 @@ struct nau8825 {
int imp_rms[NAU8825_XTALK_IMM];
int xtalk_enable;
bool xtalk_baktab_initialized; /* True if initialized. */
+ bool adcout_ds;
};
int nau8825_enable_jack_detect(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c
index 0be6e72ff5a9..5c29416aa781 100644
--- a/sound/soc/codecs/rt1308-sdw.c
+++ b/sound/soc/codecs/rt1308-sdw.c
@@ -749,6 +749,8 @@ static int __maybe_unused rt1308_dev_resume(struct device *dev)
msecs_to_jiffies(RT1308_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ sdw_show_ping_status(slave->bus, true);
+
return -ETIMEDOUT;
}
diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
index e53396606a1c..ed0a11436362 100644
--- a/sound/soc/codecs/rt1316-sdw.c
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -734,6 +734,8 @@ static int __maybe_unused rt1316_dev_resume(struct device *dev)
msecs_to_jiffies(RT1316_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ sdw_show_ping_status(slave->bus, true);
+
return -ETIMEDOUT;
}
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index f04e18c32489..c1a94229dc7e 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -793,6 +793,8 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev)
msecs_to_jiffies(RT5682_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ sdw_show_ping_status(slave->bus, true);
+
return -ETIMEDOUT;
}
diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c
index ce6932a26403..466a37f3500c 100644
--- a/sound/soc/codecs/rt5682s.c
+++ b/sound/soc/codecs/rt5682s.c
@@ -739,6 +739,7 @@ static void rt5682s_disable_push_button_irq(struct snd_soc_component *component)
*/
static int rt5682s_headset_detect(struct snd_soc_component *component, int jack_insert)
{
+ struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
unsigned int val, count;
int jack_type = 0;
@@ -805,12 +806,10 @@ static int rt5682s_headset_detect(struct snd_soc_component *component, int jack_
snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1,
RT5682S_TRIG_JD_MASK, RT5682S_TRIG_JD_LOW);
- if (!snd_soc_dapm_get_pin_status(&component->dapm, "MICBIAS"))
- snd_soc_component_update_bits(component,
- RT5682S_PWR_ANLG_1, RT5682S_PWR_MB, 0);
- if (!snd_soc_dapm_get_pin_status(&component->dapm, "Vref2"))
+ if (!rt5682s->wclk_enabled) {
snd_soc_component_update_bits(component,
- RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2, 0);
+ RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2 | RT5682S_PWR_MB, 0);
+ }
snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3,
RT5682S_PWR_CBJ, 0);
@@ -845,6 +844,7 @@ static void rt5682s_jack_detect_handler(struct work_struct *work)
snd_soc_dapm_mutex_lock(dapm);
mutex_lock(&rt5682s->calibrate_mutex);
+ mutex_lock(&rt5682s->wclk_mutex);
val = snd_soc_component_read(rt5682s->component, RT5682S_AJD1_CTRL)
& RT5682S_JDH_RS_MASK;
@@ -900,6 +900,7 @@ static void rt5682s_jack_detect_handler(struct work_struct *work)
rt5682s->irq_work_delay_time = 50;
}
+ mutex_unlock(&rt5682s->wclk_mutex);
mutex_unlock(&rt5682s->calibrate_mutex);
snd_soc_dapm_mutex_unlock(dapm);
@@ -1154,29 +1155,52 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
return 0;
}
-static int set_filter_clk(struct snd_soc_dapm_widget *w,
+
+static int rt5682s_set_pllb_power(struct rt5682s_priv *rt5682s, int on)
+{
+ struct snd_soc_component *component = rt5682s->component;
+
+ if (on) {
+ snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3,
+ RT5682S_PWR_LDO_PLLB | RT5682S_PWR_BIAS_PLLB | RT5682S_PWR_PLLB,
+ RT5682S_PWR_LDO_PLLB | RT5682S_PWR_BIAS_PLLB | RT5682S_PWR_PLLB);
+ snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3,
+ RT5682S_RSTB_PLLB, RT5682S_RSTB_PLLB);
+ } else {
+ snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3,
+ RT5682S_PWR_LDO_PLLB | RT5682S_PWR_BIAS_PLLB |
+ RT5682S_RSTB_PLLB | RT5682S_PWR_PLLB, 0);
+ }
+
+ return 0;
+}
+
+static int set_pllb_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 rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
- int ref, val, reg, idx;
- static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48};
- static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48};
+ int on = 0;
- val = snd_soc_component_read(component, RT5682S_GPIO_CTRL_1)
- & RT5682S_GP4_PIN_MASK;
+ if (rt5682s->wclk_enabled)
+ return 0;
- if (w->shift == RT5682S_PWR_ADC_S1F_BIT && val == RT5682S_GP4_PIN_ADCDAT2)
- ref = 256 * rt5682s->lrck[RT5682S_AIF2];
- else
- ref = 256 * rt5682s->lrck[RT5682S_AIF1];
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ on = 1;
- idx = rt5682s_div_sel(rt5682s, ref, div_f, ARRAY_SIZE(div_f));
+ rt5682s_set_pllb_power(rt5682s, on);
- if (w->shift == RT5682S_PWR_ADC_S1F_BIT)
- reg = RT5682S_PLL_TRACK_3;
- else
- reg = RT5682S_PLL_TRACK_2;
+ return 0;
+}
+
+static void rt5682s_set_filter_clk(struct rt5682s_priv *rt5682s, int reg, int ref)
+{
+ struct snd_soc_component *component = rt5682s->component;
+ int idx;
+ static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48};
+ static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48};
+
+ idx = rt5682s_div_sel(rt5682s, ref, div_f, ARRAY_SIZE(div_f));
snd_soc_component_update_bits(component, reg,
RT5682S_FILTER_CLK_DIV_MASK, idx << RT5682S_FILTER_CLK_DIV_SFT);
@@ -1190,6 +1214,29 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(component, RT5682S_ADDA_CLK_1,
RT5682S_ADC_OSR_MASK | RT5682S_DAC_OSR_MASK,
(idx << RT5682S_ADC_OSR_SFT) | (idx << RT5682S_DAC_OSR_SFT));
+}
+
+static int set_filter_clk(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 rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
+ int ref, reg, val;
+
+ val = snd_soc_component_read(component, RT5682S_GPIO_CTRL_1)
+ & RT5682S_GP4_PIN_MASK;
+
+ if (w->shift == RT5682S_PWR_ADC_S1F_BIT && val == RT5682S_GP4_PIN_ADCDAT2)
+ ref = 256 * rt5682s->lrck[RT5682S_AIF2];
+ else
+ ref = 256 * rt5682s->lrck[RT5682S_AIF1];
+
+ if (w->shift == RT5682S_PWR_ADC_S1F_BIT)
+ reg = RT5682S_PLL_TRACK_3;
+ else
+ reg = RT5682S_PLL_TRACK_2;
+
+ rt5682s_set_filter_clk(rt5682s, reg, ref);
return 0;
}
@@ -1218,13 +1265,9 @@ static int set_dmic_power(struct snd_soc_dapm_widget *w,
break;
case SND_SOC_DAPM_POST_PMD:
- if (!rt5682s->jack_type) {
- if (!snd_soc_dapm_get_pin_status(w->dapm, "MICBIAS"))
- snd_soc_component_update_bits(component,
- RT5682S_PWR_ANLG_1, RT5682S_PWR_MB, 0);
- if (!snd_soc_dapm_get_pin_status(w->dapm, "Vref2"))
- snd_soc_component_update_bits(component,
- RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2, 0);
+ if (!rt5682s->jack_type && !rt5682s->wclk_enabled) {
+ snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1,
+ RT5682S_PWR_VREF2 | RT5682S_PWR_MB, 0);
}
break;
}
@@ -1232,41 +1275,58 @@ static int set_dmic_power(struct snd_soc_dapm_widget *w,
return 0;
}
-static int set_i2s_clk(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+static void rt5682s_set_i2s(struct rt5682s_priv *rt5682s, int id, int on)
{
- struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
- struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
- int pre_div, id;
- unsigned int reg, mask, sft;
-
- if (event != SND_SOC_DAPM_PRE_PMU)
- return 0;
-
- if (w->shift == RT5682S_PWR_I2S2_BIT) {
- id = RT5682S_AIF2;
- reg = RT5682S_I2S2_M_CLK_CTRL_1;
- mask = RT5682S_I2S2_M_D_MASK;
- sft = RT5682S_I2S2_M_D_SFT;
+ struct snd_soc_component *component = rt5682s->component;
+ int pre_div;
+ unsigned int p_reg, p_mask, p_sft;
+ unsigned int c_reg, c_mask, c_sft;
+
+ if (id == RT5682S_AIF1) {
+ c_reg = RT5682S_ADDA_CLK_1;
+ c_mask = RT5682S_I2S_M_D_MASK;
+ c_sft = RT5682S_I2S_M_D_SFT;
+ p_reg = RT5682S_PWR_DIG_1;
+ p_mask = RT5682S_PWR_I2S1;
+ p_sft = RT5682S_PWR_I2S1_BIT;
} else {
- id = RT5682S_AIF1;
- reg = RT5682S_ADDA_CLK_1;
- mask = RT5682S_I2S_M_D_MASK;
- sft = RT5682S_I2S_M_D_SFT;
+ c_reg = RT5682S_I2S2_M_CLK_CTRL_1;
+ c_mask = RT5682S_I2S2_M_D_MASK;
+ c_sft = RT5682S_I2S2_M_D_SFT;
+ p_reg = RT5682S_PWR_DIG_1;
+ p_mask = RT5682S_PWR_I2S2;
+ p_sft = RT5682S_PWR_I2S2_BIT;
}
- if (!rt5682s->master[id])
- return 0;
+ if (on && rt5682s->master[id]) {
+ pre_div = get_clk_info(rt5682s->sysclk, rt5682s->lrck[id]);
+ if (pre_div < 0) {
+ dev_err(component->dev, "get pre_div failed\n");
+ return;
+ }
- pre_div = get_clk_info(rt5682s->sysclk, rt5682s->lrck[id]);
- if (pre_div < 0) {
- dev_err(component->dev, "get pre_div failed\n");
- return -EINVAL;
+ dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d master\n",
+ rt5682s->lrck[id], pre_div, id);
+ snd_soc_component_update_bits(component, c_reg, c_mask, pre_div << c_sft);
}
- dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d master\n",
- rt5682s->lrck[id], pre_div, id);
- snd_soc_component_update_bits(component, reg, mask, pre_div << sft);
+ snd_soc_component_update_bits(component, p_reg, p_mask, on << p_sft);
+}
+
+static int set_i2s_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 rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
+ int on = 0;
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ on = 1;
+
+ if (!strcmp(w->name, "I2S1") && !rt5682s->wclk_enabled)
+ rt5682s_set_i2s(rt5682s, RT5682S_AIF1, on);
+ else if (!strcmp(w->name, "I2S2"))
+ rt5682s_set_i2s(rt5682s, RT5682S_AIF2, on);
return 0;
}
@@ -1615,26 +1675,18 @@ static const struct snd_soc_dapm_widget rt5682s_dapm_widgets[] = {
RT5682S_PWR_LDO_MB2_BIT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("LDO", RT5682S_PWR_ANLG_3,
RT5682S_PWR_LDO_BIT, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("Vref2", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, NULL, 0),
/* PLL Powers */
SND_SOC_DAPM_SUPPLY_S("PLLA_LDO", 0, RT5682S_PWR_ANLG_3,
RT5682S_PWR_LDO_PLLA_BIT, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY_S("PLLB_LDO", 0, RT5682S_PWR_ANLG_3,
- RT5682S_PWR_LDO_PLLB_BIT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("PLLA_BIAS", 0, RT5682S_PWR_ANLG_3,
RT5682S_PWR_BIAS_PLLA_BIT, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY_S("PLLB_BIAS", 0, RT5682S_PWR_ANLG_3,
- RT5682S_PWR_BIAS_PLLB_BIT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("PLLA", 0, RT5682S_PWR_ANLG_3,
RT5682S_PWR_PLLA_BIT, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY_S("PLLB", 0, RT5682S_PWR_ANLG_3,
- RT5682S_PWR_PLLB_BIT, 0, set_filter_clk, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_SUPPLY_S("PLLA_RST", 1, RT5682S_PWR_ANLG_3,
RT5682S_RSTB_PLLA_BIT, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY_S("PLLB_RST", 1, RT5682S_PWR_ANLG_3,
- RT5682S_RSTB_PLLB_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PLLB", SND_SOC_NOPM, 0, 0,
+ set_pllb_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
/* ASRC */
SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5682S_PLL_TRACK_1,
@@ -1720,10 +1772,10 @@ static const struct snd_soc_dapm_widget rt5682s_dapm_widgets[] = {
SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
/* Digital Interface */
- SND_SOC_DAPM_SUPPLY("I2S1", RT5682S_PWR_DIG_1, RT5682S_PWR_I2S1_BIT,
- 0, set_i2s_clk, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_SUPPLY("I2S2", RT5682S_PWR_DIG_1, RT5682S_PWR_I2S2_BIT,
- 0, set_i2s_clk, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SUPPLY("I2S1", SND_SOC_NOPM, 0, 0,
+ set_i2s_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("I2S2", SND_SOC_NOPM, 0, 0,
+ set_i2s_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -1801,9 +1853,6 @@ static const struct snd_soc_dapm_route rt5682s_dapm_routes[] = {
{"PLLA", NULL, "PLLA_LDO"},
{"PLLA", NULL, "PLLA_BIAS"},
{"PLLA", NULL, "PLLA_RST"},
- {"PLLB", NULL, "PLLB_LDO"},
- {"PLLB", NULL, "PLLB_BIAS"},
- {"PLLB", NULL, "PLLB_RST"},
/*ASRC*/
{"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc},
@@ -2431,12 +2480,15 @@ static int rt5682s_set_bias_level(struct snd_soc_component *component,
RT5682S_PWR_LDO, RT5682S_PWR_LDO);
break;
case SND_SOC_BIAS_STANDBY:
- regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1,
- RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL);
+ if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1,
+ RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL);
break;
case SND_SOC_BIAS_OFF:
- regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1,
- RT5682S_DIG_GATE_CTRL | RT5682S_PWR_LDO, 0);
+ regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, RT5682S_PWR_LDO, 0);
+ if (!rt5682s->wclk_enabled)
+ regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1,
+ RT5682S_DIG_GATE_CTRL, 0);
break;
case SND_SOC_BIAS_ON:
break;
@@ -2464,30 +2516,34 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw)
struct rt5682s_priv *rt5682s =
container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]);
struct snd_soc_component *component = rt5682s->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ int ref, reg;
if (!rt5682s_clk_check(rt5682s))
return -EINVAL;
- snd_soc_dapm_mutex_lock(dapm);
-
- snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS");
- snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1,
- RT5682S_PWR_MB, RT5682S_PWR_MB);
+ mutex_lock(&rt5682s->wclk_mutex);
- snd_soc_dapm_force_enable_pin_unlocked(dapm, "Vref2");
snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1,
- RT5682S_PWR_VREF2 | RT5682S_PWR_FV2, RT5682S_PWR_VREF2);
+ RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB,
+ RT5682S_PWR_VREF2 | RT5682S_PWR_MB);
usleep_range(15000, 20000);
snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1,
RT5682S_PWR_FV2, RT5682S_PWR_FV2);
- snd_soc_dapm_force_enable_pin_unlocked(dapm, "I2S1");
- /* Only need to power PLLB due to the rate set restriction */
- snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLLB");
- snd_soc_dapm_sync_unlocked(dapm);
+ /* Set and power on I2S1 */
+ snd_soc_component_update_bits(component, RT5682S_PWR_DIG_1,
+ RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL);
+ rt5682s_set_i2s(rt5682s, RT5682S_AIF1, 1);
- snd_soc_dapm_mutex_unlock(dapm);
+ /* Only need to power on PLLB due to the rate set restriction */
+ reg = RT5682S_PLL_TRACK_2;
+ ref = 256 * rt5682s->lrck[RT5682S_AIF1];
+ rt5682s_set_filter_clk(rt5682s, reg, ref);
+ rt5682s_set_pllb_power(rt5682s, 1);
+
+ rt5682s->wclk_enabled = 1;
+
+ mutex_unlock(&rt5682s->wclk_mutex);
return 0;
}
@@ -2497,24 +2553,27 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw)
struct rt5682s_priv *rt5682s =
container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]);
struct snd_soc_component *component = rt5682s->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
if (!rt5682s_clk_check(rt5682s))
return;
- snd_soc_dapm_mutex_lock(dapm);
+ mutex_lock(&rt5682s->wclk_mutex);
- snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS");
- snd_soc_dapm_disable_pin_unlocked(dapm, "Vref2");
if (!rt5682s->jack_type)
snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1,
RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB, 0);
- snd_soc_dapm_disable_pin_unlocked(dapm, "I2S1");
- snd_soc_dapm_disable_pin_unlocked(dapm, "PLLB");
- snd_soc_dapm_sync_unlocked(dapm);
+ /* Power down I2S1 */
+ rt5682s_set_i2s(rt5682s, RT5682S_AIF1, 0);
+ snd_soc_component_update_bits(component, RT5682S_PWR_DIG_1,
+ RT5682S_DIG_GATE_CTRL, 0);
- snd_soc_dapm_mutex_unlock(dapm);
+ /* Power down PLLB */
+ rt5682s_set_pllb_power(rt5682s, 0);
+
+ rt5682s->wclk_enabled = 0;
+
+ mutex_unlock(&rt5682s->wclk_mutex);
}
static unsigned long rt5682s_wclk_recalc_rate(struct clk_hw *hw,
@@ -2805,19 +2864,10 @@ static inline int rt5682s_dai_probe_clks(struct snd_soc_component *component)
static int rt5682s_probe(struct snd_soc_component *component)
{
struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = &component->dapm;
- int ret;
rt5682s->component = component;
- ret = rt5682s_dai_probe_clks(component);
- if (ret)
- return ret;
-
- snd_soc_dapm_disable_pin(dapm, "MICBIAS");
- snd_soc_dapm_disable_pin(dapm, "Vref2");
- snd_soc_dapm_sync(dapm);
- return 0;
+ return rt5682s_dai_probe_clks(component);
}
static void rt5682s_remove(struct snd_soc_component *component)
@@ -3113,6 +3163,7 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c)
mutex_init(&rt5682s->calibrate_mutex);
mutex_init(&rt5682s->sar_mutex);
+ mutex_init(&rt5682s->wclk_mutex);
rt5682s_calibrate(rt5682s);
regmap_update_bits(rt5682s->regmap, RT5682S_MICBIAS_2,
diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h
index 7353831c73dd..824dc6543c18 100644
--- a/sound/soc/codecs/rt5682s.h
+++ b/sound/soc/codecs/rt5682s.h
@@ -1450,6 +1450,7 @@ struct rt5682s_priv {
struct delayed_work jd_check_work;
struct mutex calibrate_mutex;
struct mutex sar_mutex;
+ struct mutex wclk_mutex;
#ifdef CONFIG_COMMON_CLK
struct clk_hw dai_clks_hw[RT5682S_DAI_NUM_CLKS];
@@ -1469,6 +1470,7 @@ struct rt5682s_priv {
int jack_type;
int irq_work_delay_time;
+ int wclk_enabled;
};
int rt5682s_sel_asrc_clk_src(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c
index f7439e40ca8b..96fc5f36d0d0 100644
--- a/sound/soc/codecs/rt700-sdw.c
+++ b/sound/soc/codecs/rt700-sdw.c
@@ -542,6 +542,8 @@ static int __maybe_unused rt700_dev_resume(struct device *dev)
msecs_to_jiffies(RT700_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ sdw_show_ping_status(slave->bus, true);
+
return -ETIMEDOUT;
}
diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c
index a085b2f530aa..4120842fe699 100644
--- a/sound/soc/codecs/rt711-sdca-sdw.c
+++ b/sound/soc/codecs/rt711-sdca-sdw.c
@@ -449,6 +449,8 @@ static int __maybe_unused rt711_sdca_dev_resume(struct device *dev)
msecs_to_jiffies(RT711_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ sdw_show_ping_status(slave->bus, true);
+
return -ETIMEDOUT;
}
diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c
index 13e731d16675..3f981a9e7fb6 100644
--- a/sound/soc/codecs/rt715-sdca-sdw.c
+++ b/sound/soc/codecs/rt715-sdca-sdw.c
@@ -244,6 +244,8 @@ static int __maybe_unused rt715_dev_resume(struct device *dev)
msecs_to_jiffies(RT715_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Enumeration not complete, timed out\n");
+ sdw_show_ping_status(slave->bus, true);
+
return -ETIMEDOUT;
}
diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c
index b047bf87a100..4e61e16470ed 100644
--- a/sound/soc/codecs/rt715-sdw.c
+++ b/sound/soc/codecs/rt715-sdw.c
@@ -562,6 +562,8 @@ static int __maybe_unused rt715_dev_resume(struct device *dev)
msecs_to_jiffies(RT715_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ sdw_show_ping_status(slave->bus, true);
+
return -ETIMEDOUT;
}
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c
index b992216aee55..3047a6fbb380 100644
--- a/sound/soc/codecs/sigmadsp.c
+++ b/sound/soc/codecs/sigmadsp.c
@@ -227,13 +227,11 @@ static int sigma_fw_load_control(struct sigmadsp *sigmadsp,
if (!ctrl)
return -ENOMEM;
- name = kzalloc(name_len + 1, GFP_KERNEL);
+ name = kmemdup_nul(ctrl_chunk->name, name_len, GFP_KERNEL);
if (!name) {
ret = -ENOMEM;
goto err_free_ctrl;
}
- memcpy(name, ctrl_chunk->name, name_len);
- name[name_len] = '\0';
ctrl->name = name;
/*
diff --git a/sound/soc/codecs/src4xxx-i2c.c b/sound/soc/codecs/src4xxx-i2c.c
new file mode 100644
index 000000000000..43daa9dc8ab5
--- /dev/null
+++ b/sound/soc/codecs/src4xxx-i2c.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Driver for SRC4XXX codecs
+//
+// Copyright 2021-2022 Deqx Pty Ltd
+// Author: Matt Flax <flatmax@flatmax.com>
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "src4xxx.h"
+
+static int src4xxx_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ return src4xxx_probe(&i2c->dev,
+ devm_regmap_init_i2c(i2c, &src4xxx_regmap_config), NULL);
+}
+
+static const struct i2c_device_id src4xxx_i2c_ids[] = {
+ { "src4392", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, src4xxx_i2c_ids);
+
+static const struct of_device_id src4xxx_of_match[] = {
+ { .compatible = "ti,src4392", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, src4xxx_of_match);
+
+
+static struct i2c_driver src4xxx_i2c_driver = {
+ .driver = {
+ .name = "src4xxx",
+ .of_match_table = of_match_ptr(src4xxx_of_match),
+ },
+ .probe = src4xxx_i2c_probe,
+ .id_table = src4xxx_i2c_ids,
+};
+module_i2c_driver(src4xxx_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC SRC4392 CODEC I2C driver");
+MODULE_AUTHOR("Matt Flax <flatmax@flatmax.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/src4xxx.c b/sound/soc/codecs/src4xxx.c
new file mode 100644
index 000000000000..db4e280dd055
--- /dev/null
+++ b/sound/soc/codecs/src4xxx.c
@@ -0,0 +1,518 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// TI SRC4xxx Audio Codec driver
+//
+// Copyright 2021-2022 Deqx Pty Ltd
+// Author: Matt Flax <flatmax@flatmax.com>
+
+#include <linux/module.h>
+
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "src4xxx.h"
+
+struct src4xxx {
+ struct regmap *regmap;
+ bool master[2];
+ int mclk_hz;
+ struct device *dev;
+};
+
+enum {SRC4XXX_PORTA, SRC4XXX_PORTB};
+
+/* SRC attenuation */
+static const DECLARE_TLV_DB_SCALE(src_tlv, -12750, 50, 0);
+
+static const struct snd_kcontrol_new src4xxx_controls[] = {
+ SOC_DOUBLE_R_TLV("SRC Volume",
+ SRC4XXX_SCR_CTL_30, SRC4XXX_SCR_CTL_31, 0, 255, 1, src_tlv),
+};
+
+/* I2S port control */
+static const char * const port_out_src_text[] = {
+ "loopback", "other_port", "DIR", "SRC"
+};
+static SOC_ENUM_SINGLE_DECL(porta_out_src_enum, SRC4XXX_PORTA_CTL_03, 4,
+ port_out_src_text);
+static SOC_ENUM_SINGLE_DECL(portb_out_src_enum, SRC4XXX_PORTB_CTL_05, 4,
+ port_out_src_text);
+static const struct snd_kcontrol_new porta_out_control =
+ SOC_DAPM_ENUM("Port A source select", porta_out_src_enum);
+static const struct snd_kcontrol_new portb_out_control =
+ SOC_DAPM_ENUM("Port B source select", portb_out_src_enum);
+
+/* Digital audio transmitter control */
+static const char * const dit_mux_text[] = {"Port A", "Port B", "DIR", "SRC"};
+static SOC_ENUM_SINGLE_DECL(dit_mux_enum, SRC4XXX_TX_CTL_07, 3, dit_mux_text);
+static const struct snd_kcontrol_new dit_mux_control =
+ SOC_DAPM_ENUM("DIT source", dit_mux_enum);
+
+/* SRC control */
+static const char * const src_in_text[] = {"Port A", "Port B", "DIR"};
+static SOC_ENUM_SINGLE_DECL(src_in_enum, SRC4XXX_SCR_CTL_2D, 0, src_in_text);
+static const struct snd_kcontrol_new src_in_control =
+ SOC_DAPM_ENUM("SRC source select", src_in_enum);
+
+/* DIR control */
+static const char * const dir_in_text[] = {"Ch 1", "Ch 2", "Ch 3", "Ch 4"};
+static SOC_ENUM_SINGLE_DECL(dir_in_enum, SRC4XXX_RCV_CTL_0D, 0, dir_in_text);
+static const struct snd_kcontrol_new dir_in_control =
+ SOC_DAPM_ENUM("Digital Input", dir_in_enum);
+
+static const struct snd_soc_dapm_widget src4xxx_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("loopback_A"),
+ SND_SOC_DAPM_INPUT("other_port_A"),
+ SND_SOC_DAPM_INPUT("DIR_A"),
+ SND_SOC_DAPM_INPUT("SRC_A"),
+ SND_SOC_DAPM_MUX("Port A source",
+ SND_SOC_NOPM, 0, 0, &porta_out_control),
+
+ SND_SOC_DAPM_INPUT("loopback_B"),
+ SND_SOC_DAPM_INPUT("other_port_B"),
+ SND_SOC_DAPM_INPUT("DIR_B"),
+ SND_SOC_DAPM_INPUT("SRC_B"),
+ SND_SOC_DAPM_MUX("Port B source",
+ SND_SOC_NOPM, 0, 0, &portb_out_control),
+
+ SND_SOC_DAPM_INPUT("Port_A"),
+ SND_SOC_DAPM_INPUT("Port_B"),
+ SND_SOC_DAPM_INPUT("DIR_"),
+
+ /* Digital audio receivers and transmitters */
+ SND_SOC_DAPM_OUTPUT("DIR_OUT"),
+ SND_SOC_DAPM_OUTPUT("SRC_OUT"),
+ SND_SOC_DAPM_MUX("DIT Out Src", SRC4XXX_PWR_RST_01,
+ SRC4XXX_ENABLE_DIT_SHIFT, 1, &dit_mux_control),
+
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("AIF_A_RX", "Playback A", 0,
+ SRC4XXX_PWR_RST_01, SRC4XXX_ENABLE_PORT_A_SHIFT, 1),
+ SND_SOC_DAPM_AIF_OUT("AIF_A_TX", "Capture A", 0,
+ SRC4XXX_PWR_RST_01, SRC4XXX_ENABLE_PORT_A_SHIFT, 1),
+ SND_SOC_DAPM_AIF_IN("AIF_B_RX", "Playback B", 0,
+ SRC4XXX_PWR_RST_01, SRC4XXX_ENABLE_PORT_B_SHIFT, 1),
+ SND_SOC_DAPM_AIF_OUT("AIF_B_TX", "Capture B", 0,
+ SRC4XXX_PWR_RST_01, SRC4XXX_ENABLE_PORT_B_SHIFT, 1),
+
+ SND_SOC_DAPM_MUX("SRC source", SND_SOC_NOPM, 0, 0, &src_in_control),
+
+ SND_SOC_DAPM_INPUT("MCLK"),
+ SND_SOC_DAPM_INPUT("RXMCLKI"),
+ SND_SOC_DAPM_INPUT("RXMCLKO"),
+
+ SND_SOC_DAPM_INPUT("RX1"),
+ SND_SOC_DAPM_INPUT("RX2"),
+ SND_SOC_DAPM_INPUT("RX3"),
+ SND_SOC_DAPM_INPUT("RX4"),
+ SND_SOC_DAPM_MUX("Digital Input", SRC4XXX_PWR_RST_01,
+ SRC4XXX_ENABLE_DIR_SHIFT, 1, &dir_in_control),
+};
+
+static const struct snd_soc_dapm_route src4xxx_audio_routes[] = {
+ /* I2S Input to Output Routing */
+ {"Port A source", "loopback", "loopback_A"},
+ {"Port A source", "other_port", "other_port_A"},
+ {"Port A source", "DIR", "DIR_A"},
+ {"Port A source", "SRC", "SRC_A"},
+ {"Port B source", "loopback", "loopback_B"},
+ {"Port B source", "other_port", "other_port_B"},
+ {"Port B source", "DIR", "DIR_B"},
+ {"Port B source", "SRC", "SRC_B"},
+ /* DIT muxing */
+ {"DIT Out Src", "Port A", "Capture A"},
+ {"DIT Out Src", "Port B", "Capture B"},
+ {"DIT Out Src", "DIR", "DIR_OUT"},
+ {"DIT Out Src", "SRC", "SRC_OUT"},
+
+ /* SRC input selection */
+ {"SRC source", "Port A", "Port_A"},
+ {"SRC source", "Port B", "Port_B"},
+ {"SRC source", "DIR", "DIR_"},
+ /* SRC mclk selection */
+ {"SRC mclk source", "Master (MCLK)", "MCLK"},
+ {"SRC mclk source", "Master (RXCLKI)", "RXMCLKI"},
+ {"SRC mclk source", "Recovered receiver clk", "RXMCLKO"},
+ /* DIR input selection */
+ {"Digital Input", "Ch 1", "RX1"},
+ {"Digital Input", "Ch 2", "RX2"},
+ {"Digital Input", "Ch 3", "RX3"},
+ {"Digital Input", "Ch 4", "RX4"},
+};
+
+
+static const struct snd_soc_component_driver src4xxx_driver = {
+ .controls = src4xxx_controls,
+ .num_controls = ARRAY_SIZE(src4xxx_controls),
+
+ .dapm_widgets = src4xxx_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(src4xxx_dapm_widgets),
+ .dapm_routes = src4xxx_audio_routes,
+ .num_dapm_routes = ARRAY_SIZE(src4xxx_audio_routes),
+};
+
+static int src4xxx_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct src4xxx *src4xxx = snd_soc_component_get_drvdata(component);
+ unsigned int ctrl;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ ctrl = SRC4XXX_BUS_MASTER;
+ src4xxx->master[dai->id] = true;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ ctrl = 0;
+ src4xxx->master[dai->id] = false;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ ctrl |= SRC4XXX_BUS_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ ctrl |= SRC4XXX_BUS_LEFT_J;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ ctrl |= SRC4XXX_BUS_RIGHT_J_24;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ regmap_update_bits(src4xxx->regmap, SRC4XXX_BUS_FMT(dai->id),
+ SRC4XXX_BUS_FMT_MS_MASK, ctrl);
+
+ return 0;
+}
+
+static int src4xxx_set_mclk_hz(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct src4xxx *src4xxx = snd_soc_component_get_drvdata(component);
+
+ dev_info(component->dev, "changing mclk rate from %d to %d Hz\n",
+ src4xxx->mclk_hz, freq);
+ src4xxx->mclk_hz = freq;
+
+ return 0;
+}
+
+static int src4xxx_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 src4xxx *src4xxx = snd_soc_component_get_drvdata(component);
+ unsigned int mclk_div;
+ int val, pj, jd, d;
+ int reg;
+ int ret;
+
+ switch (dai->id) {
+ case SRC4XXX_PORTB:
+ reg = SRC4XXX_PORTB_CTL_06;
+ break;
+ default:
+ reg = SRC4XXX_PORTA_CTL_04;
+ break;
+ }
+
+ if (src4xxx->master[dai->id]) {
+ mclk_div = src4xxx->mclk_hz/params_rate(params);
+ if (src4xxx->mclk_hz != mclk_div*params_rate(params)) {
+ dev_err(component->dev,
+ "mclk %d / rate %d has a remainder.\n",
+ src4xxx->mclk_hz, params_rate(params));
+ return -EINVAL;
+ }
+
+ val = ((int)mclk_div - 128) / 128;
+ if ((val < 0) | (val > 3)) {
+ dev_err(component->dev,
+ "div register setting %d is out of range\n",
+ val);
+ dev_err(component->dev,
+ "unsupported sample rate %d Hz for the master clock of %d Hz\n",
+ params_rate(params), src4xxx->mclk_hz);
+ return -EINVAL;
+ }
+
+ /* set the TX DIV */
+ ret = regmap_update_bits(src4xxx->regmap,
+ SRC4XXX_TX_CTL_07, SRC4XXX_TX_MCLK_DIV_MASK,
+ val<<SRC4XXX_TX_MCLK_DIV_SHIFT);
+ if (ret) {
+ dev_err(component->dev,
+ "Couldn't set the TX's div register to %d << %d = 0x%x\n",
+ val, SRC4XXX_TX_MCLK_DIV_SHIFT,
+ val<<SRC4XXX_TX_MCLK_DIV_SHIFT);
+ return ret;
+ }
+
+ /* set the PLL for the digital receiver */
+ switch (src4xxx->mclk_hz) {
+ case 24576000:
+ pj = 0x22;
+ jd = 0x00;
+ d = 0x00;
+ break;
+ case 22579200:
+ pj = 0x22;
+ jd = 0x1b;
+ d = 0xa3;
+ break;
+ default:
+ /* don't error out here,
+ * other parts of the chip are still functional
+ * Dummy initialize variables to avoid
+ * -Wsometimes-uninitialized from clang.
+ */
+ dev_info(component->dev,
+ "Couldn't set the RCV PLL as this master clock rate is unknown. Chosen regmap values may not match real world values.\n");
+ pj = 0x0;
+ jd = 0xff;
+ d = 0xff;
+ break;
+ }
+ ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_0F, pj);
+ if (ret < 0)
+ dev_err(component->dev,
+ "Failed to update PLL register 0x%x\n",
+ SRC4XXX_RCV_PLL_0F);
+ ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_10, jd);
+ if (ret < 0)
+ dev_err(component->dev,
+ "Failed to update PLL register 0x%x\n",
+ SRC4XXX_RCV_PLL_10);
+ ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_11, d);
+ if (ret < 0)
+ dev_err(component->dev,
+ "Failed to update PLL register 0x%x\n",
+ SRC4XXX_RCV_PLL_11);
+
+ ret = regmap_update_bits(src4xxx->regmap,
+ SRC4XXX_TX_CTL_07, SRC4XXX_TX_MCLK_DIV_MASK,
+ val<<SRC4XXX_TX_MCLK_DIV_SHIFT);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "Couldn't set the TX's div register to %d << %d = 0x%x\n",
+ val, SRC4XXX_TX_MCLK_DIV_SHIFT,
+ val<<SRC4XXX_TX_MCLK_DIV_SHIFT);
+ return ret;
+ }
+
+ return regmap_update_bits(src4xxx->regmap, reg,
+ SRC4XXX_MCLK_DIV_MASK, val);
+ } else {
+ dev_info(dai->dev, "not setting up MCLK as not master\n");
+ }
+
+ return 0;
+};
+
+static const struct snd_soc_dai_ops src4xxx_dai_ops = {
+ .hw_params = src4xxx_hw_params,
+ .set_sysclk = src4xxx_set_mclk_hz,
+ .set_fmt = src4xxx_set_dai_fmt,
+};
+
+#define SRC4XXX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+#define SRC4XXX_RATES (SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000|\
+ SNDRV_PCM_RATE_88200|\
+ SNDRV_PCM_RATE_96000|\
+ SNDRV_PCM_RATE_176400|\
+ SNDRV_PCM_RATE_192000)
+
+static struct snd_soc_dai_driver src4xxx_dai_driver[] = {
+ {
+ .id = SRC4XXX_PORTA,
+ .name = "src4xxx-portA",
+ .playback = {
+ .stream_name = "Playback A",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SRC4XXX_RATES,
+ .formats = SRC4XXX_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture A",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SRC4XXX_RATES,
+ .formats = SRC4XXX_FORMATS,
+ },
+ .ops = &src4xxx_dai_ops,
+ },
+ {
+ .id = SRC4XXX_PORTB,
+ .name = "src4xxx-portB",
+ .playback = {
+ .stream_name = "Playback B",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SRC4XXX_RATES,
+ .formats = SRC4XXX_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture B",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SRC4XXX_RATES,
+ .formats = SRC4XXX_FORMATS,
+ },
+ .ops = &src4xxx_dai_ops,
+ },
+};
+
+static const struct reg_default src4xxx_reg_defaults[] = {
+ { SRC4XXX_PWR_RST_01, 0x00 }, /* all powered down intially */
+ { SRC4XXX_PORTA_CTL_03, 0x00 },
+ { SRC4XXX_PORTA_CTL_04, 0x00 },
+ { SRC4XXX_PORTB_CTL_05, 0x00 },
+ { SRC4XXX_PORTB_CTL_06, 0x00 },
+ { SRC4XXX_TX_CTL_07, 0x00 },
+ { SRC4XXX_TX_CTL_08, 0x00 },
+ { SRC4XXX_TX_CTL_09, 0x00 },
+ { SRC4XXX_SRC_DIT_IRQ_MSK_0B, 0x00 },
+ { SRC4XXX_SRC_DIT_IRQ_MODE_0C, 0x00 },
+ { SRC4XXX_RCV_CTL_0D, 0x00 },
+ { SRC4XXX_RCV_CTL_0E, 0x00 },
+ { SRC4XXX_RCV_PLL_0F, 0x00 }, /* not spec. in the datasheet */
+ { SRC4XXX_RCV_PLL_10, 0xff }, /* not spec. in the datasheet */
+ { SRC4XXX_RCV_PLL_11, 0xff }, /* not spec. in the datasheet */
+ { SRC4XXX_RVC_IRQ_MSK_16, 0x00 },
+ { SRC4XXX_RVC_IRQ_MSK_17, 0x00 },
+ { SRC4XXX_RVC_IRQ_MODE_18, 0x00 },
+ { SRC4XXX_RVC_IRQ_MODE_19, 0x00 },
+ { SRC4XXX_RVC_IRQ_MODE_1A, 0x00 },
+ { SRC4XXX_GPIO_1_1B, 0x00 },
+ { SRC4XXX_GPIO_2_1C, 0x00 },
+ { SRC4XXX_GPIO_3_1D, 0x00 },
+ { SRC4XXX_GPIO_4_1E, 0x00 },
+ { SRC4XXX_SCR_CTL_2D, 0x00 },
+ { SRC4XXX_SCR_CTL_2E, 0x00 },
+ { SRC4XXX_SCR_CTL_2F, 0x00 },
+ { SRC4XXX_SCR_CTL_30, 0x00 },
+ { SRC4XXX_SCR_CTL_31, 0x00 },
+};
+
+int src4xxx_probe(struct device *dev, struct regmap *regmap,
+ void (*switch_mode)(struct device *dev))
+{
+ struct src4xxx *src4xxx;
+ int ret;
+
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ src4xxx = devm_kzalloc(dev, sizeof(*src4xxx), GFP_KERNEL);
+ if (!src4xxx)
+ return -ENOMEM;
+
+ src4xxx->regmap = regmap;
+ src4xxx->dev = dev;
+ src4xxx->mclk_hz = 0; /* mclk has not been configured yet */
+ dev_set_drvdata(dev, src4xxx);
+
+ ret = regmap_write(regmap, SRC4XXX_PWR_RST_01, SRC4XXX_RESET);
+ if (ret < 0)
+ dev_err(dev, "Failed to issue reset: %d\n", ret);
+ usleep_range(1, 500); /* sleep for more then 500 ns */
+ ret = regmap_write(regmap, SRC4XXX_PWR_RST_01, SRC4XXX_POWER_DOWN);
+ if (ret < 0)
+ dev_err(dev, "Failed to decommission reset: %d\n", ret);
+ usleep_range(500, 1000); /* sleep for 500 us or more */
+
+ ret = regmap_update_bits(src4xxx->regmap, SRC4XXX_PWR_RST_01,
+ SRC4XXX_POWER_ENABLE, SRC4XXX_POWER_ENABLE);
+ if (ret < 0)
+ dev_err(dev, "Failed to port A and B : %d\n", ret);
+
+ /* set receiver to use master clock (rcv mclk is most likely jittery) */
+ ret = regmap_update_bits(src4xxx->regmap, SRC4XXX_RCV_CTL_0D,
+ SRC4XXX_RXCLK_MCLK, SRC4XXX_RXCLK_MCLK);
+ if (ret < 0)
+ dev_err(dev,
+ "Failed to enable mclk as the PLL1 DIR reference : %d\n", ret);
+
+ /* default to leaving the PLL2 running on loss of lock, divide by 8 */
+ ret = regmap_update_bits(src4xxx->regmap, SRC4XXX_RCV_CTL_0E,
+ SRC4XXX_PLL2_DIV_8 | SRC4XXX_REC_MCLK_EN | SRC4XXX_PLL2_LOL,
+ SRC4XXX_PLL2_DIV_8 | SRC4XXX_REC_MCLK_EN | SRC4XXX_PLL2_LOL);
+ if (ret < 0)
+ dev_err(dev, "Failed to enable mclk rec and div : %d\n", ret);
+
+ ret = devm_snd_soc_register_component(dev, &src4xxx_driver,
+ src4xxx_dai_driver, ARRAY_SIZE(src4xxx_dai_driver));
+ if (ret == 0)
+ dev_info(dev, "src4392 probe ok %d\n", ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(src4xxx_probe);
+
+static bool src4xxx_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SRC4XXX_RES_00:
+ case SRC4XXX_GLOBAL_ITR_STS_02:
+ case SRC4XXX_SRC_DIT_STS_0A:
+ case SRC4XXX_NON_AUDIO_D_12:
+ case SRC4XXX_RVC_STS_13:
+ case SRC4XXX_RVC_STS_14:
+ case SRC4XXX_RVC_STS_15:
+ case SRC4XXX_SUB_CODE_1F:
+ case SRC4XXX_SUB_CODE_20:
+ case SRC4XXX_SUB_CODE_21:
+ case SRC4XXX_SUB_CODE_22:
+ case SRC4XXX_SUB_CODE_23:
+ case SRC4XXX_SUB_CODE_24:
+ case SRC4XXX_SUB_CODE_25:
+ case SRC4XXX_SUB_CODE_26:
+ case SRC4XXX_SUB_CODE_27:
+ case SRC4XXX_SUB_CODE_28:
+ case SRC4XXX_PC_PREAMBLE_HI_29:
+ case SRC4XXX_PC_PREAMBLE_LO_2A:
+ case SRC4XXX_PD_PREAMBLE_HI_2B:
+ case SRC4XXX_PC_PREAMBLE_LO_2C:
+ case SRC4XXX_IO_RATIO_32:
+ case SRC4XXX_IO_RATIO_33:
+ return true;
+ }
+
+ if (reg > SRC4XXX_IO_RATIO_33 && reg < SRC4XXX_PAGE_SEL_7F)
+ return true;
+
+ return false;
+}
+
+const struct regmap_config src4xxx_regmap_config = {
+ .val_bits = 8,
+ .reg_bits = 8,
+ .max_register = SRC4XXX_IO_RATIO_33,
+
+ .reg_defaults = src4xxx_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(src4xxx_reg_defaults),
+ .volatile_reg = src4xxx_volatile_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(src4xxx_regmap_config);
+
+MODULE_DESCRIPTION("ASoC SRC4XXX CODEC driver");
+MODULE_AUTHOR("Matt Flax <flatmax@flatmax.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/src4xxx.h b/sound/soc/codecs/src4xxx.h
new file mode 100644
index 000000000000..5bf778fb9945
--- /dev/null
+++ b/sound/soc/codecs/src4xxx.h
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// src4xxx.h -- SRC4XXX ALSA SoC audio driver
+//
+// Copyright 2021-2022 Deqx Pty Ltd
+// Author: Matt R Flax <flatmax@flatmax.com>
+
+#ifndef __SRC4XXX_H__
+#define __SRC4XXX_H__
+
+#define SRC4XXX_RES_00 0x00
+#define SRC4XXX_PWR_RST_01 0x01
+#define SRC4XXX_RESET 0x80
+#define SRC4XXX_POWER_DOWN 0x00
+#define SRC4XXX_POWER_ENABLE 0x20
+#define SRC4XXX_ENABLE_SRC 0x1
+#define SRC4XXX_ENABLE_SRC_SHIFT 0
+#define SRC4XXX_ENABLE_DIR 0x2
+#define SRC4XXX_ENABLE_DIR_SHIFT 1
+#define SRC4XXX_ENABLE_DIT 0x4
+#define SRC4XXX_ENABLE_DIT_SHIFT 2
+#define SRC4XXX_ENABLE_PORT_B 0x8
+#define SRC4XXX_ENABLE_PORT_B_SHIFT 3
+#define SRC4XXX_ENABLE_PORT_A 0x10
+#define SRC4XXX_ENABLE_PORT_A_SHIFT 4
+
+#define SRC4XXX_PORTA_CTL_03 0x03
+#define SRC4XXX_BUS_MASTER 0x8
+#define SRC4XXX_BUS_LEFT_J 0x0
+#define SRC4XXX_BUS_I2S 0x1
+#define SRC4XXX_BUS_RIGHT_J_16 0x4
+#define SRC4XXX_BUS_RIGHT_J_18 0x5
+#define SRC4XXX_BUS_RIGHT_J_20 0x6
+#define SRC4XXX_BUS_RIGHT_J_24 0x7
+#define SRC4XXX_BUS_FMT_MS_MASK 0xf
+
+#define SRC4XXX_PORTA_CTL_04 0x04
+#define SRC4XXX_MCLK_DIV_MASK 0x3
+
+#define SRC4XXX_BUS_FMT(id) (SRC4XXX_PORTA_CTL_03+2*id)
+#define SRC4XXX_BUS_CLK(id) (SRC4XXX_PORTA_CTL_04+2*id)
+
+#define SRC4XXX_PORTB_CTL_05 0x05
+#define SRC4XXX_PORTB_CTL_06 0x06
+
+#define SRC4XXX_TX_CTL_07 0x07
+#define SRC4XXX_TX_MCLK_DIV_MASK 0x60
+#define SRC4XXX_TX_MCLK_DIV_SHIFT 5
+
+#define SRC4XXX_TX_CTL_08 0x08
+#define SRC4XXX_TX_CTL_09 0x09
+#define SRC4XXX_SRC_DIT_IRQ_MSK_0B 0x0B
+#define SRC4XXX_SRC_BTI_EN 0x01
+#define SRC4XXX_SRC_TSLIP_EN 0x02
+#define SRC4XXX_SRC_DIT_IRQ_MODE_0C 0x0C
+#define SRC4XXX_RCV_CTL_0D 0x0D
+#define SRC4XXX_RXCLK_RXCKI 0x0
+#define SRC4XXX_RXCLK_MCLK 0x8
+#define SRC4XXX_RCV_CTL_0E 0x0E
+#define SRC4XXX_REC_MCLK_EN 0x1
+#define SRC4XXX_PLL2_DIV_0 (0x0<<1)
+#define SRC4XXX_PLL2_DIV_2 (0x1<<1)
+#define SRC4XXX_PLL2_DIV_4 (0x2<<1)
+#define SRC4XXX_PLL2_DIV_8 (0x3<<1)
+#define SRC4XXX_PLL2_LOL 0x8
+#define SRC4XXX_RCV_PLL_0F 0x0F
+#define SRC4XXX_RCV_PLL_10 0x10
+#define SRC4XXX_RCV_PLL_11 0x11
+#define SRC4XXX_RVC_IRQ_MSK_16 0x16
+#define SRC4XXX_RVC_IRQ_MSK_17 0x17
+#define SRC4XXX_RVC_IRQ_MODE_18 0x18
+#define SRC4XXX_RVC_IRQ_MODE_19 0x19
+#define SRC4XXX_RVC_IRQ_MODE_1A 0x1A
+#define SRC4XXX_GPIO_1_1B 0x1B
+#define SRC4XXX_GPIO_2_1C 0x1C
+#define SRC4XXX_GPIO_3_1D 0x1D
+#define SRC4XXX_GPIO_4_1E 0x1E
+#define SRC4XXX_SCR_CTL_2D 0x2D
+#define SRC4XXX_SCR_CTL_2E 0x2E
+#define SRC4XXX_SCR_CTL_2F 0x2F
+#define SRC4XXX_SCR_CTL_30 0x30
+#define SRC4XXX_SCR_CTL_31 0x31
+#define SRC4XXX_PAGE_SEL_7F 0x7F
+
+// read only registers
+#define SRC4XXX_GLOBAL_ITR_STS_02 0x02
+#define SRC4XXX_SRC_DIT_STS_0A 0x0A
+#define SRC4XXX_NON_AUDIO_D_12 0x12
+#define SRC4XXX_RVC_STS_13 0x13
+#define SRC4XXX_RVC_STS_14 0x14
+#define SRC4XXX_RVC_STS_15 0x15
+#define SRC4XXX_SUB_CODE_1F 0x1F
+#define SRC4XXX_SUB_CODE_20 0x20
+#define SRC4XXX_SUB_CODE_21 0x21
+#define SRC4XXX_SUB_CODE_22 0x22
+#define SRC4XXX_SUB_CODE_23 0x23
+#define SRC4XXX_SUB_CODE_24 0x24
+#define SRC4XXX_SUB_CODE_25 0x25
+#define SRC4XXX_SUB_CODE_26 0x26
+#define SRC4XXX_SUB_CODE_27 0x27
+#define SRC4XXX_SUB_CODE_28 0x28
+#define SRC4XXX_PC_PREAMBLE_HI_29 0x29
+#define SRC4XXX_PC_PREAMBLE_LO_2A 0x2A
+#define SRC4XXX_PD_PREAMBLE_HI_2B 0x2B
+#define SRC4XXX_PC_PREAMBLE_LO_2C 0x2C
+#define SRC4XXX_IO_RATIO_32 0x32
+#define SRC4XXX_IO_RATIO_33 0x33
+
+int src4xxx_probe(struct device *dev, struct regmap *regmap,
+ void (*switch_mode)(struct device *dev));
+extern const struct regmap_config src4xxx_regmap_config;
+
+#endif /* __SRC4XXX_H__ */
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index 6d8847848299..22cb3b7c8283 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -6,14 +6,13 @@
* Author: Lars-Peter Clausen <lars@metafoo.de>
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_data/ssm2518.h>
+#include <linux/gpio/consumer.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -114,7 +113,7 @@ struct ssm2518 {
unsigned int sysclk;
const struct snd_pcm_hw_constraint_list *constraints;
- int enable_gpio;
+ struct gpio_desc *enable_gpio;
};
static const struct reg_default ssm2518_reg_defaults[] = {
@@ -483,8 +482,8 @@ static int ssm2518_set_power(struct ssm2518 *ssm2518, bool enable)
regcache_mark_dirty(ssm2518->regmap);
}
- if (gpio_is_valid(ssm2518->enable_gpio))
- gpio_set_value(ssm2518->enable_gpio, enable);
+ if (ssm2518->enable_gpio)
+ gpiod_set_value_cansleep(ssm2518->enable_gpio, enable);
regcache_cache_only(ssm2518->regmap, !enable);
@@ -736,7 +735,6 @@ static const struct regmap_config ssm2518_regmap_config = {
static int ssm2518_i2c_probe(struct i2c_client *i2c)
{
- struct ssm2518_platform_data *pdata = i2c->dev.platform_data;
struct ssm2518 *ssm2518;
int ret;
@@ -744,22 +742,14 @@ static int ssm2518_i2c_probe(struct i2c_client *i2c)
if (ssm2518 == NULL)
return -ENOMEM;
- if (pdata) {
- ssm2518->enable_gpio = pdata->enable_gpio;
- } else if (i2c->dev.of_node) {
- ssm2518->enable_gpio = of_get_gpio(i2c->dev.of_node, 0);
- if (ssm2518->enable_gpio < 0 && ssm2518->enable_gpio != -ENOENT)
- return ssm2518->enable_gpio;
- } else {
- ssm2518->enable_gpio = -1;
- }
+ /* Start with enabling the chip */
+ ssm2518->enable_gpio = devm_gpiod_get_optional(&i2c->dev, NULL,
+ GPIOD_OUT_HIGH);
+ ret = PTR_ERR_OR_ZERO(ssm2518->enable_gpio);
+ if (ret)
+ return ret;
- if (gpio_is_valid(ssm2518->enable_gpio)) {
- ret = devm_gpio_request_one(&i2c->dev, ssm2518->enable_gpio,
- GPIOF_OUT_INIT_HIGH, "SSM2518 nSD");
- if (ret)
- return ret;
- }
+ gpiod_set_consumer_name(ssm2518->enable_gpio, "SSM2518 nSD");
i2c_set_clientdata(i2c, ssm2518);
diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c
index f076878908ee..99545bcb2ba9 100644
--- a/sound/soc/codecs/sti-sas.c
+++ b/sound/soc/codecs/sti-sas.c
@@ -96,11 +96,8 @@ static int sti_sas_write_reg(void *context, unsigned int reg,
unsigned int value)
{
struct sti_sas_data *drvdata = context;
- int status;
-
- status = regmap_write(drvdata->dac.regmap, reg, value);
- return status;
+ return regmap_write(drvdata->dac.regmap, reg, value);
}
static int sti_sas_init_sas_registers(struct snd_soc_component *component,
@@ -385,11 +382,8 @@ static int sti_sas_resume(struct snd_soc_component *component)
static int sti_sas_component_probe(struct snd_soc_component *component)
{
struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
- int ret;
- ret = sti_sas_init_sas_registers(component, drvdata);
-
- return ret;
+ return sti_sas_init_sas_registers(component, drvdata);
}
static struct snd_soc_component_driver sti_sas_driver = {
diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c
index dc088a1c6721..b486d0bd86c9 100644
--- a/sound/soc/codecs/tas2562.c
+++ b/sound/soc/codecs/tas2562.c
@@ -54,6 +54,8 @@ struct tas2562_data {
int i_sense_slot;
int volume_lvl;
int model_id;
+ bool dac_powered;
+ bool unmuted;
};
enum tas256x_model {
@@ -63,39 +65,6 @@ enum tas256x_model {
TAS2110,
};
-static int tas2562_set_bias_level(struct snd_soc_component *component,
- enum snd_soc_bias_level level)
-{
- struct tas2562_data *tas2562 =
- snd_soc_component_get_drvdata(component);
-
- switch (level) {
- case SND_SOC_BIAS_ON:
- snd_soc_component_update_bits(component,
- TAS2562_PWR_CTRL,
- TAS2562_MODE_MASK, TAS2562_ACTIVE);
- break;
- case SND_SOC_BIAS_STANDBY:
- case SND_SOC_BIAS_PREPARE:
- snd_soc_component_update_bits(component,
- TAS2562_PWR_CTRL,
- TAS2562_MODE_MASK, TAS2562_MUTE);
- break;
- case SND_SOC_BIAS_OFF:
- snd_soc_component_update_bits(component,
- TAS2562_PWR_CTRL,
- TAS2562_MODE_MASK, TAS2562_SHUTDOWN);
- break;
-
- default:
- dev_err(tas2562->dev,
- "wrong power level setting %d\n", level);
- return -EINVAL;
- }
-
- return 0;
-}
-
static int tas2562_set_samplerate(struct tas2562_data *tas2562, int samplerate)
{
int samp_rate;
@@ -384,30 +353,43 @@ static int tas2562_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
+static int tas2562_update_pwr_ctrl(struct tas2562_data *tas2562)
+{
+ struct snd_soc_component *component = tas2562->component;
+ unsigned int val;
+ int ret;
+
+ if (tas2562->dac_powered)
+ val = tas2562->unmuted ?
+ TAS2562_ACTIVE : TAS2562_MUTE;
+ else
+ val = TAS2562_SHUTDOWN;
+
+ ret = snd_soc_component_update_bits(component, TAS2562_PWR_CTRL,
+ TAS2562_MODE_MASK, val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int tas2562_mute(struct snd_soc_dai *dai, int mute, int direction)
{
- struct snd_soc_component *component = dai->component;
+ struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(dai->component);
- return snd_soc_component_update_bits(component, TAS2562_PWR_CTRL,
- TAS2562_MODE_MASK,
- mute ? TAS2562_MUTE : 0);
+ tas2562->unmuted = !mute;
+ return tas2562_update_pwr_ctrl(tas2562);
}
static int tas2562_codec_probe(struct snd_soc_component *component)
{
struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
- int ret;
tas2562->component = component;
if (tas2562->sdz_gpio)
gpiod_set_value_cansleep(tas2562->sdz_gpio, 1);
- ret = snd_soc_component_update_bits(component, TAS2562_PWR_CTRL,
- TAS2562_MODE_MASK, TAS2562_MUTE);
- if (ret < 0)
- return ret;
-
return 0;
}
@@ -457,35 +439,23 @@ static int tas2562_dac_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
- int ret;
+ int ret = 0;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- ret = snd_soc_component_update_bits(component,
- TAS2562_PWR_CTRL,
- TAS2562_MODE_MASK,
- TAS2562_MUTE);
- if (ret)
- goto end;
+ tas2562->dac_powered = true;
+ ret = tas2562_update_pwr_ctrl(tas2562);
break;
case SND_SOC_DAPM_PRE_PMD:
- ret = snd_soc_component_update_bits(component,
- TAS2562_PWR_CTRL,
- TAS2562_MODE_MASK,
- TAS2562_SHUTDOWN);
- if (ret)
- goto end;
+ tas2562->dac_powered = false;
+ ret = tas2562_update_pwr_ctrl(tas2562);
break;
default:
dev_err(tas2562->dev, "Not supported evevt\n");
return -EINVAL;
}
-end:
- if (ret < 0)
- return ret;
-
- return 0;
+ return ret;
}
static int tas2562_volume_control_get(struct snd_kcontrol *kcontrol,
@@ -579,7 +549,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2110 = {
.probe = tas2562_codec_probe,
.suspend = tas2562_suspend,
.resume = tas2562_resume,
- .set_bias_level = tas2562_set_bias_level,
.controls = tas2562_snd_controls,
.num_controls = ARRAY_SIZE(tas2562_snd_controls),
.dapm_widgets = tas2110_dapm_widgets,
@@ -618,7 +587,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2562 = {
.probe = tas2562_codec_probe,
.suspend = tas2562_suspend,
.resume = tas2562_resume,
- .set_bias_level = tas2562_set_bias_level,
.controls = tas2562_snd_controls,
.num_controls = ARRAY_SIZE(tas2562_snd_controls),
.dapm_widgets = tas2562_dapm_widgets,
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 846d9d3ecc9d..51b87a936179 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -31,11 +31,66 @@ struct tas2764_priv {
struct gpio_desc *sdz_gpio;
struct regmap *regmap;
struct device *dev;
+ int irq;
int v_sense_slot;
int i_sense_slot;
+
+ bool dac_powered;
+ bool unmuted;
+};
+
+static const char *tas2764_int_ltch0_msgs[8] = {
+ "fault: over temperature", /* INT_LTCH0 & BIT(0) */
+ "fault: over current",
+ "fault: bad TDM clock",
+ "limiter active",
+ "fault: PVDD below limiter inflection point",
+ "fault: limiter max attenuation",
+ "fault: BOP infinite hold",
+ "fault: BOP mute", /* INT_LTCH0 & BIT(7) */
+};
+
+static const unsigned int tas2764_int_readout_regs[6] = {
+ TAS2764_INT_LTCH0,
+ TAS2764_INT_LTCH1,
+ TAS2764_INT_LTCH1_0,
+ TAS2764_INT_LTCH2,
+ TAS2764_INT_LTCH3,
+ TAS2764_INT_LTCH4,
};
+static irqreturn_t tas2764_irq(int irq, void *data)
+{
+ struct tas2764_priv *tas2764 = data;
+ u8 latched[6] = {0, 0, 0, 0, 0, 0};
+ int ret = IRQ_NONE;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(latched); i++)
+ latched[i] = snd_soc_component_read(tas2764->component,
+ tas2764_int_readout_regs[i]);
+
+ for (i = 0; i < 8; i++) {
+ if (latched[0] & BIT(i)) {
+ dev_crit_ratelimited(tas2764->dev, "%s\n",
+ tas2764_int_ltch0_msgs[i]);
+ ret = IRQ_HANDLED;
+ }
+ }
+
+ if (latched[0]) {
+ dev_err_ratelimited(tas2764->dev, "other context to the fault: %02x,%02x,%02x,%02x,%02x",
+ latched[1], latched[2], latched[3], latched[4], latched[5]);
+ snd_soc_component_update_bits(tas2764->component,
+ TAS2764_INT_CLK_CFG,
+ TAS2764_INT_CLK_CFG_IRQZ_CLR,
+ TAS2764_INT_CLK_CFG_IRQZ_CLR);
+ }
+
+ return ret;
+}
+
static void tas2764_reset(struct tas2764_priv *tas2764)
{
if (tas2764->reset_gpio) {
@@ -50,34 +105,22 @@ static void tas2764_reset(struct tas2764_priv *tas2764)
usleep_range(1000, 2000);
}
-static int tas2764_set_bias_level(struct snd_soc_component *component,
- enum snd_soc_bias_level level)
+static int tas2764_update_pwr_ctrl(struct tas2764_priv *tas2764)
{
- struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_component *component = tas2764->component;
+ unsigned int val;
+ int ret;
- switch (level) {
- case SND_SOC_BIAS_ON:
- snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
- TAS2764_PWR_CTRL_MASK,
- TAS2764_PWR_CTRL_ACTIVE);
- break;
- case SND_SOC_BIAS_STANDBY:
- case SND_SOC_BIAS_PREPARE:
- snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
- TAS2764_PWR_CTRL_MASK,
- TAS2764_PWR_CTRL_MUTE);
- break;
- case SND_SOC_BIAS_OFF:
- snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
- TAS2764_PWR_CTRL_MASK,
- TAS2764_PWR_CTRL_SHUTDOWN);
- break;
+ if (tas2764->dac_powered)
+ val = tas2764->unmuted ?
+ TAS2764_PWR_CTRL_ACTIVE : TAS2764_PWR_CTRL_MUTE;
+ else
+ val = TAS2764_PWR_CTRL_SHUTDOWN;
- default:
- dev_err(tas2764->dev,
- "wrong power level setting %d\n", level);
- return -EINVAL;
- }
+ ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
+ TAS2764_PWR_CTRL_MASK, val);
+ if (ret < 0)
+ return ret;
return 0;
}
@@ -114,9 +157,7 @@ static int tas2764_codec_resume(struct snd_soc_component *component)
usleep_range(1000, 2000);
}
- ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
- TAS2764_PWR_CTRL_MASK,
- TAS2764_PWR_CTRL_ACTIVE);
+ ret = tas2764_update_pwr_ctrl(tas2764);
if (ret < 0)
return ret;
@@ -150,14 +191,12 @@ static int tas2764_dac_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
- TAS2764_PWR_CTRL_MASK,
- TAS2764_PWR_CTRL_MUTE);
+ tas2764->dac_powered = true;
+ ret = tas2764_update_pwr_ctrl(tas2764);
break;
case SND_SOC_DAPM_PRE_PMD:
- ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
- TAS2764_PWR_CTRL_MASK,
- TAS2764_PWR_CTRL_SHUTDOWN);
+ tas2764->dac_powered = false;
+ ret = tas2764_update_pwr_ctrl(tas2764);
break;
default:
dev_err(tas2764->dev, "Unsupported event\n");
@@ -202,17 +241,11 @@ static const struct snd_soc_dapm_route tas2764_audio_map[] = {
static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction)
{
- struct snd_soc_component *component = dai->component;
- int ret;
-
- ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
- TAS2764_PWR_CTRL_MASK,
- mute ? TAS2764_PWR_CTRL_MUTE : 0);
+ struct tas2764_priv *tas2764 =
+ snd_soc_component_get_drvdata(dai->component);
- if (ret < 0)
- return ret;
-
- return 0;
+ tas2764->unmuted = !mute;
+ return tas2764_update_pwr_ctrl(tas2764);
}
static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth)
@@ -485,7 +518,7 @@ static struct snd_soc_dai_driver tas2764_dai_driver[] = {
.id = 0,
.playback = {
.stream_name = "ASI1 Playback",
- .channels_min = 2,
+ .channels_min = 1,
.channels_max = 2,
.rates = TAS2764_RATES,
.formats = TAS2764_FORMATS,
@@ -516,6 +549,34 @@ static int tas2764_codec_probe(struct snd_soc_component *component)
tas2764_reset(tas2764);
+ if (tas2764->irq) {
+ ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK0, 0xff);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK1, 0xff);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK2, 0xff);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK3, 0xff);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK4, 0xff);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_request_threaded_irq(tas2764->dev, tas2764->irq, NULL, tas2764_irq,
+ IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
+ "tas2764", tas2764);
+ if (ret)
+ dev_warn(tas2764->dev, "failed to request IRQ: %d\n", ret);
+ }
+
ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5,
TAS2764_TDM_CFG5_VSNS_ENABLE, 0);
if (ret < 0)
@@ -526,30 +587,33 @@ static int tas2764_codec_probe(struct snd_soc_component *component)
if (ret < 0)
return ret;
- ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
- TAS2764_PWR_CTRL_MASK,
- TAS2764_PWR_CTRL_MUTE);
- if (ret < 0)
- return ret;
-
return 0;
}
static DECLARE_TLV_DB_SCALE(tas2764_digital_tlv, 1100, 50, 0);
static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10050, 50, 1);
+static const char * const tas2764_hpf_texts[] = {
+ "Disabled", "2 Hz", "50 Hz", "100 Hz", "200 Hz",
+ "400 Hz", "800 Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ tas2764_hpf_enum, TAS2764_DC_BLK0,
+ TAS2764_DC_BLK0_HPF_FREQ_PB_SHIFT, tas2764_hpf_texts);
+
static const struct snd_kcontrol_new tas2764_snd_controls[] = {
SOC_SINGLE_TLV("Speaker Volume", TAS2764_DVC, 0,
TAS2764_DVC_MAX, 1, tas2764_playback_volume),
SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 1, 0x14, 0,
tas2764_digital_tlv),
+ SOC_ENUM("HPF Corner Frequency", tas2764_hpf_enum),
};
static const struct snd_soc_component_driver soc_component_driver_tas2764 = {
.probe = tas2764_codec_probe,
.suspend = tas2764_codec_suspend,
.resume = tas2764_codec_resume,
- .set_bias_level = tas2764_set_bias_level,
.controls = tas2764_snd_controls,
.num_controls = ARRAY_SIZE(tas2764_snd_controls),
.dapm_widgets = tas2764_dapm_widgets,
@@ -585,9 +649,21 @@ static const struct regmap_range_cfg tas2764_regmap_ranges[] = {
},
};
+static bool tas2764_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4:
+ case TAS2764_INT_CLK_CFG:
+ return true;
+ default:
+ return false;
+ }
+}
+
static const struct regmap_config tas2764_i2c_regmap = {
.reg_bits = 8,
.val_bits = 8,
+ .volatile_reg = tas2764_volatile_register,
.reg_defaults = tas2764_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(tas2764_reg_defaults),
.cache_type = REGCACHE_RBTREE,
@@ -641,6 +717,7 @@ static int tas2764_i2c_probe(struct i2c_client *client)
return -ENOMEM;
tas2764->dev = &client->dev;
+ tas2764->irq = client->irq;
i2c_set_clientdata(client, tas2764);
dev_set_drvdata(&client->dev, tas2764);
diff --git a/sound/soc/codecs/tas2764.h b/sound/soc/codecs/tas2764.h
index f015f22a083b..168af772a898 100644
--- a/sound/soc/codecs/tas2764.h
+++ b/sound/soc/codecs/tas2764.h
@@ -33,6 +33,10 @@
#define TAS2764_VSENSE_POWER_EN 3
#define TAS2764_ISENSE_POWER_EN 4
+/* DC Blocker Control */
+#define TAS2764_DC_BLK0 TAS2764_REG(0x0, 0x04)
+#define TAS2764_DC_BLK0_HPF_FREQ_PB_SHIFT 0
+
/* Digital Volume Control */
#define TAS2764_DVC TAS2764_REG(0X0, 0x1a)
#define TAS2764_DVC_MAX 0xc9
@@ -87,4 +91,23 @@
#define TAS2764_TDM_CFG6_ISNS_ENABLE BIT(6)
#define TAS2764_TDM_CFG6_50_MASK GENMASK(5, 0)
+/* Interrupt Masks */
+#define TAS2764_INT_MASK0 TAS2764_REG(0x0, 0x3b)
+#define TAS2764_INT_MASK1 TAS2764_REG(0x0, 0x3c)
+#define TAS2764_INT_MASK2 TAS2764_REG(0x0, 0x40)
+#define TAS2764_INT_MASK3 TAS2764_REG(0x0, 0x41)
+#define TAS2764_INT_MASK4 TAS2764_REG(0x0, 0x3d)
+
+/* Latched Fault Registers */
+#define TAS2764_INT_LTCH0 TAS2764_REG(0x0, 0x49)
+#define TAS2764_INT_LTCH1 TAS2764_REG(0x0, 0x4a)
+#define TAS2764_INT_LTCH1_0 TAS2764_REG(0x0, 0x4b)
+#define TAS2764_INT_LTCH2 TAS2764_REG(0x0, 0x4f)
+#define TAS2764_INT_LTCH3 TAS2764_REG(0x0, 0x50)
+#define TAS2764_INT_LTCH4 TAS2764_REG(0x0, 0x51)
+
+/* Clock/IRQ Settings */
+#define TAS2764_INT_CLK_CFG TAS2764_REG(0x0, 0x5c)
+#define TAS2764_INT_CLK_CFG_IRQZ_CLR BIT(2)
+
#endif /* __TAS2764__ */
diff --git a/sound/soc/codecs/tfa989x.c b/sound/soc/codecs/tfa989x.c
index 1c27429b9af6..b853507e65a8 100644
--- a/sound/soc/codecs/tfa989x.c
+++ b/sound/soc/codecs/tfa989x.c
@@ -193,7 +193,7 @@ static int tfa9890_init(struct regmap *regmap)
{
int ret;
- /* unhide keys to allow updating them */
+ /* temporarily allow access to hidden registers */
ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x5a6b);
if (ret)
return ret;
@@ -203,7 +203,7 @@ static int tfa9890_init(struct regmap *regmap)
if (ret)
return ret;
- /* hide keys again */
+ /* hide registers again */
ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x0000);
if (ret)
return ret;
diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c
index 2844a9d2bc4a..91a22d927915 100644
--- a/sound/soc/codecs/tlv320adcx140.c
+++ b/sound/soc/codecs/tlv320adcx140.c
@@ -31,6 +31,7 @@ struct adcx140_priv {
struct device *dev;
bool micbias_vg;
+ bool phase_calib_on;
unsigned int dai_fmt;
unsigned int slot_width;
@@ -592,6 +593,52 @@ static const struct snd_soc_dapm_route adcx140_audio_map[] = {
{"MIC4M Input Mux", "Digital", "MIC4M"},
};
+#define ADCX140_PHASE_CALIB_SWITCH(xname) {\
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+ .info = adcx140_phase_calib_info, \
+ .get = adcx140_phase_calib_get, \
+ .put = adcx140_phase_calib_put}
+
+static int adcx140_phase_calib_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int adcx140_phase_calib_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ struct snd_soc_component *codec =
+ snd_soc_kcontrol_component(kcontrol);
+ struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(codec);
+
+ value->value.integer.value[0] = adcx140->phase_calib_on ? 1 : 0;
+
+
+ return 0;
+}
+
+static int adcx140_phase_calib_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ struct snd_soc_component *codec
+ = snd_soc_kcontrol_component(kcontrol);
+ struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(codec);
+
+ bool v = value->value.integer.value[0] ? true : false;
+
+ if (adcx140->phase_calib_on != v) {
+ adcx140->phase_calib_on = v;
+ return 1;
+ }
+ return 0;
+}
+
static const struct snd_kcontrol_new adcx140_snd_controls[] = {
SOC_SINGLE_TLV("Analog CH1 Mic Gain Volume", ADCX140_CH1_CFG1, 2, 42, 0,
adc_tlv),
@@ -628,6 +675,7 @@ static const struct snd_kcontrol_new adcx140_snd_controls[] = {
0, 0xff, 0, dig_vol_tlv),
SOC_SINGLE_TLV("Digital CH8 Out Volume", ADCX140_CH8_CFG2,
0, 0xff, 0, dig_vol_tlv),
+ ADCX140_PHASE_CALIB_SWITCH("Phase Calibration Switch"),
};
static int adcx140_reset(struct adcx140_priv *adcx140)
@@ -653,6 +701,8 @@ static int adcx140_reset(struct adcx140_priv *adcx140)
static void adcx140_pwr_ctrl(struct adcx140_priv *adcx140, bool power_state)
{
int pwr_ctrl = 0;
+ int ret = 0;
+ struct snd_soc_component *component = adcx140->component;
if (power_state)
pwr_ctrl = ADCX140_PWR_CFG_ADC_PDZ | ADCX140_PWR_CFG_PLL_PDZ;
@@ -660,6 +710,14 @@ static void adcx140_pwr_ctrl(struct adcx140_priv *adcx140, bool power_state)
if (adcx140->micbias_vg && power_state)
pwr_ctrl |= ADCX140_PWR_CFG_BIAS_PDZ;
+ if (pwr_ctrl) {
+ ret = regmap_write(adcx140->regmap, ADCX140_PHASE_CALIB,
+ adcx140->phase_calib_on ? 0x00 : 0x40);
+ if (ret)
+ dev_err(component->dev, "%s: register write error %d\n",
+ __func__, ret);
+ }
+
regmap_update_bits(adcx140->regmap, ADCX140_PWR_CFG,
ADCX140_PWR_CTRL_MSK, pwr_ctrl);
}
@@ -1095,6 +1153,7 @@ static int adcx140_i2c_probe(struct i2c_client *i2c)
if (!adcx140)
return -ENOMEM;
+ adcx140->phase_calib_on = false;
adcx140->dev = &i2c->dev;
adcx140->gpio_reset = devm_gpiod_get_optional(adcx140->dev,
diff --git a/sound/soc/codecs/tlv320adcx140.h b/sound/soc/codecs/tlv320adcx140.h
index d7d4e3a88b5c..fd80fac8b327 100644
--- a/sound/soc/codecs/tlv320adcx140.h
+++ b/sound/soc/codecs/tlv320adcx140.h
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-// TLV320ADCX104 Sound driver
+// TLV320ADCX140 Sound driver
// Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com/
#ifndef _TLV320ADCX140_H
@@ -90,6 +90,7 @@
#define ADCX140_PWR_CFG 0x75
#define ADCX140_DEV_STS0 0x76
#define ADCX140_DEV_STS1 0x77
+#define ADCX140_PHASE_CALIB 0X7b
#define ADCX140_RESET BIT(0)
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 8bae4b475068..e5dfb3d752a3 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -271,7 +271,7 @@ static ssize_t keyclick_show(struct device *dev,
freq = (125 << ((val >> 8) & 0x7)) >> 1;
len = 2 * (1 + ((val >> 4) & 0xf));
- return sprintf(buf, "amp=%x freq=%iHz len=%iclks\n", amp, freq, len);
+ return sysfs_emit(buf, "amp=%x freq=%iHz len=%iclks\n", amp, freq, len);
}
/* Any write to the keyclick attribute will trigger the keyclick event */
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
index d8ab0810fceb..2305a472d132 100644
--- a/sound/soc/codecs/ts3a227e.c
+++ b/sound/soc/codecs/ts3a227e.c
@@ -78,12 +78,20 @@ static const int ts3a227e_buttons[] = {
#define ADC_COMPLETE_INT_DISABLE 0x04
#define INTB_DISABLE 0x08
+/* TS3A227E_REG_SETTING_1 0x4 */
+#define DEBOUNCE_INSERTION_SETTING_SFT (0)
+#define DEBOUNCE_INSERTION_SETTING_MASK (0x7 << DEBOUNCE_PRESS_SETTING_SFT)
+
/* TS3A227E_REG_SETTING_2 0x05 */
#define KP_ENABLE 0x04
/* TS3A227E_REG_SETTING_3 0x06 */
-#define MICBIAS_SETTING_SFT (3)
+#define MICBIAS_SETTING_SFT 3
#define MICBIAS_SETTING_MASK (0x7 << MICBIAS_SETTING_SFT)
+#define DEBOUNCE_RELEASE_SETTING_SFT 2
+#define DEBOUNCE_RELEASE_SETTING_MASK (0x1 << DEBOUNCE_RELEASE_SETTING_SFT)
+#define DEBOUNCE_PRESS_SETTING_SFT 0
+#define DEBOUNCE_PRESS_SETTING_MASK (0x3 << DEBOUNCE_PRESS_SETTING_SFT)
/* TS3A227E_REG_ACCESSORY_STATUS 0x0b */
#define TYPE_3_POLE 0x01
@@ -136,7 +144,7 @@ static bool ts3a227e_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case TS3A227E_REG_INTERRUPT ... TS3A227E_REG_INTERRUPT_DISABLE:
- case TS3A227E_REG_SETTING_2:
+ case TS3A227E_REG_SETTING_1 ... TS3A227E_REG_SETTING_2:
case TS3A227E_REG_SWITCH_STATUS_1 ... TS3A227E_REG_ADC_OUTPUT:
return true;
default:
@@ -269,14 +277,55 @@ static const struct regmap_config ts3a227e_regmap_config = {
static int ts3a227e_parse_device_property(struct ts3a227e *ts3a227e,
struct device *dev)
{
- u32 micbias;
+ u32 value;
+ u32 value_ms;
+ u32 setting3_value = 0;
+ u32 setting3_mask = 0;
int err;
- err = device_property_read_u32(dev, "ti,micbias", &micbias);
+ err = device_property_read_u32(dev, "ti,micbias", &value);
+ if (!err) {
+ setting3_mask = MICBIAS_SETTING_MASK;
+ setting3_value = (value << MICBIAS_SETTING_SFT) &
+ MICBIAS_SETTING_MASK;
+ }
+
+ err = device_property_read_u32(dev, "ti,debounce-release-ms",
+ &value_ms);
if (!err) {
+ value = (value_ms > 10);
+ setting3_mask |= DEBOUNCE_RELEASE_SETTING_MASK;
+ setting3_value |= (value << DEBOUNCE_RELEASE_SETTING_SFT) &
+ DEBOUNCE_RELEASE_SETTING_MASK;
+ }
+
+ err = device_property_read_u32(dev, "ti,debounce-press-ms", &value_ms);
+ if (!err) {
+ value = (value_ms + 20) / 40;
+ if (value > 3)
+ value = 3;
+ setting3_mask |= DEBOUNCE_PRESS_SETTING_MASK;
+ setting3_value |= (value << DEBOUNCE_PRESS_SETTING_SFT) &
+ DEBOUNCE_PRESS_SETTING_MASK;
+ }
+
+ if (setting3_mask)
regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_3,
- MICBIAS_SETTING_MASK,
- (micbias & 0x07) << MICBIAS_SETTING_SFT);
+ setting3_mask, setting3_value);
+
+ err = device_property_read_u32(dev, "ti,debounce-insertion-ms",
+ &value_ms);
+ if (!err) {
+ if (value_ms < 165)
+ value = (value_ms + 15) / 30;
+ else if (value_ms < 1500)
+ value = 6;
+ else
+ value = 7;
+ regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_1,
+ DEBOUNCE_INSERTION_SETTING_MASK,
+ (value << DEBOUNCE_INSERTION_SETTING_SFT) &
+ DEBOUNCE_INSERTION_SETTING_MASK);
}
return 0;
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index 2db3d8a60c7a..1a62bec94005 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -450,7 +450,7 @@ static int uda134x_soc_probe(struct snd_soc_component *component)
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
struct uda134x_platform_data *pd = uda134x->pd;
const struct snd_soc_dapm_widget *widgets;
- unsigned num_widgets;
+ unsigned int num_widgets;
int ret;
printk(KERN_INFO "UDA134X SoC Audio Codec\n");
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index 98baef594bf3..1911750f7445 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -714,11 +714,12 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
struct snd_soc_component *component = mbhc->component;
int ret;
- ret = pm_runtime_resume_and_get(component->dev);
+ ret = pm_runtime_get_sync(component->dev);
if (ret < 0 && ret != -EACCES) {
dev_err_ratelimited(component->dev,
- "pm_runtime_resume_and_get failed in %s, ret %d\n",
+ "pm_runtime_get_sync failed in %s, ret %d\n",
__func__, ret);
+ pm_runtime_put_noidle(component->dev);
return ret;
}
@@ -1096,11 +1097,12 @@ static void wcd_correct_swch_plug(struct work_struct *work)
mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
component = mbhc->component;
- ret = pm_runtime_resume_and_get(component->dev);
+ ret = pm_runtime_get_sync(component->dev);
if (ret < 0 && ret != -EACCES) {
dev_err_ratelimited(component->dev,
- "pm_runtime_resume_and_get failed in %s, ret %d\n",
+ "pm_runtime_get_sync failed in %s, ret %d\n",
__func__, ret);
+ pm_runtime_put_noidle(component->dev);
return;
}
micbias_mv = wcd_mbhc_get_micbias(mbhc);
@@ -1189,7 +1191,7 @@ correct_plug_type:
pt_gnd_mic_swap_cnt = 0;
plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
continue;
- } else if (cross_conn < 0) /* Error */
+ } else /* Error if (cross_conn < 0) */
continue;
if (pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD) {
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index beeeb35e8032..d2548fdf9ae5 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -1821,12 +1821,10 @@ static int wcd9335_set_decimator_rate(struct snd_soc_dai *dai,
tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3;
shift = 0;
shift_val = 0x0F;
- } else if (tx_port == 13) {
+ } else /* (tx_port == 13) */ {
tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3;
shift = 4;
shift_val = 0x03;
- } else {
- return -EINVAL;
}
tx_mux_sel = snd_soc_component_read(comp, tx_port_reg) &
@@ -1974,8 +1972,8 @@ static int wcd9335_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- slim_stream_unprepare(dai_data->sruntime);
slim_stream_disable(dai_data->sruntime);
+ slim_stream_unprepare(dai_data->sruntime);
break;
default:
break;
@@ -5013,16 +5011,22 @@ static const struct regmap_irq wcd9335_codec_irqs[] = {
},
};
+static const unsigned int wcd9335_config_regs[] = {
+ WCD9335_INTR_LEVEL0,
+};
+
static const struct regmap_irq_chip wcd9335_regmap_irq1_chip = {
.name = "wcd9335_pin1_irq",
.status_base = WCD9335_INTR_PIN1_STATUS0,
.mask_base = WCD9335_INTR_PIN1_MASK0,
.ack_base = WCD9335_INTR_PIN1_CLEAR0,
- .type_base = WCD9335_INTR_LEVEL0,
- .num_type_reg = 4,
.num_regs = 4,
.irqs = wcd9335_codec_irqs,
.num_irqs = ARRAY_SIZE(wcd9335_codec_irqs),
+ .config_base = wcd9335_config_regs,
+ .num_config_bases = ARRAY_SIZE(wcd9335_config_regs),
+ .num_config_regs = 4,
+ .set_type_config = regmap_irq_set_type_config_simple,
};
static int wcd9335_parse_dt(struct wcd9335_codec *wcd)
diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c
index f56907d0942d..28175c746b9a 100644
--- a/sound/soc/codecs/wcd934x.c
+++ b/sound/soc/codecs/wcd934x.c
@@ -1913,8 +1913,8 @@ static int wcd934x_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- slim_stream_unprepare(dai_data->sruntime);
slim_stream_disable(dai_data->sruntime);
+ slim_stream_unprepare(dai_data->sruntime);
break;
default:
break;
diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index 781ae569be29..aca06a4026f3 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -1298,7 +1298,6 @@ static struct regmap_irq_chip wcd938x_regmap_irq_chip = {
.num_regs = 3,
.status_base = WCD938X_DIGITAL_INTR_STATUS_0,
.mask_base = WCD938X_DIGITAL_INTR_MASK_0,
- .type_base = WCD938X_DIGITAL_INTR_LEVEL_0,
.ack_base = WCD938X_DIGITAL_INTR_CLEAR_0,
.use_ack = 1,
.runtime_pm = true,
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index af7d324e3352..c09c9ac51b3e 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -2099,9 +2099,6 @@ 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);
@@ -2134,6 +2131,9 @@ 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:
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index f3f4a10bf0f7..fc634c995834 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -2457,9 +2457,6 @@ 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);
@@ -2492,6 +2489,9 @@ 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:
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index 210ad662fc26..77136a521605 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -1161,9 +1161,6 @@ 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);
@@ -1182,6 +1179,9 @@ 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:
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index cfaa45ede916..8a2e9771bb50 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -1602,7 +1602,9 @@ static int wm_adsp_buffer_init(struct wm_adsp *dsp)
if (list_empty(&dsp->buffer_list)) {
/* Fall back to legacy support */
ret = wm_adsp_buffer_parse_legacy(dsp);
- if (ret)
+ if (ret == -ENODEV)
+ adsp_info(dsp, "Legacy support not available\n");
+ else if (ret)
adsp_warn(dsp, "Failed to parse legacy: %d\n", ret);
}
diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
index 63e1d7aa6137..c7b10bbfba7e 100644
--- a/sound/soc/codecs/wsa883x.c
+++ b/sound/soc/codecs/wsa883x.c
@@ -415,7 +415,6 @@
#define WSA883X_NUM_REGISTERS (WSA883X_EMEM_63 + 1)
#define WSA883X_MAX_REGISTER (WSA883X_NUM_REGISTERS - 1)
-#define WSA883X_PROBE_TIMEOUT 1000
#define WSA883X_VERSION_1_0 0
#define WSA883X_VERSION_1_1 1
@@ -1409,6 +1408,7 @@ static int wsa883x_probe(struct sdw_slave *pdev,
wsa883x->sconfig.type = SDW_STREAM_PDM;
pdev->prop.sink_ports = GENMASK(WSA883X_MAX_SWR_PORTS, 0);
+ 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);
@@ -1440,43 +1440,17 @@ err:
static int __maybe_unused wsa883x_runtime_suspend(struct device *dev)
{
struct regmap *regmap = dev_get_regmap(dev, NULL);
- struct wsa883x_priv *wsa883x = dev_get_drvdata(dev);
-
- gpiod_direction_output(wsa883x->sd_n, 0);
regcache_cache_only(regmap, true);
regcache_mark_dirty(regmap);
- regulator_disable(wsa883x->vdd);
return 0;
}
static int __maybe_unused wsa883x_runtime_resume(struct device *dev)
{
- struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct regmap *regmap = dev_get_regmap(dev, NULL);
- struct wsa883x_priv *wsa883x = dev_get_drvdata(dev);
- unsigned long time;
- int ret;
-
- ret = regulator_enable(wsa883x->vdd);
- if (ret) {
- dev_err(dev, "Failed to enable vdd regulator (%d)\n", ret);
- return ret;
- }
-
- gpiod_direction_output(wsa883x->sd_n, 1);
-
- time = wait_for_completion_timeout(&slave->initialization_complete,
- msecs_to_jiffies(WSA883X_PROBE_TIMEOUT));
- if (!time) {
- dev_err(dev, "Initialization not complete, timed out\n");
- gpiod_direction_output(wsa883x->sd_n, 0);
- regulator_disable(wsa883x->vdd);
- return -ETIMEDOUT;
- }
- usleep_range(20000, 20010);
regcache_cache_only(regmap, false);
regcache_sync(regmap);