summaryrefslogtreecommitdiff
path: root/sound/soc/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/Kconfig56
-rw-r--r--sound/soc/codecs/Makefile19
-rw-r--r--sound/soc/codecs/adau7118.c6
-rw-r--r--sound/soc/codecs/ak4118.c1
-rw-r--r--sound/soc/codecs/ak4458.c12
-rw-r--r--sound/soc/codecs/ak4613.c2
-rw-r--r--sound/soc/codecs/ak4619.c912
-rw-r--r--sound/soc/codecs/audio-iio-aux.c83
-rw-r--r--sound/soc/codecs/aw87390.c2
-rw-r--r--sound/soc/codecs/aw88261.c2
-rw-r--r--sound/soc/codecs/aw88395/aw88395.c4
-rw-r--r--sound/soc/codecs/aw88395/aw88395_lib.c51
-rw-r--r--sound/soc/codecs/aw88399.c4
-rw-r--r--sound/soc/codecs/cs35l34.c2
-rw-r--r--sound/soc/codecs/cs35l35.c2
-rw-r--r--sound/soc/codecs/cs35l36.c2
-rw-r--r--sound/soc/codecs/cs35l41-lib.c4
-rw-r--r--sound/soc/codecs/cs35l41.c3
-rw-r--r--sound/soc/codecs/cs35l56-sdw.c75
-rw-r--r--sound/soc/codecs/cs35l56-shared.c133
-rw-r--r--sound/soc/codecs/cs35l56.c211
-rw-r--r--sound/soc/codecs/cs35l56.h2
-rw-r--r--sound/soc/codecs/cs530x-i2c.c72
-rw-r--r--sound/soc/codecs/cs530x.c971
-rw-r--r--sound/soc/codecs/cs530x.h223
-rw-r--r--sound/soc/codecs/cs53l30.c3
-rw-r--r--sound/soc/codecs/cx2072x.c5
-rw-r--r--sound/soc/codecs/da7213.c2
-rw-r--r--sound/soc/codecs/es8311.c973
-rw-r--r--sound/soc/codecs/es8311.h162
-rw-r--r--sound/soc/codecs/es8326.c58
-rw-r--r--sound/soc/codecs/framer-codec.c2
-rw-r--r--sound/soc/codecs/hdmi-codec.c2
-rw-r--r--sound/soc/codecs/idt821034.c2
-rw-r--r--sound/soc/codecs/jz4760.c2
-rw-r--r--sound/soc/codecs/jz4770.c2
-rw-r--r--sound/soc/codecs/lpass-macro-common.c23
-rw-r--r--sound/soc/codecs/lpass-macro-common.h41
-rw-r--r--sound/soc/codecs/lpass-rx-macro.c623
-rw-r--r--sound/soc/codecs/lpass-tx-macro.c2
-rw-r--r--sound/soc/codecs/lpass-va-macro.c31
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.c644
-rw-r--r--sound/soc/codecs/max98088.c10
-rw-r--r--sound/soc/codecs/max98390.c1
-rw-r--r--sound/soc/codecs/max98504.c6
-rw-r--r--sound/soc/codecs/mt6358.c38
-rw-r--r--sound/soc/codecs/nau8822.c76
-rw-r--r--sound/soc/codecs/nau8822.h1
-rw-r--r--sound/soc/codecs/nau8824.c21
-rw-r--r--sound/soc/codecs/nau8824.h1
-rw-r--r--sound/soc/codecs/pcm3168a.c3
-rw-r--r--sound/soc/codecs/pcm512x-i2c.c2
-rw-r--r--sound/soc/codecs/pcm512x-spi.c2
-rw-r--r--sound/soc/codecs/pcm6240.c67
-rw-r--r--sound/soc/codecs/peb2466.c2
-rw-r--r--sound/soc/codecs/rk817_codec.c1
-rw-r--r--sound/soc/codecs/rt1318.c1354
-rw-r--r--sound/soc/codecs/rt1318.h342
-rw-r--r--sound/soc/codecs/rt1320-sdw.c2260
-rw-r--r--sound/soc/codecs/rt1320-sdw.h94
-rw-r--r--sound/soc/codecs/rt711-sdca.c72
-rw-r--r--sound/soc/codecs/rt711-sdca.h1
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.c36
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.h95
-rw-r--r--sound/soc/codecs/rt712-sdca.c665
-rw-r--r--sound/soc/codecs/rt712-sdca.h48
-rw-r--r--sound/soc/codecs/simple-mux.c55
-rw-r--r--sound/soc/codecs/tas2552.c1
-rw-r--r--sound/soc/codecs/tas2764.c1
-rw-r--r--sound/soc/codecs/tas2770.c1
-rw-r--r--sound/soc/codecs/tas2780.c1
-rw-r--r--sound/soc/codecs/tas2781-comlib.c21
-rw-r--r--sound/soc/codecs/tas2781-fmwlib.c89
-rw-r--r--sound/soc/codecs/tas2781-i2c.c235
-rw-r--r--sound/soc/codecs/tas5086.c27
-rw-r--r--sound/soc/codecs/tlv320adc3xxx.c106
-rw-r--r--sound/soc/codecs/tlv320adcx140.c1
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c1
-rw-r--r--sound/soc/codecs/ts3a227e.c1
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.c4
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.h4
-rw-r--r--sound/soc/codecs/wcd9335.c128
-rw-r--r--sound/soc/codecs/wcd934x.c72
-rw-r--r--sound/soc/codecs/wcd937x-sdw.c1137
-rw-r--r--sound/soc/codecs/wcd937x.c2971
-rw-r--r--sound/soc/codecs/wcd937x.h624
-rw-r--r--sound/soc/codecs/wcd938x-sdw.c4
-rw-r--r--sound/soc/codecs/wcd938x.c36
-rw-r--r--sound/soc/codecs/wcd938x.h10
-rw-r--r--sound/soc/codecs/wcd939x-sdw.c4
-rw-r--r--sound/soc/codecs/wcd939x.c176
-rw-r--r--sound/soc/codecs/wcd939x.h18
-rw-r--r--sound/soc/codecs/wm0010.c8
-rw-r--r--sound/soc/codecs/wm_adsp.c2
-rw-r--r--sound/soc/codecs/wsa881x.c2
-rw-r--r--sound/soc/codecs/wsa883x.c11
-rw-r--r--sound/soc/codecs/wsa884x.c10
97 files changed, 14910 insertions, 1480 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 4afc43d3f71f..97bb69c9848d 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -45,6 +45,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_AK4535
imply SND_SOC_AK4554
imply SND_SOC_AK4613
+ imply SND_SOC_AK4619
imply SND_SOC_AK4641
imply SND_SOC_AK4642
imply SND_SOC_AK4671
@@ -99,6 +100,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_CS47L90
imply SND_SOC_CS47L92
imply SND_SOC_CS53L30
+ imply SND_SOC_CS530X_I2C
imply SND_SOC_CX20442
imply SND_SOC_CX2072X
imply SND_SOC_DA7210
@@ -221,7 +223,9 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RT722_SDCA_SDW
imply SND_SOC_RT1308_SDW
imply SND_SOC_RT1316_SDW
+ imply SND_SOC_RT1318
imply SND_SOC_RT1318_SDW
+ imply SND_SOC_RT1320_SDW
imply SND_SOC_RT9120
imply SND_SOC_RTQ9128
imply SND_SOC_SDW_MOCKUP
@@ -278,6 +282,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_UDA1380
imply SND_SOC_WCD9335
imply SND_SOC_WCD934X
+ imply SND_SOC_WCD937X_SDW
imply SND_SOC_WCD938X_SDW
imply SND_SOC_WCD939X_SDW
imply SND_SOC_LPASS_MACRO_COMMON
@@ -596,6 +601,10 @@ config SND_SOC_AK4613
tristate "AKM AK4613 CODEC"
depends on I2C
+config SND_SOC_AK4619
+ tristate "AKM AK4619 CODEC"
+ depends on I2C
+
config SND_SOC_AK4641
tristate
depends on I2C
@@ -997,6 +1006,19 @@ config SND_SOC_CS53L30
tristate "Cirrus Logic CS53L30 CODEC"
depends on I2C
+config SND_SOC_CS530X
+ tristate
+
+config SND_SOC_CS530X_I2C
+ tristate "Cirrus Logic CS530x ADCs (I2C)"
+ depends on I2C
+ select REGMAP
+ select REGMAP_I2C
+ select SND_SOC_CS530X
+ help
+ Enable support for Cirrus Logic CS530X ADCs
+ with I2C control.
+
config SND_SOC_CX20442
tristate
depends on TTY
@@ -1101,6 +1123,10 @@ config SND_SOC_ES83XX_DSM_COMMON
depends on ACPI
tristate
+config SND_SOC_ES8311
+ tristate "Everest Semi ES8311 CODEC"
+ depends on I2C
+
config SND_SOC_ES8316
tristate "Everest Semi ES8316 CODEC"
depends on I2C
@@ -1570,11 +1596,21 @@ config SND_SOC_RT1316_SDW
depends on SOUNDWIRE
select REGMAP_SOUNDWIRE
+config SND_SOC_RT1318
+ tristate
+ depends on I2C
+
config SND_SOC_RT1318_SDW
tristate "Realtek RT1318 Codec - SDW"
depends on SOUNDWIRE
select REGMAP_SOUNDWIRE
+config SND_SOC_RT1320_SDW
+ tristate "Realtek RT1320 Codec - SDW"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ select REGMAP_SOUNDWIRE_MBQ
+
config SND_SOC_RT5514
tristate
depends on I2C
@@ -2100,6 +2136,25 @@ config SND_SOC_WCD934X
The WCD9340/9341 is a audio codec IC Integrated in
Qualcomm SoCs like SDM845.
+config SND_SOC_WCD937X
+ depends on SND_SOC_WCD937X_SDW
+ tristate
+ depends on SOUNDWIRE || !SOUNDWIRE
+ select SND_SOC_WCD_CLASSH
+
+config SND_SOC_WCD937X_SDW
+ tristate "WCD9370/WCD9375 Codec - SDW"
+ select SND_SOC_WCD937X
+ select SND_SOC_WCD_MBHC
+ select REGMAP_IRQ
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ help
+ The WCD9370/9375 is an audio codec IC used with SoCs
+ like SC7280 or QCM6490 chipsets, and it connected
+ via soundwire.
+ To compile this codec driver say Y or m.
+
config SND_SOC_WCD938X
depends on SND_SOC_WCD938X_SDW
tristate
@@ -2502,6 +2557,7 @@ config SND_SOC_LPASS_MACRO_COMMON
config SND_SOC_LPASS_WSA_MACRO
depends on COMMON_CLK
select REGMAP_MMIO
+ select SND_SOC_LPASS_MACRO_COMMON
tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)"
config SND_SOC_LPASS_VA_MACRO
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index b4df22186e25..5868007e1045 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -39,6 +39,7 @@ snd-soc-ak4458-y := ak4458.o
snd-soc-ak4535-y := ak4535.o
snd-soc-ak4554-y := ak4554.o
snd-soc-ak4613-y := ak4613.o
+snd-soc-ak4619-y := ak4619.o
snd-soc-ak4641-y := ak4641.o
snd-soc-ak4642-y := ak4642.o
snd-soc-ak4671-y := ak4671.o
@@ -107,6 +108,8 @@ snd-soc-cs47l85-y := cs47l85.o
snd-soc-cs47l90-y := cs47l90.o
snd-soc-cs47l92-y := cs47l92.o
snd-soc-cs53l30-y := cs53l30.o
+snd-soc-cs530x-y := cs530x.o
+snd-soc-cs530x-i2c-y := cs530x-i2c.o
snd-soc-cx20442-y := cx20442.o
snd-soc-cx2072x-y := cx2072x.o
snd-soc-da7210-y := da7210.o
@@ -119,6 +122,7 @@ snd-soc-dmic-y := dmic.o
snd-soc-es7134-y := es7134.o
snd-soc-es7241-y := es7241.o
snd-soc-es83xx-dsm-common-y := es83xx-dsm-common.o
+snd-soc-es8311-y := es8311.o
snd-soc-es8316-y := es8316.o
snd-soc-es8326-y := es8326.o
snd-soc-es8328-y := es8328.o
@@ -221,7 +225,9 @@ snd-soc-rt1305-y := rt1305.o
snd-soc-rt1308-y := rt1308.o
snd-soc-rt1308-sdw-y := rt1308-sdw.o
snd-soc-rt1316-sdw-y := rt1316-sdw.o
+snd-soc-rt1318-y := rt1318.o
snd-soc-rt1318-sdw-y := rt1318-sdw.o
+snd-soc-rt1320-sdw-y := rt1320-sdw.o
snd-soc-rt274-y := rt274.o
snd-soc-rt286-y := rt286.o
snd-soc-rt298-y := rt298.o
@@ -316,6 +322,8 @@ snd-soc-wcd-classh-y := wcd-clsh-v2.o
snd-soc-wcd-mbhc-y := wcd-mbhc-v2.o
snd-soc-wcd9335-y := wcd9335.o
snd-soc-wcd934x-y := wcd934x.o
+snd-soc-wcd937x-objs := wcd937x.o
+snd-soc-wcd937x-sdw-objs := wcd937x-sdw.o
snd-soc-wcd938x-y := wcd938x.o
snd-soc-wcd938x-sdw-y := wcd938x-sdw.o
snd-soc-wcd939x-y := wcd939x.o
@@ -435,6 +443,7 @@ obj-$(CONFIG_SND_SOC_AK4458) += snd-soc-ak4458.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o
obj-$(CONFIG_SND_SOC_AK4613) += snd-soc-ak4613.o
+obj-$(CONFIG_SND_SOC_AK4619) += snd-soc-ak4619.o
obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o
obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
@@ -504,6 +513,8 @@ obj-$(CONFIG_SND_SOC_CS47L85) += snd-soc-cs47l85.o
obj-$(CONFIG_SND_SOC_CS47L90) += snd-soc-cs47l90.o
obj-$(CONFIG_SND_SOC_CS47L92) += snd-soc-cs47l92.o
obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o
+obj-$(CONFIG_SND_SOC_CS530X) += snd-soc-cs530x.o
+obj-$(CONFIG_SND_SOC_CS530X_I2C) += snd-soc-cs530x-i2c.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_CX2072X) += snd-soc-cx2072x.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
@@ -516,6 +527,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_ES83XX_DSM_COMMON) += snd-soc-es83xx-dsm-common.o
+obj-$(CONFIG_SND_SOC_ES8311) += snd-soc-es8311.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
@@ -613,7 +625,9 @@ obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o
obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o
obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o
obj-$(CONFIG_SND_SOC_RT1316_SDW) += snd-soc-rt1316-sdw.o
+obj-$(CONFIG_SND_SOC_RT1318) += snd-soc-rt1318.o
obj-$(CONFIG_SND_SOC_RT1318_SDW) += snd-soc-rt1318-sdw.o
+obj-$(CONFIG_SND_SOC_RT1320_SDW) += snd-soc-rt1320-sdw.o
obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
@@ -710,6 +724,11 @@ obj-$(CONFIG_SND_SOC_WCD_CLASSH) += snd-soc-wcd-classh.o
obj-$(CONFIG_SND_SOC_WCD_MBHC) += snd-soc-wcd-mbhc.o
obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o
obj-$(CONFIG_SND_SOC_WCD934X) += snd-soc-wcd934x.o
+obj-$(CONFIG_SND_SOC_WCD937X) += snd-soc-wcd937x.o
+ifdef CONFIG_SND_SOC_WCD937X_SDW
+# avoid link failure by forcing sdw code built-in when needed
+obj-$(CONFIG_SND_SOC_WCD937X) += snd-soc-wcd937x-sdw.o
+endif
obj-$(CONFIG_SND_SOC_WCD938X) += snd-soc-wcd938x.o
ifdef CONFIG_SND_SOC_WCD938X_SDW
# avoid link failure by forcing sdw code built-in when needed
diff --git a/sound/soc/codecs/adau7118.c b/sound/soc/codecs/adau7118.c
index a663d37e5776..abc4764697a5 100644
--- a/sound/soc/codecs/adau7118.c
+++ b/sound/soc/codecs/adau7118.c
@@ -121,8 +121,10 @@ static const struct snd_soc_dapm_widget adau7118_widgets[] = {
};
static int adau7118_set_channel_map(struct snd_soc_dai *dai,
- unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
+ unsigned int tx_num,
+ const unsigned int *tx_slot,
+ unsigned int rx_num,
+ const unsigned int *rx_slot)
{
struct adau7118_data *st =
snd_soc_component_get_drvdata(dai->component);
diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c
index 9a43235e6a11..23e868e4e3fb 100644
--- a/sound/soc/codecs/ak4118.c
+++ b/sound/soc/codecs/ak4118.c
@@ -9,7 +9,6 @@
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/slab.h>
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index 73cf482f104f..d472d9952628 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -10,7 +10,6 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
@@ -46,7 +45,6 @@ struct ak4458_priv {
const struct ak4458_drvdata *drvdata;
struct device *dev;
struct regmap *regmap;
- struct gpio_desc *reset_gpiod;
struct reset_control *reset;
struct gpio_desc *mute_gpiod;
int digfil; /* SSLOW, SD, SLOW bits */
@@ -632,10 +630,7 @@ static struct snd_soc_dai_driver ak4497_dai = {
static void ak4458_reset(struct ak4458_priv *ak4458, bool active)
{
- if (ak4458->reset_gpiod) {
- gpiod_set_value_cansleep(ak4458->reset_gpiod, active);
- usleep_range(1000, 2000);
- } else if (!IS_ERR_OR_NULL(ak4458->reset)) {
+ if (!IS_ERR_OR_NULL(ak4458->reset)) {
if (active)
reset_control_assert(ak4458->reset);
else
@@ -759,11 +754,6 @@ static int ak4458_i2c_probe(struct i2c_client *i2c)
if (IS_ERR(ak4458->reset))
return PTR_ERR(ak4458->reset);
- ak4458->reset_gpiod = devm_gpiod_get_optional(ak4458->dev, "reset",
- GPIOD_OUT_LOW);
- if (IS_ERR(ak4458->reset_gpiod))
- return PTR_ERR(ak4458->reset_gpiod);
-
ak4458->mute_gpiod = devm_gpiod_get_optional(ak4458->dev, "mute",
GPIOD_OUT_LOW);
if (IS_ERR(ak4458->mute_gpiod))
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index 73fb35560e51..551738abd1a5 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -753,7 +753,7 @@ static int ak4613_dai_trigger(struct snd_pcm_substream *substream, int cmd,
* SND_SOC_DAIFMT_CBC_CFC
* SND_SOC_DAIFMT_CBP_CFP
*/
-static u64 ak4613_dai_formats =
+static const u64 ak4613_dai_formats =
SND_SOC_POSSIBLE_DAIFMT_I2S |
SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
diff --git a/sound/soc/codecs/ak4619.c b/sound/soc/codecs/ak4619.c
new file mode 100644
index 000000000000..8f2442482f72
--- /dev/null
+++ b/sound/soc/codecs/ak4619.c
@@ -0,0 +1,912 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ak4619.c -- Asahi Kasei ALSA SoC Audio driver
+ *
+ * Copyright (C) 2023 Renesas Electronics Corporation
+ * Khanh Le <khanh.le.xr@renesas.com>
+ *
+ * Based on ak4613.c by Kuninori Morimoto
+ * Based on da7213.c by Adam Thomson
+ * Based on ak4641.c by Harald Welte
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+/*
+ * Registers
+ */
+
+#define PWR_MGMT 0x00 /* Power Management */
+#define AU_IFF1 0x01 /* Audio I/F Format */
+#define AU_IFF2 0x02 /* Audio I/F Format (Extended) */
+#define SYS_CLK 0x03 /* System Clock Setting */
+#define MIC_AMP1 0x04 /* MIC AMP Gain 1 */
+#define MIC_AMP2 0x05 /* MIC AMP Gain 2 */
+#define LADC1 0x06 /* ADC1 Lch Digital Volume */
+#define RADC1 0x07 /* ADC1 Rch Digital Volume */
+#define LADC2 0x08 /* ADC2 Lch Digital Volume */
+#define RADC2 0x09 /* ADC2 Rch Digital Volume */
+#define ADC_DF 0x0a /* ADC Digital Filter Setting */
+#define ADC_AI 0x0b /* ADC Analog Input Setting */
+#define ADC_MHPF 0x0D /* ADC Mute & HPF Control */
+#define LDAC1 0x0E /* DAC1 Lch Digital Volume */
+#define RDAC1 0x0F /* DAC1 Rch Digital Volume */
+#define LDAC2 0x10 /* DAC2 Lch Digital Volume */
+#define RDAC2 0x11 /* DAC2 Rch Digital Volume */
+#define DAC_IS 0x12 /* DAC Input Select Setting */
+#define DAC_DEMP 0x13 /* DAC De-Emphasis Setting */
+#define DAC_MF 0x14 /* DAC Mute & Filter Setting */
+
+/*
+ * Bit fields
+ */
+
+/* Power Management */
+#define PMAD2 BIT(5)
+#define PMAD1 BIT(4)
+#define PMDA2 BIT(2)
+#define PMDA1 BIT(1)
+#define RSTN BIT(0)
+
+/* Audio_I/F Format */
+#define DCF_STEREO_I2S (0x0 << 4)
+#define DCF_STEREO_MSB (0x5 << 4)
+#define DCF_PCM_SF (0x6 << 4)
+#define DCF_PCM_LF (0x7 << 4)
+#define DSL_32 (0x3 << 2)
+#define DCF_MASK (0x7 << 4)
+#define DSL_MASK (0x3 << 2)
+#define BCKP BIT(1)
+
+/* Audio_I/F Format (Extended) */
+#define DIDL_24 (0x0 << 2)
+#define DIDL_20 (0x1 << 2)
+#define DIDL_16 (0x2 << 2)
+#define DIDL_32 (0x3 << 2)
+#define DODL_24 (0x0 << 0)
+#define DODL_20 (0x1 << 0)
+#define DODL_16 (0x2 << 0)
+#define DIDL_MASK (0x3 << 2)
+#define DODL_MASK (0x3 << 0)
+#define SLOT BIT(4)
+
+/* System Clock Setting */
+#define FS_MASK 0x7
+
+/* MIC AMP Gain */
+#define MGNL_SHIFT 4
+#define MGNR_SHIFT 0
+#define MGN_MAX 0xB
+
+/* ADC Digital Volume */
+#define VOLAD_SHIFT 0
+#define VOLAD_MAX 0xFF
+
+/* ADC Digital Filter Setting */
+#define AD1SL_SHIFT 0
+#define AD2SL_SHIFT 4
+
+/* Analog Input Select */
+#define AD1LSEL_SHIFT 6
+#define AD1RSEL_SHIFT 4
+#define AD2LSEL_SHIFT 2
+#define AD2RSEL_SHIFT 0
+
+/* ADC Mute & HPF Control */
+#define ATSPAD_SHIFT 7
+#define AD1MUTE_SHIFT 5
+#define AD2MUTE_SHIFT 6
+#define AD1MUTE_MAX 1
+#define AD2MUTE_MAX 1
+#define AD1MUTE_EN BIT(5)
+#define AD2MUTE_EN BIT(6)
+#define AD1HPFN_SHIFT 1
+#define AD1HPFN_MAX 1
+#define AD2HPFN_SHIFT 2
+#define AD2HPFN_MAX 1
+
+/* DAC Digital Volume */
+#define VOLDA_SHIFT 0
+#define VOLDA_MAX 0xFF
+
+/* DAC Input Select Setting */
+#define DAC1SEL_SHIFT 0
+#define DAC2SEL_SHIFT 2
+
+/* DAC De-Emphasis Setting */
+#define DEM1_32000 (0x3 << 0)
+#define DEM1_44100 (0x0 << 0)
+#define DEM1_48000 (0x2 << 0)
+#define DEM1_OFF (0x1 << 0)
+#define DEM2_32000 (0x3 << 2)
+#define DEM2_44100 (0x0 << 2)
+#define DEM2_48000 (0x2 << 2)
+#define DEM2_OFF (0x1 << 2)
+#define DEM1_MASK (0x3 << 0)
+#define DEM2_MASK (0x3 << 2)
+#define DEM1_SHIFT 0
+#define DEM2_SHIFT 2
+
+/* DAC Mute & Filter Setting */
+#define DA1MUTE_SHIFT 4
+#define DA1MUTE_MAX 1
+#define DA2MUTE_SHIFT 5
+#define DA2MUTE_MAX 1
+#define DA1MUTE_EN BIT(4)
+#define DA2MUTE_EN BIT(5)
+#define ATSPDA_SHIFT 7
+#define DA1SL_SHIFT 0
+#define DA2SL_SHIFT 2
+
+/* Codec private data */
+struct ak4619_priv {
+ struct regmap *regmap;
+ struct snd_pcm_hw_constraint_list constraint;
+ int deemph_en;
+ unsigned int playback_rate;
+ unsigned int sysclk;
+};
+
+/*
+ * DAC Volume
+ *
+ * max : 0x00 : +12.0 dB
+ * ( 0.5 dB step )
+ * min : 0xFE : -115.0 dB
+ * mute: 0xFF
+ */
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -11550, 50, 1);
+
+/*
+ * MIC Volume
+ *
+ * max : 0x0B : +27.0 dB
+ * ( 3 dB step )
+ * min: 0x00 : -6.0 dB
+ */
+static const DECLARE_TLV_DB_SCALE(mic_tlv, -600, 300, 0);
+
+/*
+ * ADC Volume
+ *
+ * max : 0x00 : +24.0 dB
+ * ( 0.5 dB step )
+ * min : 0xFE : -103.0 dB
+ * mute: 0xFF
+ */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -10350, 50, 1);
+
+/* ADC & DAC Volume Level Transition Time select */
+static const char * const ak4619_vol_trans_txt[] = {
+ "4/fs", "16/fs"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_adc_vol_trans, ADC_MHPF, ATSPAD_SHIFT, ak4619_vol_trans_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_vol_trans, DAC_MF, ATSPDA_SHIFT, ak4619_vol_trans_txt);
+
+/* ADC Digital Filter select */
+static const char * const ak4619_adc_digi_fil_txt[] = {
+ "Sharp Roll-Off Filter",
+ "Slow Roll-Off Filter",
+ "Short Delay Sharp Roll-Off Filter",
+ "Short Delay Slow Roll-Off Filter",
+ "Voice Filter"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_adc_1_digi_fil, ADC_DF, AD1SL_SHIFT, ak4619_adc_digi_fil_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_adc_2_digi_fil, ADC_DF, AD2SL_SHIFT, ak4619_adc_digi_fil_txt);
+
+/* DAC De-Emphasis Filter select */
+static const char * const ak4619_dac_de_emp_txt[] = {
+ "44.1kHz", "OFF", "48kHz", "32kHz"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_1_de_emp, DAC_DEMP, DEM1_SHIFT, ak4619_dac_de_emp_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_2_de_emp, DAC_DEMP, DEM2_SHIFT, ak4619_dac_de_emp_txt);
+
+/* DAC Digital Filter select */
+static const char * const ak4619_dac_digi_fil_txt[] = {
+ "Sharp Roll-Off Filter",
+ "Slow Roll-Off Filter",
+ "Short Delay Sharp Roll-Off Filter",
+ "Short Delay Slow Roll-Off Filter"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_1_digi_fil, DAC_MF, DA1SL_SHIFT, ak4619_dac_digi_fil_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_2_digi_fil, DAC_MF, DA2SL_SHIFT, ak4619_dac_digi_fil_txt);
+
+/*
+ * Control functions
+ */
+
+static void ak4619_set_deemph(struct snd_soc_component *component)
+{
+ struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+ u8 dem = 0;
+
+ if (!ak4619->deemph_en)
+ return;
+
+ switch (ak4619->playback_rate) {
+ case 32000:
+ dem |= DEM1_32000 | DEM2_32000;
+ break;
+ case 44100:
+ dem |= DEM1_44100 | DEM2_44100;
+ break;
+ case 48000:
+ dem |= DEM1_48000 | DEM2_48000;
+ break;
+ default:
+ dem |= DEM1_OFF | DEM2_OFF;
+ break;
+ }
+ snd_soc_component_update_bits(component, DAC_DEMP, DEM1_MASK | DEM2_MASK, dem);
+}
+
+static int ak4619_put_deemph(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+ int deemph_en = ucontrol->value.integer.value[0];
+ int ret = 0;
+
+ switch (deemph_en) {
+ case 0:
+ case 1:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (ak4619->deemph_en != deemph_en)
+ ret = 1; /* The value changed */
+
+ ak4619->deemph_en = deemph_en;
+ ak4619_set_deemph(component);
+
+ return ret;
+}
+
+static int ak4619_get_deemph(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = ak4619->deemph_en;
+
+ return 0;
+};
+
+/*
+ * KControls
+ */
+static const struct snd_kcontrol_new ak4619_snd_controls[] = {
+
+ /* Volume controls */
+ SOC_DOUBLE_R_TLV("DAC 1 Volume", LDAC1, RDAC1, VOLDA_SHIFT, VOLDA_MAX, 1, dac_tlv),
+ SOC_DOUBLE_R_TLV("DAC 2 Volume", LDAC2, RDAC2, VOLDA_SHIFT, VOLDA_MAX, 1, dac_tlv),
+ SOC_DOUBLE_R_TLV("ADC 1 Volume", LADC1, RADC1, VOLAD_SHIFT, VOLAD_MAX, 1, adc_tlv),
+ SOC_DOUBLE_R_TLV("ADC 2 Volume", LADC2, RADC2, VOLAD_SHIFT, VOLAD_MAX, 1, adc_tlv),
+
+ SOC_DOUBLE_TLV("Mic 1 Volume", MIC_AMP1, MGNL_SHIFT, MGNR_SHIFT, MGN_MAX, 0, mic_tlv),
+ SOC_DOUBLE_TLV("Mic 2 Volume", MIC_AMP2, MGNL_SHIFT, MGNR_SHIFT, MGN_MAX, 0, mic_tlv),
+
+ /* Volume Level Transition Time controls */
+ SOC_ENUM("ADC Volume Level Transition Time", ak4619_adc_vol_trans),
+ SOC_ENUM("DAC Volume Level Transition Time", ak4619_dac_vol_trans),
+
+ /* Mute controls */
+ SOC_SINGLE("DAC 1 Switch", DAC_MF, DA1MUTE_SHIFT, DA1MUTE_MAX, 1),
+ SOC_SINGLE("DAC 2 Switch", DAC_MF, DA2MUTE_SHIFT, DA2MUTE_MAX, 1),
+
+ SOC_SINGLE("ADC 1 Switch", ADC_MHPF, AD1MUTE_SHIFT, AD1MUTE_MAX, 1),
+ SOC_SINGLE("ADC 2 Switch", ADC_MHPF, AD2MUTE_SHIFT, AD2MUTE_MAX, 1),
+
+ /* Filter controls */
+ SOC_ENUM("ADC 1 Digital Filter", ak4619_adc_1_digi_fil),
+ SOC_ENUM("ADC 2 Digital Filter", ak4619_adc_2_digi_fil),
+
+ SOC_SINGLE("ADC 1 HPF", ADC_MHPF, AD1HPFN_SHIFT, AD1HPFN_MAX, 1),
+ SOC_SINGLE("ADC 2 HPF", ADC_MHPF, AD2HPFN_SHIFT, AD2HPFN_MAX, 1),
+
+ SOC_ENUM("DAC 1 De-Emphasis Filter", ak4619_dac_1_de_emp),
+ SOC_ENUM("DAC 2 De-Emphasis Filter", ak4619_dac_2_de_emp),
+
+ SOC_ENUM("DAC 1 Digital Filter", ak4619_dac_1_digi_fil),
+ SOC_ENUM("DAC 2 Digital Filter", ak4619_dac_2_digi_fil),
+
+ SOC_SINGLE_BOOL_EXT("Playback De-Emphasis Switch", 0, ak4619_get_deemph, ak4619_put_deemph),
+};
+
+/*
+ * DAPM
+ */
+
+/* Analog input mode */
+static const char * const ak4619_analog_in_txt[] = {
+ "Differential", "Single-Ended1", "Single-Ended2", "Pseudo Differential"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_ad_1_left_in, ADC_AI, AD1LSEL_SHIFT, ak4619_analog_in_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_ad_1_right_in, ADC_AI, AD1RSEL_SHIFT, ak4619_analog_in_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_ad_2_left_in, ADC_AI, AD2LSEL_SHIFT, ak4619_analog_in_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_ad_2_right_in, ADC_AI, AD2RSEL_SHIFT, ak4619_analog_in_txt);
+
+static const struct snd_kcontrol_new ak4619_ad_1_left_in_mux =
+ SOC_DAPM_ENUM("Analog Input 1 Left MUX", ak4619_ad_1_left_in);
+static const struct snd_kcontrol_new ak4619_ad_1_right_in_mux =
+ SOC_DAPM_ENUM("Analog Input 1 Right MUX", ak4619_ad_1_right_in);
+static const struct snd_kcontrol_new ak4619_ad_2_left_in_mux =
+ SOC_DAPM_ENUM("Analog Input 2 Left MUX", ak4619_ad_2_left_in);
+static const struct snd_kcontrol_new ak4619_ad_2_right_in_mux =
+ SOC_DAPM_ENUM("Analog Input 2 Right MUX", ak4619_ad_2_right_in);
+
+/* DAC source mux */
+static const char * const ak4619_dac_in_txt[] = {
+ "SDIN1", "SDIN2", "SDOUT1", "SDOUT2"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_1_in, DAC_IS, DAC1SEL_SHIFT, ak4619_dac_in_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_2_in, DAC_IS, DAC2SEL_SHIFT, ak4619_dac_in_txt);
+
+static const struct snd_kcontrol_new ak4619_dac_1_in_mux =
+ SOC_DAPM_ENUM("DAC 1 Source MUX", ak4619_dac_1_in);
+static const struct snd_kcontrol_new ak4619_dac_2_in_mux =
+ SOC_DAPM_ENUM("DAC 2 Source MUX", ak4619_dac_2_in);
+
+static const struct snd_soc_dapm_widget ak4619_dapm_widgets[] = {
+
+ /* DACs */
+ SND_SOC_DAPM_DAC("DAC1", NULL, PWR_MGMT, 1, 0),
+ SND_SOC_DAPM_DAC("DAC2", NULL, PWR_MGMT, 2, 0),
+
+ /* ADCs */
+ SND_SOC_DAPM_ADC("ADC1", NULL, PWR_MGMT, 4, 0),
+ SND_SOC_DAPM_ADC("ADC2", NULL, PWR_MGMT, 5, 0),
+
+ /* Outputs */
+ SND_SOC_DAPM_OUTPUT("AOUT1L"),
+ SND_SOC_DAPM_OUTPUT("AOUT2L"),
+
+ SND_SOC_DAPM_OUTPUT("AOUT1R"),
+ SND_SOC_DAPM_OUTPUT("AOUT2R"),
+
+ /* Inputs */
+ SND_SOC_DAPM_INPUT("AIN1L"),
+ SND_SOC_DAPM_INPUT("AIN2L"),
+ SND_SOC_DAPM_INPUT("AIN4L"),
+ SND_SOC_DAPM_INPUT("AIN5L"),
+
+ SND_SOC_DAPM_INPUT("AIN1R"),
+ SND_SOC_DAPM_INPUT("AIN2R"),
+ SND_SOC_DAPM_INPUT("AIN4R"),
+ SND_SOC_DAPM_INPUT("AIN5R"),
+
+ SND_SOC_DAPM_INPUT("MIC1L"),
+ SND_SOC_DAPM_INPUT("MIC1R"),
+ SND_SOC_DAPM_INPUT("MIC2L"),
+ SND_SOC_DAPM_INPUT("MIC2R"),
+
+ /* DAI */
+ SND_SOC_DAPM_AIF_IN("SDIN1", "Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SDIN2", "Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SDOUT1", "Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SDOUT2", "Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* MUXs for Mic PGA source selection */
+ SND_SOC_DAPM_MUX("Analog Input 1 Left MUX", SND_SOC_NOPM, 0, 0, &ak4619_ad_1_left_in_mux),
+ SND_SOC_DAPM_MUX("Analog Input 1 Right MUX", SND_SOC_NOPM, 0, 0, &ak4619_ad_1_right_in_mux),
+ SND_SOC_DAPM_MUX("Analog Input 2 Left MUX", SND_SOC_NOPM, 0, 0, &ak4619_ad_2_left_in_mux),
+ SND_SOC_DAPM_MUX("Analog Input 2 Right MUX", SND_SOC_NOPM, 0, 0, &ak4619_ad_2_right_in_mux),
+
+ /* MUXs for DAC source selection */
+ SND_SOC_DAPM_MUX("DAC 1 Source MUX", SND_SOC_NOPM, 0, 0, &ak4619_dac_1_in_mux),
+ SND_SOC_DAPM_MUX("DAC 2 Source MUX", SND_SOC_NOPM, 0, 0, &ak4619_dac_2_in_mux),
+};
+
+static const struct snd_soc_dapm_route ak4619_intercon[] = {
+ /* Dest Connecting Widget Source */
+
+ /* Output path */
+ {"AOUT1L", NULL, "DAC1"},
+ {"AOUT2L", NULL, "DAC2"},
+
+ {"AOUT1R", NULL, "DAC1"},
+ {"AOUT2R", NULL, "DAC2"},
+
+ {"DAC1", NULL, "DAC 1 Source MUX"},
+ {"DAC2", NULL, "DAC 2 Source MUX"},
+
+ {"DAC 1 Source MUX", "SDIN1", "SDIN1"},
+ {"DAC 1 Source MUX", "SDIN2", "SDIN2"},
+ {"DAC 1 Source MUX", "SDOUT1", "SDOUT1"},
+ {"DAC 1 Source MUX", "SDOUT2", "SDOUT2"},
+
+ {"DAC 2 Source MUX", "SDIN1", "SDIN1"},
+ {"DAC 2 Source MUX", "SDIN2", "SDIN2"},
+ {"DAC 2 Source MUX", "SDOUT1", "SDOUT1"},
+ {"DAC 2 Source MUX", "SDOUT2", "SDOUT2"},
+
+ /* Input path */
+ {"SDOUT1", NULL, "ADC1"},
+ {"SDOUT2", NULL, "ADC2"},
+
+ {"ADC1", NULL, "Analog Input 1 Left MUX"},
+ {"ADC1", NULL, "Analog Input 1 Right MUX"},
+
+ {"ADC2", NULL, "Analog Input 2 Left MUX"},
+ {"ADC2", NULL, "Analog Input 2 Right MUX"},
+
+ {"Analog Input 1 Left MUX", "Differential", "MIC1L"},
+ {"Analog Input 1 Left MUX", "Single-Ended1", "MIC1L"},
+ {"Analog Input 1 Left MUX", "Single-Ended2", "MIC1L"},
+ {"Analog Input 1 Left MUX", "Pseudo Differential", "MIC1L"},
+
+ {"Analog Input 1 Right MUX", "Differential", "MIC1R"},
+ {"Analog Input 1 Right MUX", "Single-Ended1", "MIC1R"},
+ {"Analog Input 1 Right MUX", "Single-Ended2", "MIC1R"},
+ {"Analog Input 1 Right MUX", "Pseudo Differential", "MIC1R"},
+
+ {"Analog Input 2 Left MUX", "Differential", "MIC2L"},
+ {"Analog Input 2 Left MUX", "Single-Ended1", "MIC2L"},
+ {"Analog Input 2 Left MUX", "Single-Ended2", "MIC2L"},
+ {"Analog Input 2 Left MUX", "Pseudo Differential", "MIC2L"},
+
+ {"Analog Input 2 Right MUX", "Differential", "MIC2R"},
+ {"Analog Input 2 Right MUX", "Single-Ended1", "MIC2R"},
+ {"Analog Input 2 Right MUX", "Single-Ended2", "MIC2R"},
+ {"Analog Input 2 Right MUX", "Pseudo Differential", "MIC2R"},
+
+ {"MIC1L", NULL, "AIN1L"},
+ {"MIC1L", NULL, "AIN2L"},
+
+ {"MIC1R", NULL, "AIN1R"},
+ {"MIC1R", NULL, "AIN2R"},
+
+ {"MIC2L", NULL, "AIN4L"},
+ {"MIC2L", NULL, "AIN5L"},
+
+ {"MIC2R", NULL, "AIN4R"},
+ {"MIC2R", NULL, "AIN5R"},
+};
+
+static const struct reg_default ak4619_reg_defaults[] = {
+ { PWR_MGMT, 0x00 },
+ { AU_IFF1, 0x0C },
+ { AU_IFF2, 0x0C },
+ { SYS_CLK, 0x00 },
+ { MIC_AMP1, 0x22 },
+ { MIC_AMP2, 0x22 },
+ { LADC1, 0x30 },
+ { RADC1, 0x30 },
+ { LADC2, 0x30 },
+ { RADC2, 0x30 },
+ { ADC_DF, 0x00 },
+ { ADC_AI, 0x00 },
+ { ADC_MHPF, 0x00 },
+ { LDAC1, 0x18 },
+ { RDAC1, 0x18 },
+ { LDAC2, 0x18 },
+ { RDAC2, 0x18 },
+ { DAC_IS, 0x04 },
+ { DAC_DEMP, 0x05 },
+ { DAC_MF, 0x0A },
+};
+
+static int ak4619_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ u8 pwr_ctrl = 0;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ pwr_ctrl |= RSTN;
+ fallthrough;
+ case SND_SOC_BIAS_PREPARE:
+ pwr_ctrl |= PMAD1 | PMAD2 | PMDA1 | PMDA2;
+ fallthrough;
+ case SND_SOC_BIAS_STANDBY:
+ case SND_SOC_BIAS_OFF:
+ default:
+ break;
+ }
+
+ snd_soc_component_write(component, PWR_MGMT, pwr_ctrl);
+
+ return 0;
+}
+
+static int ak4619_dai_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 ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+ unsigned int width;
+ unsigned int rate;
+ unsigned int fs;
+ bool is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ u8 dai_ctrl = 0;
+ u8 clk_mode = 0;
+
+ width = params_width(params);
+ switch (width) {
+ case 16:
+ dai_ctrl |= is_play ? DIDL_16 : DODL_16;
+ break;
+ case 20:
+ dai_ctrl |= is_play ? DIDL_20 : DODL_20;
+ break;
+ case 24:
+ dai_ctrl |= is_play ? DIDL_24 : DODL_24;
+ break;
+ case 32:
+ if (is_play)
+ dai_ctrl |= DIDL_32;
+ else
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rate = params_rate(params);
+ if (rate)
+ fs = ak4619->sysclk / rate;
+ else
+ return -EINVAL;
+
+ switch (rate) {
+ case 8000:
+ case 11025:
+ case 12000:
+ case 16000:
+ case 22050:
+ case 24000:
+ case 32000:
+ case 44100:
+ case 48000:
+ switch (fs) {
+ case 256:
+ clk_mode |= (0x0 << 0);
+ break;
+ case 384:
+ clk_mode |= (0x2 << 0);
+ break;
+ case 512:
+ clk_mode |= (0x3 << 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case 64000:
+ case 88200:
+ case 96000:
+ if (fs == 256)
+ clk_mode |= (0x1 << 0);
+ else
+ return -EINVAL;
+ break;
+ case 176400:
+ case 192000:
+ if (fs == 128)
+ clk_mode |= (0x4 << 0);
+ else
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component, SYS_CLK, FS_MASK, clk_mode);
+ snd_soc_component_update_bits(component, AU_IFF2,
+ is_play ? DIDL_MASK : DODL_MASK, dai_ctrl);
+
+ if (is_play) {
+ ak4619->playback_rate = rate;
+ ak4619_set_deemph(component);
+ }
+
+ return 0;
+}
+
+static int ak4619_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ u8 dai_fmt1 = 0;
+ u8 dai_fmt2 = 0;
+
+ /* Set clock normal/inverted */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ dai_fmt1 |= BCKP;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ case SND_SOC_DAIFMT_IB_IF:
+ default:
+ return -EINVAL;
+ }
+
+ /* Only Stereo modes are supported */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ dai_fmt1 |= DCF_STEREO_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ dai_fmt1 |= DCF_STEREO_MSB;
+ break;
+ case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */
+ dai_fmt1 |= DCF_PCM_SF;
+ dai_fmt2 |= SLOT;
+ break;
+ case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */
+ dai_fmt1 |= DCF_PCM_LF;
+ dai_fmt2 |= SLOT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Only slave mode is support */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* By default only 64 BICK per LRCLK is supported */
+ dai_fmt1 |= DSL_32;
+
+ snd_soc_component_update_bits(component, AU_IFF1, DCF_MASK |
+ DSL_MASK | BCKP, dai_fmt1);
+ snd_soc_component_update_bits(component, AU_IFF2, SLOT, dai_fmt2);
+
+ return 0;
+}
+
+static int ak4619_dai_set_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+
+ ak4619->sysclk = freq;
+
+ return 0;
+}
+
+static int ak4619_dai_mute(struct snd_soc_dai *dai, int mute, int direction)
+{
+ struct snd_soc_component *component = dai->component;
+
+ snd_soc_component_update_bits(component, DAC_MF, DA1MUTE_EN, mute ? DA1MUTE_EN : 0);
+ snd_soc_component_update_bits(component, DAC_MF, DA2MUTE_EN, mute ? DA2MUTE_EN : 0);
+
+ return 0;
+}
+
+static void ak4619_hw_constraints(struct ak4619_priv *ak4619,
+ struct snd_pcm_runtime *runtime)
+{
+ struct snd_pcm_hw_constraint_list *constraint = &ak4619->constraint;
+ int ak4619_rate_mask = 0;
+ unsigned int fs;
+ int i;
+ static const unsigned int ak4619_sr[] = {
+ 8000,
+ 11025,
+ 12000,
+ 16000,
+ 22050,
+ 24000,
+ 32000,
+ 44100,
+ 48000,
+ 64000,
+ 88200,
+ 96000,
+ 176400,
+ 192000,
+ };
+
+ /*
+ * [8kHz - 48kHz] : 256fs, 384fs or 512fs
+ * [64kHz - 96kHz] : 256fs
+ * [176.4kHz, 192kHz] : 128fs
+ */
+
+ for (i = 0; i < ARRAY_SIZE(ak4619_sr); i++) {
+ fs = ak4619->sysclk / ak4619_sr[i];
+
+ switch (fs) {
+ case 512:
+ case 384:
+ case 256:
+ ak4619_rate_mask |= (1 << i);
+ break;
+ case 128:
+ switch (i) {
+ case (ARRAY_SIZE(ak4619_sr) - 1):
+ case (ARRAY_SIZE(ak4619_sr) - 2):
+ ak4619_rate_mask |= (1 << i);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ constraint->list = ak4619_sr;
+ constraint->mask = ak4619_rate_mask;
+ constraint->count = ARRAY_SIZE(ak4619_sr);
+
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, constraint);
+};
+
+#define PLAYBACK_MODE 0
+#define CAPTURE_MODE 1
+
+static int ak4619_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+
+ ak4619_hw_constraints(ak4619, substream->runtime);
+
+ return 0;
+}
+
+static u64 ak4619_dai_formats[] = {
+ /*
+ * Select below from Sound Card, not here
+ * SND_SOC_DAIFMT_CBC_CFC
+ * SND_SOC_DAIFMT_CBP_CFP
+ */
+
+ /* First Priority */
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J,
+
+ /* Second Priority */
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B,
+};
+
+static const struct snd_soc_dai_ops ak4619_dai_ops = {
+ .startup = ak4619_dai_startup,
+ .set_sysclk = ak4619_dai_set_sysclk,
+ .set_fmt = ak4619_dai_set_fmt,
+ .hw_params = ak4619_dai_hw_params,
+ .mute_stream = ak4619_dai_mute,
+ .auto_selectable_formats = ak4619_dai_formats,
+ .num_auto_selectable_formats = ARRAY_SIZE(ak4619_dai_formats),
+};
+
+static const struct snd_soc_component_driver soc_component_dev_ak4619 = {
+ .set_bias_level = ak4619_set_bias_level,
+ .controls = ak4619_snd_controls,
+ .num_controls = ARRAY_SIZE(ak4619_snd_controls),
+ .dapm_widgets = ak4619_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ak4619_dapm_widgets),
+ .dapm_routes = ak4619_intercon,
+ .num_dapm_routes = ARRAY_SIZE(ak4619_intercon),
+ .idle_bias_on = 1,
+ .endianness = 1,
+};
+
+static const struct regmap_config ak4619_regmap_cfg = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x14,
+ .reg_defaults = ak4619_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(ak4619_reg_defaults),
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static const struct of_device_id ak4619_of_match[] = {
+ { .compatible = "asahi-kasei,ak4619", .data = &ak4619_regmap_cfg },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ak4619_of_match);
+
+static const struct i2c_device_id ak4619_i2c_id[] = {
+ { "ak4619", (kernel_ulong_t)&ak4619_regmap_cfg },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ak4619_i2c_id);
+
+#define AK4619_RATES SNDRV_PCM_RATE_8000_192000
+
+#define AK4619_DAC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S20_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define AK4619_ADC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S20_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver ak4619_dai = {
+ .name = "ak4619-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AK4619_RATES,
+ .formats = AK4619_DAC_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AK4619_RATES,
+ .formats = AK4619_ADC_FORMATS,
+ },
+ .ops = &ak4619_dai_ops,
+ .symmetric_rate = 1,
+};
+
+static int ak4619_i2c_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct ak4619_priv *ak4619;
+ int ret;
+
+ ak4619 = devm_kzalloc(dev, sizeof(*ak4619), GFP_KERNEL);
+ if (!ak4619)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, ak4619);
+
+ ak4619->regmap = devm_regmap_init_i2c(i2c, &ak4619_regmap_cfg);
+ if (IS_ERR(ak4619->regmap)) {
+ ret = PTR_ERR(ak4619->regmap);
+ dev_err(dev, "regmap_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_snd_soc_register_component(dev, &soc_component_dev_ak4619,
+ &ak4619_dai, 1);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register ak4619 component: %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct i2c_driver ak4619_i2c_driver = {
+ .driver = {
+ .name = "ak4619-codec",
+ .of_match_table = ak4619_of_match,
+ },
+ .probe = ak4619_i2c_probe,
+ .id_table = ak4619_i2c_id,
+};
+module_i2c_driver(ak4619_i2c_driver);
+
+MODULE_DESCRIPTION("SoC AK4619 driver");
+MODULE_AUTHOR("Khanh Le <khanh.le.xr@renesas.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/audio-iio-aux.c b/sound/soc/codecs/audio-iio-aux.c
index 1e8e1effc2af..588e48044c13 100644
--- a/sound/soc/codecs/audio-iio-aux.c
+++ b/sound/soc/codecs/audio-iio-aux.c
@@ -6,6 +6,7 @@
//
// Author: Herve Codina <herve.codina@bootlin.com>
+#include <linux/cleanup.h>
#include <linux/iio/consumer.h>
#include <linux/minmax.h>
#include <linux/mod_devicetable.h>
@@ -131,33 +132,27 @@ static int audio_iio_aux_add_dapms(struct snd_soc_component *component,
struct audio_iio_aux_chan *chan)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
- char *output_name;
- char *input_name;
- char *pga_name;
int ret;
- input_name = kasprintf(GFP_KERNEL, "%s IN", chan->name);
+ /* Allocated names are not needed afterwards (duplicated in ASoC internals) */
+ char *input_name __free(kfree) = kasprintf(GFP_KERNEL, "%s IN", chan->name);
if (!input_name)
return -ENOMEM;
- output_name = kasprintf(GFP_KERNEL, "%s OUT", chan->name);
- if (!output_name) {
- ret = -ENOMEM;
- goto out_free_input_name;
- }
+ char *output_name __free(kfree) = kasprintf(GFP_KERNEL, "%s OUT", chan->name);
+ if (!output_name)
+ return -ENOMEM;
- pga_name = kasprintf(GFP_KERNEL, "%s PGA", chan->name);
- if (!pga_name) {
- ret = -ENOMEM;
- goto out_free_output_name;
- }
+ char *pga_name __free(kfree) = kasprintf(GFP_KERNEL, "%s PGA", chan->name);
+ if (!pga_name)
+ return -ENOMEM;
widgets[0] = SND_SOC_DAPM_INPUT(input_name);
widgets[1] = SND_SOC_DAPM_OUTPUT(output_name);
widgets[2] = SND_SOC_DAPM_PGA(pga_name, SND_SOC_NOPM, 0, 0, NULL, 0);
ret = snd_soc_dapm_new_controls(dapm, widgets, 3);
if (ret)
- goto out_free_pga_name;
+ return ret;
routes[0].sink = pga_name;
routes[0].control = NULL;
@@ -165,17 +160,8 @@ static int audio_iio_aux_add_dapms(struct snd_soc_component *component,
routes[1].sink = output_name;
routes[1].control = NULL;
routes[1].source = pga_name;
- ret = snd_soc_dapm_add_routes(dapm, routes, 2);
-
- /* Allocated names are no more needed (duplicated in ASoC internals) */
-out_free_pga_name:
- kfree(pga_name);
-out_free_output_name:
- kfree(output_name);
-out_free_input_name:
- kfree(input_name);
- return ret;
+ return snd_soc_dapm_add_routes(dapm, routes, 2);
}
static int audio_iio_aux_component_probe(struct snd_soc_component *component)
@@ -244,8 +230,6 @@ static int audio_iio_aux_probe(struct platform_device *pdev)
struct audio_iio_aux_chan *iio_aux_chan;
struct device *dev = &pdev->dev;
struct audio_iio_aux *iio_aux;
- const char **names;
- u32 *invert_ranges;
int count;
int ret;
int i;
@@ -262,22 +246,22 @@ static int audio_iio_aux_probe(struct platform_device *pdev)
iio_aux->num_chans = count;
- names = kcalloc(iio_aux->num_chans, sizeof(*names), GFP_KERNEL);
+ const char **names __free(kfree) = kcalloc(iio_aux->num_chans,
+ sizeof(*names),
+ GFP_KERNEL);
if (!names)
return -ENOMEM;
- invert_ranges = kcalloc(iio_aux->num_chans, sizeof(*invert_ranges), GFP_KERNEL);
- if (!invert_ranges) {
- ret = -ENOMEM;
- goto out_free_names;
- }
+ u32 *invert_ranges __free(kfree) = kcalloc(iio_aux->num_chans,
+ sizeof(*invert_ranges),
+ GFP_KERNEL);
+ if (!invert_ranges)
+ return -ENOMEM;
ret = device_property_read_string_array(dev, "io-channel-names",
names, iio_aux->num_chans);
- if (ret < 0) {
- dev_err_probe(dev, ret, "failed to read io-channel-names\n");
- goto out_free_invert_ranges;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read io-channel-names\n");
/*
* snd-control-invert-range is optional and can contain fewer items
@@ -288,10 +272,8 @@ static int audio_iio_aux_probe(struct platform_device *pdev)
count = min_t(unsigned int, count, iio_aux->num_chans);
ret = device_property_read_u32_array(dev, "snd-control-invert-range",
invert_ranges, count);
- if (ret < 0) {
- dev_err_probe(dev, ret, "failed to read snd-control-invert-range\n");
- goto out_free_invert_ranges;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read snd-control-invert-range\n");
}
for (i = 0; i < iio_aux->num_chans; i++) {
@@ -300,23 +282,16 @@ static int audio_iio_aux_probe(struct platform_device *pdev)
iio_aux_chan->is_invert_range = invert_ranges[i];
iio_aux_chan->iio_chan = devm_iio_channel_get(dev, iio_aux_chan->name);
- if (IS_ERR(iio_aux_chan->iio_chan)) {
- ret = PTR_ERR(iio_aux_chan->iio_chan);
- dev_err_probe(dev, ret, "get IIO channel '%s' failed\n",
- iio_aux_chan->name);
- goto out_free_invert_ranges;
- }
+ if (IS_ERR(iio_aux_chan->iio_chan))
+ return dev_err_probe(dev, PTR_ERR(iio_aux_chan->iio_chan),
+ "get IIO channel '%s' failed\n",
+ iio_aux_chan->name);
}
platform_set_drvdata(pdev, iio_aux);
- ret = devm_snd_soc_register_component(dev, &audio_iio_aux_component_driver,
- NULL, 0);
-out_free_invert_ranges:
- kfree(invert_ranges);
-out_free_names:
- kfree(names);
- return ret;
+ return devm_snd_soc_register_component(dev, &audio_iio_aux_component_driver,
+ NULL, 0);
}
static const struct of_device_id audio_iio_aux_ids[] = {
diff --git a/sound/soc/codecs/aw87390.c b/sound/soc/codecs/aw87390.c
index 79521ff44001..110009616966 100644
--- a/sound/soc/codecs/aw87390.c
+++ b/sound/soc/codecs/aw87390.c
@@ -445,7 +445,7 @@ static int aw87390_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id aw87390_i2c_id[] = {
- { AW87390_I2C_NAME, 0 },
+ { AW87390_I2C_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, aw87390_i2c_id);
diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c
index a78ceedd0334..fb99871578c5 100644
--- a/sound/soc/codecs/aw88261.c
+++ b/sound/soc/codecs/aw88261.c
@@ -1266,7 +1266,7 @@ static int aw88261_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id aw88261_i2c_id[] = {
- { AW88261_I2C_NAME, 0 },
+ { AW88261_I2C_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, aw88261_i2c_id);
diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c
index 3c459a67ad0c..aea44a199b98 100644
--- a/sound/soc/codecs/aw88395/aw88395.c
+++ b/sound/soc/codecs/aw88395/aw88395.c
@@ -8,9 +8,9 @@
// Author: Weidong Wang <wangweidong.a@awinic.com>
//
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/firmware.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <sound/soc.h>
#include "aw88395.h"
@@ -560,7 +560,7 @@ static int aw88395_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id aw88395_i2c_id[] = {
- { AW88395_I2C_NAME, 0 },
+ { AW88395_I2C_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, aw88395_i2c_id);
diff --git a/sound/soc/codecs/aw88395/aw88395_lib.c b/sound/soc/codecs/aw88395/aw88395_lib.c
index f25f6e0d4428..769ca32a5c8e 100644
--- a/sound/soc/codecs/aw88395/aw88395_lib.c
+++ b/sound/soc/codecs/aw88395/aw88395_lib.c
@@ -7,6 +7,7 @@
// Author: Bruce zhao <zhaolei@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/crc8.h>
#include <linux/i2c.h>
#include "aw88395_lib.h"
@@ -361,11 +362,11 @@ static int aw_dev_parse_raw_dsp_fw(unsigned char *data, unsigned int data_len,
static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *data,
unsigned int data_len, struct aw_prof_desc *prof_desc)
{
- struct aw_bin *aw_bin;
int ret;
int i;
- aw_bin = devm_kzalloc(aw_dev->dev, data_len + sizeof(struct aw_bin), GFP_KERNEL);
+ struct aw_bin *aw_bin __free(kfree) = kzalloc(data_len + sizeof(struct aw_bin),
+ GFP_KERNEL);
if (!aw_bin)
return -ENOMEM;
@@ -375,7 +376,7 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *
ret = aw_parsing_bin_file(aw_dev, aw_bin);
if (ret < 0) {
dev_err(aw_dev->dev, "parse bin failed");
- goto parse_bin_failed;
+ return ret;
}
for (i = 0; i < aw_bin->all_bin_parse_num; i++) {
@@ -387,10 +388,8 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *
data + aw_bin->header_info[i].valid_data_addr;
break;
case DATA_TYPE_DSP_REG:
- if (aw_bin->header_info[i].valid_data_len & 0x01) {
- ret = -EINVAL;
- goto parse_bin_failed;
- }
+ if (aw_bin->header_info[i].valid_data_len & 0x01)
+ return -EINVAL;
swab16_array((u16 *)(data + aw_bin->header_info[i].valid_data_addr),
aw_bin->header_info[i].valid_data_len >> 1);
@@ -402,10 +401,8 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *
break;
case DATA_TYPE_DSP_FW:
case DATA_TYPE_SOC_APP:
- if (aw_bin->header_info[i].valid_data_len & 0x01) {
- ret = -EINVAL;
- goto parse_bin_failed;
- }
+ if (aw_bin->header_info[i].valid_data_len & 0x01)
+ return -EINVAL;
swab16_array((u16 *)(data + aw_bin->header_info[i].valid_data_addr),
aw_bin->header_info[i].valid_data_len >> 1);
@@ -422,20 +419,17 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *
}
}
prof_desc->prof_st = AW88395_PROFILE_OK;
- ret = 0;
-parse_bin_failed:
- devm_kfree(aw_dev->dev, aw_bin);
- return ret;
+ return 0;
}
static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev,
uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc)
{
- struct aw_bin *aw_bin;
int ret;
- aw_bin = devm_kzalloc(aw_dev->dev, data_len + sizeof(*aw_bin), GFP_KERNEL);
+ struct aw_bin *aw_bin __free(kfree) = kzalloc(data_len + sizeof(*aw_bin),
+ GFP_KERNEL);
if (!aw_bin)
return -ENOMEM;
@@ -445,14 +439,13 @@ static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev,
ret = aw_parsing_bin_file(aw_dev, aw_bin);
if (ret < 0) {
dev_err(aw_dev->dev, "parse bin failed");
- goto parse_bin_failed;
+ return ret;
}
if ((aw_bin->all_bin_parse_num != 1) ||
(aw_bin->header_info[0].bin_data_type != DATA_TYPE_REGISTER)) {
dev_err(aw_dev->dev, "bin num or type error");
- ret = -EINVAL;
- goto parse_bin_failed;
+ return -EINVAL;
}
prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data =
@@ -461,15 +454,7 @@ static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev,
aw_bin->header_info[0].valid_data_len;
prof_desc->prof_st = AW88395_PROFILE_OK;
- devm_kfree(aw_dev->dev, aw_bin);
- aw_bin = NULL;
-
return 0;
-
-parse_bin_failed:
- devm_kfree(aw_dev->dev, aw_bin);
- aw_bin = NULL;
- return ret;
}
static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg_hdr *cfg_hdr,
@@ -678,21 +663,21 @@ static int aw_dev_cfg_get_multiple_valid_prof(struct aw_device *aw_dev,
static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev,
struct aw_cfg_hdr *prof_hdr)
{
- struct aw_all_prof_info *all_prof_info;
int ret;
- all_prof_info = devm_kzalloc(aw_dev->dev, sizeof(struct aw_all_prof_info), GFP_KERNEL);
+ struct aw_all_prof_info *all_prof_info __free(kfree) = kzalloc(sizeof(*all_prof_info),
+ GFP_KERNEL);
if (!all_prof_info)
return -ENOMEM;
ret = aw_dev_parse_dev_type(aw_dev, prof_hdr, all_prof_info);
if (ret < 0) {
- goto exit;
+ return ret;
} else if (ret == AW88395_DEV_TYPE_NONE) {
dev_dbg(aw_dev->dev, "get dev type num is 0, parse default dev");
ret = aw_dev_parse_dev_default_type(aw_dev, prof_hdr, all_prof_info);
if (ret < 0)
- goto exit;
+ return ret;
}
switch (aw_dev->prof_data_type) {
@@ -710,8 +695,6 @@ static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev,
if (!ret)
aw_dev->prof_info.prof_name_list = profile_name;
-exit:
- devm_kfree(aw_dev->dev, all_prof_info);
return ret;
}
diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c
index 9fcb805bf971..8dc2b8aa6832 100644
--- a/sound/soc/codecs/aw88399.c
+++ b/sound/soc/codecs/aw88399.c
@@ -8,9 +8,9 @@
//
#include <linux/crc32.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/firmware.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <sound/soc.h>
#include "aw88399.h"
@@ -1892,7 +1892,7 @@ static int aw88399_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id aw88399_i2c_id[] = {
- { AW88399_I2C_NAME, 0 },
+ { AW88399_I2C_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, aw88399_i2c_id);
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
index 4c517231d765..e63a518e3b8e 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -787,7 +787,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l34 = {
.endianness = 1,
};
-static struct regmap_config cs35l34_regmap = {
+static const struct regmap_config cs35l34_regmap = {
.reg_bits = 8,
.val_bits = 8,
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
index c39b3cfe9574..7a01b1d9fc9d 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -1086,7 +1086,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l35 = {
.endianness = 1,
};
-static struct regmap_config cs35l35_regmap = {
+static const struct regmap_config cs35l35_regmap = {
.reg_bits = 8,
.val_bits = 8,
diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c
index bc79990615e8..cbea79bd8980 100644
--- a/sound/soc/codecs/cs35l36.c
+++ b/sound/soc/codecs/cs35l36.c
@@ -1300,7 +1300,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l36 = {
.endianness = 1,
};
-static struct regmap_config cs35l36_regmap = {
+static const struct regmap_config cs35l36_regmap = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c
index e9993a39f7d0..1702f26049d3 100644
--- a/sound/soc/codecs/cs35l41-lib.c
+++ b/sound/soc/codecs/cs35l41-lib.c
@@ -936,8 +936,8 @@ int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsign
EXPORT_SYMBOL_GPL(cs35l41_register_errata_patch);
int cs35l41_set_channels(struct device *dev, struct regmap *reg,
- unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
+ unsigned int tx_num, const unsigned int *tx_slot,
+ unsigned int rx_num, const unsigned int *rx_slot)
{
unsigned int val, mask;
int i;
diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c
index cb25c33cc9b9..1688c2c688f0 100644
--- a/sound/soc/codecs/cs35l41.c
+++ b/sound/soc/codecs/cs35l41.c
@@ -673,7 +673,8 @@ static const struct snd_soc_dapm_route cs35l41_audio_map[] = {
};
static int cs35l41_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_n,
- unsigned int *tx_slot, unsigned int rx_n, unsigned int *rx_slot)
+ const unsigned int *tx_slot,
+ unsigned int rx_n, const unsigned int *rx_slot)
{
struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(dai->component);
diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c
index 70ff55c1517f..fc03bb7ecae1 100644
--- a/sound/soc/codecs/cs35l56-sdw.c
+++ b/sound/soc/codecs/cs35l56-sdw.c
@@ -271,7 +271,6 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral)
prop->source_ports = BIT(CS35L56_SDW1_CAPTURE_PORT);
prop->sink_ports = BIT(CS35L56_SDW1_PLAYBACK_PORT);
prop->paging_support = true;
- prop->clk_stop_mode1 = false;
prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY | SDW_SCP_INT1_IMPL_DEF;
@@ -317,79 +316,6 @@ static int cs35l56_sdw_update_status(struct sdw_slave *peripheral,
return 0;
}
-static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56,
- struct sdw_slave *peripheral)
-{
- unsigned int curr_scale_reg, next_scale_reg;
- int curr_scale, next_scale, ret;
-
- if (!cs35l56->base.init_done)
- return 0;
-
- if (peripheral->bus->params.curr_bank) {
- curr_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B1;
- next_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B0;
- } else {
- curr_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B0;
- next_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B1;
- }
-
- /*
- * Current clock scale value must be different to new value.
- * Modify current to guarantee this. If next still has the dummy
- * value we wrote when it was current, the core code has not set
- * a new scale so restore its original good value
- */
- curr_scale = sdw_read_no_pm(peripheral, curr_scale_reg);
- if (curr_scale < 0) {
- dev_err(cs35l56->base.dev, "Failed to read current clock scale: %d\n", curr_scale);
- return curr_scale;
- }
-
- next_scale = sdw_read_no_pm(peripheral, next_scale_reg);
- if (next_scale < 0) {
- dev_err(cs35l56->base.dev, "Failed to read next clock scale: %d\n", next_scale);
- return next_scale;
- }
-
- if (next_scale == CS35L56_SDW_INVALID_BUS_SCALE) {
- next_scale = cs35l56->old_sdw_clock_scale;
- ret = sdw_write_no_pm(peripheral, next_scale_reg, next_scale);
- if (ret < 0) {
- dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n",
- ret);
- return ret;
- }
- }
-
- cs35l56->old_sdw_clock_scale = curr_scale;
- ret = sdw_write_no_pm(peripheral, curr_scale_reg, CS35L56_SDW_INVALID_BUS_SCALE);
- if (ret < 0) {
- dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n", ret);
- return ret;
- }
-
- dev_dbg(cs35l56->base.dev, "Next bus scale: %#x\n", next_scale);
-
- return 0;
-}
-
-static int cs35l56_sdw_bus_config(struct sdw_slave *peripheral,
- struct sdw_bus_params *params)
-{
- struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
- int sclk;
-
- sclk = params->curr_dr_freq / 2;
- dev_dbg(cs35l56->base.dev, "%s: sclk=%u c=%u r=%u\n",
- __func__, sclk, params->col, params->row);
-
- if ((cs35l56->base.type == 0x56) && (cs35l56->base.rev < 0xb0))
- return cs35l56_a1_kick_divider(cs35l56, peripheral);
-
- return 0;
-}
-
static int __maybe_unused cs35l56_sdw_clk_stop(struct sdw_slave *peripheral,
enum sdw_clk_stop_mode mode,
enum sdw_clk_stop_type type)
@@ -405,7 +331,6 @@ static const struct sdw_slave_ops cs35l56_sdw_ops = {
.read_prop = cs35l56_sdw_read_prop,
.interrupt_callback = cs35l56_sdw_interrupt,
.update_status = cs35l56_sdw_update_status,
- .bus_config = cs35l56_sdw_bus_config,
#ifdef DEBUG
.clk_stop = cs35l56_sdw_clk_stop,
#endif
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index 30497152e02a..e7e8d617da94 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -20,6 +20,18 @@ static const struct reg_sequence cs35l56_patch[] = {
* Firmware can change these to non-defaults to satisfy SDCA.
* Ensure that they are at known defaults.
*/
+ { CS35L56_ASP1_ENABLES1, 0x00000000 },
+ { CS35L56_ASP1_CONTROL1, 0x00000028 },
+ { CS35L56_ASP1_CONTROL2, 0x18180200 },
+ { CS35L56_ASP1_CONTROL3, 0x00000002 },
+ { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 },
+ { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
+ { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
+ { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
+ { CS35L56_ASP1TX1_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX2_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX3_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX4_INPUT, 0x00000000 },
{ CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 },
{ CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 },
{ CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 },
@@ -41,12 +53,18 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED);
static const struct reg_default cs35l56_reg_defaults[] = {
/* no defaults for OTP_MEM - first read populates cache */
- /*
- * No defaults for ASP1 control or ASP1TX mixer. See
- * cs35l56_populate_asp1_register_defaults() and
- * cs35l56_sync_asp1_mixer_widgets_with_firmware().
- */
-
+ { CS35L56_ASP1_ENABLES1, 0x00000000 },
+ { CS35L56_ASP1_CONTROL1, 0x00000028 },
+ { CS35L56_ASP1_CONTROL2, 0x18180200 },
+ { CS35L56_ASP1_CONTROL3, 0x00000002 },
+ { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 },
+ { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
+ { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
+ { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
+ { CS35L56_ASP1TX1_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX2_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX3_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX4_INPUT, 0x00000000 },
{ CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 },
{ CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 },
{ CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 },
@@ -206,77 +224,6 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
}
}
-static const struct reg_sequence cs35l56_asp1_defaults[] = {
- REG_SEQ0(CS35L56_ASP1_ENABLES1, 0x00000000),
- REG_SEQ0(CS35L56_ASP1_CONTROL1, 0x00000028),
- REG_SEQ0(CS35L56_ASP1_CONTROL2, 0x18180200),
- REG_SEQ0(CS35L56_ASP1_CONTROL3, 0x00000002),
- REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL1, 0x03020100),
- REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL5, 0x00020100),
- REG_SEQ0(CS35L56_ASP1_DATA_CONTROL1, 0x00000018),
- REG_SEQ0(CS35L56_ASP1_DATA_CONTROL5, 0x00000018),
- REG_SEQ0(CS35L56_ASP1TX1_INPUT, 0x00000000),
- REG_SEQ0(CS35L56_ASP1TX2_INPUT, 0x00000000),
- REG_SEQ0(CS35L56_ASP1TX3_INPUT, 0x00000000),
- REG_SEQ0(CS35L56_ASP1TX4_INPUT, 0x00000000),
-};
-
-/*
- * The firmware can have control of the ASP so we don't provide regmap
- * with defaults for these registers, to prevent a regcache_sync() from
- * overwriting the firmware settings. But if the machine driver hooks up
- * the ASP it means the driver is taking control of the ASP, so then the
- * registers are populated with the defaults.
- */
-int cs35l56_init_asp1_regs_for_driver_control(struct cs35l56_base *cs35l56_base)
-{
- if (!cs35l56_base->fw_owns_asp1)
- return 0;
-
- cs35l56_base->fw_owns_asp1 = false;
-
- return regmap_multi_reg_write(cs35l56_base->regmap, cs35l56_asp1_defaults,
- ARRAY_SIZE(cs35l56_asp1_defaults));
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_init_asp1_regs_for_driver_control, SND_SOC_CS35L56_SHARED);
-
-/*
- * The firmware boot sequence can overwrite the ASP1 config registers so that
- * they don't match regmap's view of their values. Rewrite the values from the
- * regmap cache into the hardware registers.
- */
-int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base)
-{
- struct reg_sequence asp1_regs[ARRAY_SIZE(cs35l56_asp1_defaults)];
- int i, ret;
-
- if (cs35l56_base->fw_owns_asp1)
- return 0;
-
- memcpy(asp1_regs, cs35l56_asp1_defaults, sizeof(asp1_regs));
-
- /* Read current values from regmap cache into the write sequence */
- for (i = 0; i < ARRAY_SIZE(asp1_regs); ++i) {
- ret = regmap_read(cs35l56_base->regmap, asp1_regs[i].reg, &asp1_regs[i].def);
- if (ret)
- goto err;
- }
-
- /* Write the values cache-bypassed so that they will be written to silicon */
- ret = regmap_multi_reg_write_bypassed(cs35l56_base->regmap, asp1_regs,
- ARRAY_SIZE(asp1_regs));
- if (ret)
- goto err;
-
- return 0;
-
-err:
- dev_err(cs35l56_base->dev, "Failed to sync ASP1 registers: %d\n", ret);
-
- return ret;
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_force_sync_asp1_registers_from_cache, SND_SOC_CS35L56_SHARED);
-
int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command)
{
unsigned int val;
@@ -298,19 +245,13 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, SND_SOC_CS35L56_SHARED);
int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base)
{
int ret;
- unsigned int reg;
unsigned int val;
ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_SHUTDOWN);
if (ret)
return ret;
- if (cs35l56_base->rev < CS35L56_REVID_B0)
- reg = CS35L56_DSP1_PM_CUR_STATE_A1;
- else
- reg = CS35L56_DSP1_PM_CUR_STATE;
-
- ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg,
+ ret = regmap_read_poll_timeout(cs35l56_base->regmap, CS35L56_DSP1_PM_CUR_STATE,
val, (val == CS35L56_HALO_STATE_SHUTDOWN),
CS35L56_HALO_STATE_POLL_US,
CS35L56_HALO_STATE_TIMEOUT_US);
@@ -323,15 +264,9 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_firmware_shutdown, SND_SOC_CS35L56_SHARED);
int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base)
{
- unsigned int reg;
unsigned int val = 0;
int read_ret, poll_ret;
- if (cs35l56_base->rev < CS35L56_REVID_B0)
- reg = CS35L56_DSP1_HALO_STATE_A1;
- else
- reg = CS35L56_DSP1_HALO_STATE;
-
/*
* The regmap must remain in cache-only until the chip has
* booted, so use a bypassed read of the status register.
@@ -341,7 +276,7 @@ int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base)
CS35L56_HALO_STATE_POLL_US,
CS35L56_HALO_STATE_TIMEOUT_US,
false,
- cs35l56_base->regmap, reg, &val);
+ cs35l56_base->regmap, CS35L56_DSP1_HALO_STATE, &val);
if (poll_ret) {
dev_err(cs35l56_base->dev, "Firmware boot timed out(%d): HALO_STATE=%#x\n",
@@ -397,7 +332,7 @@ int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq)
{
int ret;
- if (!irq)
+ if (irq < 1)
return 0;
ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq,
@@ -779,11 +714,6 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
else
cs35l56_wait_control_port_ready();
- /*
- * The HALO_STATE register is in different locations on Ax and B0
- * devices so the REVID needs to be determined before waiting for the
- * firmware to boot.
- */
ret = regmap_read_bypassed(cs35l56_base->regmap, CS35L56_REVID, &revid);
if (ret < 0) {
dev_err(cs35l56_base->dev, "Get Revision ID failed\n");
@@ -857,9 +787,16 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, SND_SOC_CS35L56_SHARED);
int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base)
{
struct gpio_descs *descs;
- int speaker_id;
+ u32 speaker_id;
int i, ret;
+ /* Attempt to read the speaker type from a device property first */
+ ret = device_property_read_u32(cs35l56_base->dev, "cirrus,speaker-id", &speaker_id);
+ if (!ret) {
+ dev_dbg(cs35l56_base->dev, "Speaker ID = %d\n", speaker_id);
+ return speaker_id;
+ }
+
/* Read the speaker type qualifier from the motherboard GPIOs */
descs = gpiod_get_array_optional(cs35l56_base->dev, "spk-id", GPIOD_IN);
if (!descs) {
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index 758dfdf9d3ea..84c34f5b1a51 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -63,131 +63,6 @@ static int cs35l56_dspwait_put_volsw(struct snd_kcontrol *kcontrol,
return snd_soc_put_volsw(kcontrol, ucontrol);
}
-static const unsigned short cs35l56_asp1_mixer_regs[] = {
- CS35L56_ASP1TX1_INPUT, CS35L56_ASP1TX2_INPUT,
- CS35L56_ASP1TX3_INPUT, CS35L56_ASP1TX4_INPUT,
-};
-
-static const char * const cs35l56_asp1_mux_control_names[] = {
- "ASP1 TX1 Source", "ASP1 TX2 Source", "ASP1 TX3 Source", "ASP1 TX4 Source"
-};
-
-static int cs35l56_sync_asp1_mixer_widgets_with_firmware(struct cs35l56_private *cs35l56)
-{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cs35l56->component);
- const char *prefix = cs35l56->component->name_prefix;
- char full_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
- const char *name;
- struct snd_kcontrol *kcontrol;
- struct soc_enum *e;
- unsigned int val[4];
- int i, item, ret;
-
- if (cs35l56->asp1_mixer_widgets_initialized)
- return 0;
-
- /*
- * Resume so we can read the registers from silicon if the regmap
- * cache has not yet been populated.
- */
- ret = pm_runtime_resume_and_get(cs35l56->base.dev);
- if (ret < 0)
- return ret;
-
- /* Wait for firmware download and reboot */
- cs35l56_wait_dsp_ready(cs35l56);
-
- ret = regmap_bulk_read(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT,
- val, ARRAY_SIZE(val));
-
- pm_runtime_mark_last_busy(cs35l56->base.dev);
- pm_runtime_put_autosuspend(cs35l56->base.dev);
-
- if (ret) {
- dev_err(cs35l56->base.dev, "Failed to read ASP1 mixer regs: %d\n", ret);
- return ret;
- }
-
- for (i = 0; i < ARRAY_SIZE(cs35l56_asp1_mux_control_names); ++i) {
- name = cs35l56_asp1_mux_control_names[i];
-
- if (prefix) {
- snprintf(full_name, sizeof(full_name), "%s %s", prefix, name);
- name = full_name;
- }
-
- kcontrol = snd_soc_card_get_kcontrol_locked(dapm->card, name);
- if (!kcontrol) {
- dev_warn(cs35l56->base.dev, "Could not find control %s\n", name);
- continue;
- }
-
- e = (struct soc_enum *)kcontrol->private_value;
- item = snd_soc_enum_val_to_item(e, val[i] & CS35L56_ASP_TXn_SRC_MASK);
- snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
- }
-
- cs35l56->asp1_mixer_widgets_initialized = true;
-
- return 0;
-}
-
-static int cs35l56_dspwait_asp1tx_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
- struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- int index = e->shift_l;
- unsigned int addr, val;
- int ret;
-
- ret = cs35l56_sync_asp1_mixer_widgets_with_firmware(cs35l56);
- if (ret)
- return ret;
-
- addr = cs35l56_asp1_mixer_regs[index];
- ret = regmap_read(cs35l56->base.regmap, addr, &val);
- if (ret)
- return ret;
-
- val &= CS35L56_ASP_TXn_SRC_MASK;
- ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
-
- return 0;
-}
-
-static int cs35l56_dspwait_asp1tx_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
- struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- int item = ucontrol->value.enumerated.item[0];
- int index = e->shift_l;
- unsigned int addr, val;
- bool changed;
- int ret;
-
- ret = cs35l56_sync_asp1_mixer_widgets_with_firmware(cs35l56);
- if (ret)
- return ret;
-
- addr = cs35l56_asp1_mixer_regs[index];
- val = snd_soc_enum_item_to_val(e, item);
-
- ret = regmap_update_bits_check(cs35l56->base.regmap, addr,
- CS35L56_ASP_TXn_SRC_MASK, val, &changed);
- if (ret)
- return ret;
-
- if (changed)
- snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
-
- return changed;
-}
-
static DECLARE_TLV_DB_SCALE(vol_tlv, -10000, 25, 0);
static const struct snd_kcontrol_new cs35l56_controls[] = {
@@ -196,7 +71,11 @@ static const struct snd_kcontrol_new cs35l56_controls[] = {
cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw),
SOC_SINGLE_S_EXT_TLV("Speaker Volume",
CS35L56_MAIN_RENDER_USER_VOLUME,
- 6, -400, 400, 9, 0,
+ CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT,
+ CS35L56_MAIN_RENDER_USER_VOLUME_MIN,
+ CS35L56_MAIN_RENDER_USER_VOLUME_MAX,
+ CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT,
+ 0,
cs35l56_dspwait_get_volsw,
cs35l56_dspwait_put_volsw,
vol_tlv),
@@ -206,44 +85,40 @@ static const struct snd_kcontrol_new cs35l56_controls[] = {
};
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx1_enum,
- SND_SOC_NOPM,
- 0, 0,
+ CS35L56_ASP1TX1_INPUT,
+ 0, CS35L56_ASP_TXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new asp1_tx1_mux =
- SOC_DAPM_ENUM_EXT("ASP1TX1 SRC", cs35l56_asp1tx1_enum,
- cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put);
+ SOC_DAPM_ENUM("ASP1TX1 SRC", cs35l56_asp1tx1_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx2_enum,
- SND_SOC_NOPM,
- 1, 0,
+ CS35L56_ASP1TX2_INPUT,
+ 0, CS35L56_ASP_TXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new asp1_tx2_mux =
- SOC_DAPM_ENUM_EXT("ASP1TX2 SRC", cs35l56_asp1tx2_enum,
- cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put);
+ SOC_DAPM_ENUM("ASP1TX2 SRC", cs35l56_asp1tx2_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx3_enum,
- SND_SOC_NOPM,
- 2, 0,
+ CS35L56_ASP1TX3_INPUT,
+ 0, CS35L56_ASP_TXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new asp1_tx3_mux =
- SOC_DAPM_ENUM_EXT("ASP1TX3 SRC", cs35l56_asp1tx3_enum,
- cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put);
+ SOC_DAPM_ENUM("ASP1TX3 SRC", cs35l56_asp1tx3_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx4_enum,
- SND_SOC_NOPM,
- 3, 0,
+ CS35L56_ASP1TX4_INPUT,
+ 0, CS35L56_ASP_TXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new asp1_tx4_mux =
- SOC_DAPM_ENUM_EXT("ASP1TX4 SRC", cs35l56_asp1tx4_enum,
- cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put);
+ SOC_DAPM_ENUM("ASP1TX4 SRC", cs35l56_asp1tx4_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx1_enum,
CS35L56_SWIRE_DP3_CH1_INPUT,
@@ -281,21 +156,6 @@ static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx4_enum,
static const struct snd_kcontrol_new sdw1_tx4_mux =
SOC_DAPM_ENUM("SDW1TX4 SRC", cs35l56_sdw1tx4_enum);
-static int cs35l56_asp1_cfg_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 cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- /* Override register values set by firmware boot */
- return cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base);
- default:
- return 0;
- }
-}
-
static int cs35l56_play_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -332,9 +192,6 @@ static const struct snd_soc_dapm_widget cs35l56_dapm_widgets[] = {
SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_B", 0, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_AMP", 0, 0),
- SND_SOC_DAPM_SUPPLY("ASP1 CFG", SND_SOC_NOPM, 0, 0, cs35l56_asp1_cfg_event,
- SND_SOC_DAPM_PRE_PMU),
-
SND_SOC_DAPM_SUPPLY("PLAY", SND_SOC_NOPM, 0, 0, cs35l56_play_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -402,9 +259,6 @@ static const struct snd_soc_dapm_route cs35l56_audio_map[] = {
{ "AMP", NULL, "VDD_B" },
{ "AMP", NULL, "VDD_AMP" },
- { "ASP1 Playback", NULL, "ASP1 CFG" },
- { "ASP1 Capture", NULL, "ASP1 CFG" },
-
{ "ASP1 Playback", NULL, "PLAY" },
{ "SDW1 Playback", NULL, "PLAY" },
@@ -455,14 +309,9 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f
{
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component);
unsigned int val;
- int ret;
dev_dbg(cs35l56->base.dev, "%s: %#x\n", __func__, fmt);
- ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
- if (ret)
- return ret;
-
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBC_CFC:
break;
@@ -536,11 +385,6 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx
unsigned int rx_mask, int slots, int slot_width)
{
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
- int ret;
-
- ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
- if (ret)
- return ret;
if ((slots == 0) || (slot_width == 0)) {
dev_dbg(cs35l56->base.dev, "tdm config cleared\n");
@@ -589,11 +433,6 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream,
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
unsigned int rate = params_rate(params);
u8 asp_width, asp_wl;
- int ret;
-
- ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
- if (ret)
- return ret;
asp_wl = params_width(params);
if (cs35l56->asp_slot_width)
@@ -650,11 +489,7 @@ static int cs35l56_asp_dai_set_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
- int freq_id, ret;
-
- ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
- if (ret)
- return ret;
+ int freq_id;
if (freq == 0) {
cs35l56->sysclk_set = false;
@@ -1035,13 +870,6 @@ static int cs35l56_component_probe(struct snd_soc_component *component)
debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->base.can_hibernate);
debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->base.fw_patched);
- /*
- * The widgets for the ASP1TX mixer can't be initialized
- * until the firmware has been downloaded and rebooted.
- */
- regcache_drop_region(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT, CS35L56_ASP1TX4_INPUT);
- cs35l56->asp1_mixer_widgets_initialized = false;
-
queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);
return 0;
@@ -1432,9 +1260,6 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
cs35l56->base.cal_index = -1;
cs35l56->speaker_id = -ENOENT;
- /* Assume that the firmware owns ASP1 until we know different */
- cs35l56->base.fw_owns_asp1 = true;
-
dev_set_drvdata(cs35l56->base.dev, cs35l56);
cs35l56_fill_supply_names(cs35l56->supplies);
diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h
index b000e7365e40..8a987ec01507 100644
--- a/sound/soc/codecs/cs35l56.h
+++ b/sound/soc/codecs/cs35l56.h
@@ -51,8 +51,6 @@ struct cs35l56_private {
u8 asp_slot_count;
bool tdm_mode;
bool sysclk_set;
- bool asp1_mixer_widgets_initialized;
- u8 old_sdw_clock_scale;
};
extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi;
diff --git a/sound/soc/codecs/cs530x-i2c.c b/sound/soc/codecs/cs530x-i2c.c
new file mode 100644
index 000000000000..56659bf735db
--- /dev/null
+++ b/sound/soc/codecs/cs530x-i2c.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS530x CODEC driver
+//
+// Copyright (C) 2024 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include "cs530x.h"
+
+static const struct of_device_id cs530x_of_match[] = {
+ {
+ .compatible = "cirrus,cs5302",
+ .data = (void *)CS5302,
+ }, {
+ .compatible = "cirrus,cs5304",
+ .data = (void *)CS5304,
+ }, {
+ .compatible = "cirrus,cs5308",
+ .data = (void *)CS5308,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cs530x_of_match);
+
+static const struct i2c_device_id cs530x_i2c_id[] = {
+ { "cs5302", CS5302 },
+ { "cs5304", CS5304 },
+ { "cs5308", CS5308 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cs530x_i2c_id);
+
+static int cs530x_i2c_probe(struct i2c_client *client)
+{
+ struct cs530x_priv *cs530x;
+
+ cs530x = devm_kzalloc(&client->dev, sizeof(*cs530x), GFP_KERNEL);
+ if (!cs530x)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, cs530x);
+
+ cs530x->regmap = devm_regmap_init_i2c(client, &cs530x_regmap);
+ if (IS_ERR(cs530x->regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(cs530x->regmap),
+ "Failed to allocate register map\n");
+
+ cs530x->devtype = (uintptr_t)i2c_get_match_data(client);
+ cs530x->dev = &client->dev;
+
+ return cs530x_probe(cs530x);
+}
+
+static struct i2c_driver cs530x_i2c_driver = {
+ .driver = {
+ .name = "cs530x",
+ .of_match_table = cs530x_of_match,
+ },
+ .probe = cs530x_i2c_probe,
+ .id_table = cs530x_i2c_id,
+};
+module_i2c_driver(cs530x_i2c_driver);
+
+MODULE_DESCRIPTION("I2C CS530X driver");
+MODULE_IMPORT_NS(SND_SOC_CS530X);
+MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paulha@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c
new file mode 100644
index 000000000000..25a86a32e936
--- /dev/null
+++ b/sound/soc/codecs/cs530x.c
@@ -0,0 +1,971 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS530x CODEC driver
+//
+// Copyright (C) 2024 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <sound/core.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <sound/initval.h>
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <linux/pm.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "cs530x.h"
+
+#define CS530X_MAX_ADC_CH 8
+#define CS530X_MIN_ADC_CH 2
+
+static const char *cs530x_supply_names[CS530X_NUM_SUPPLIES] = {
+ "vdd-a",
+ "vdd-io",
+};
+
+static const struct reg_default cs530x_reg_defaults[] = {
+ { CS530X_CLK_CFG_0, 0x30 },
+ { CS530X_CLK_CFG_1, 0x0001 },
+ { CS530X_CHIP_ENABLE, 0 },
+ { CS530X_ASP_CFG, 0 },
+ { CS530X_SIGNAL_PATH_CFG, 0 },
+ { CS530X_IN_ENABLES, 0 },
+ { CS530X_IN_RAMP_SUM, 0x0022 },
+ { CS530X_IN_FILTER, 0 },
+ { CS530X_IN_HIZ, 0 },
+ { CS530X_IN_INV, 0 },
+ { CS530X_IN_VOL_CTRL1_0, 0x8000 },
+ { CS530X_IN_VOL_CTRL1_1, 0x8000 },
+ { CS530X_IN_VOL_CTRL2_0, 0x8000 },
+ { CS530X_IN_VOL_CTRL2_1, 0x8000 },
+ { CS530X_IN_VOL_CTRL3_0, 0x8000 },
+ { CS530X_IN_VOL_CTRL3_1, 0x8000 },
+ { CS530X_IN_VOL_CTRL4_0, 0x8000 },
+ { CS530X_IN_VOL_CTRL4_1, 0x8000 },
+ { CS530X_PAD_FN, 0 },
+ { CS530X_PAD_LVL, 0 },
+};
+
+static bool cs530x_read_and_write_regs(unsigned int reg)
+{
+ switch (reg) {
+ case CS530X_CLK_CFG_0:
+ case CS530X_CLK_CFG_1:
+ case CS530X_CHIP_ENABLE:
+ case CS530X_ASP_CFG:
+ case CS530X_SIGNAL_PATH_CFG:
+ case CS530X_IN_ENABLES:
+ case CS530X_IN_RAMP_SUM:
+ case CS530X_IN_FILTER:
+ case CS530X_IN_HIZ:
+ case CS530X_IN_INV:
+ case CS530X_IN_VOL_CTRL1_0:
+ case CS530X_IN_VOL_CTRL1_1:
+ case CS530X_IN_VOL_CTRL2_0:
+ case CS530X_IN_VOL_CTRL2_1:
+ case CS530X_IN_VOL_CTRL3_0:
+ case CS530X_IN_VOL_CTRL3_1:
+ case CS530X_IN_VOL_CTRL4_0:
+ case CS530X_IN_VOL_CTRL4_1:
+ case CS530X_PAD_FN:
+ case CS530X_PAD_LVL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs530x_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS530X_DEVID:
+ case CS530X_REVID:
+ return true;
+ default:
+ return cs530x_read_and_write_regs(reg);
+ }
+}
+
+static bool cs530x_writeable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS530X_SW_RESET:
+ case CS530X_IN_VOL_CTRL5:
+ return true;
+ default:
+ return cs530x_read_and_write_regs(reg);
+ }
+}
+
+static int cs530x_put_volsw_vu(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+ int ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (ret)
+ goto volsw_err;
+
+ /* Write IN_VU bit for the volume change to take effect */
+ regmap_write(regmap, CS530X_IN_VOL_CTRL5, CS530X_IN_VU);
+
+volsw_err:
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return ret;
+}
+
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1270, 50, 0);
+
+static const char * const cs530x_in_hpf_text[] = {
+ "Min Phase Slow Roll-off",
+ "Min Phase Fast Roll-off",
+ "Linear Phase Slow Roll-off",
+ "Linear Phase Fast Roll-off",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs530x_in_hpf_enum, CS530X_IN_FILTER,
+ CS530X_IN_FILTER_SHIFT,
+ cs530x_in_hpf_text);
+
+static const char * const cs530x_in_4ch_sum_text[] = {
+ "None",
+ "Groups of 2",
+ "Groups of 4",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch4_enum, CS530X_IN_RAMP_SUM,
+ CS530X_IN_SUM_MODE_SHIFT,
+ cs530x_in_4ch_sum_text);
+
+static const struct snd_kcontrol_new cs530x_in_sum_4ch_controls[] = {
+SOC_ENUM("IN Sum Select", cs530x_in_sum_ch4_enum),
+};
+
+static const char * const cs530x_in_8ch_sum_text[] = {
+ "None",
+ "Groups of 2",
+ "Groups of 4",
+ "Groups of 8",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch8_enum, CS530X_IN_RAMP_SUM,
+ CS530X_IN_SUM_MODE_SHIFT,
+ cs530x_in_8ch_sum_text);
+
+static const struct snd_kcontrol_new cs530x_in_sum_8ch_controls[] = {
+SOC_ENUM("IN Sum Select", cs530x_in_sum_ch8_enum),
+};
+
+
+static const char * const cs530x_vol_ramp_text[] = {
+ "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
+ "15ms/6dB", "30ms/6dB",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs530x_ramp_inc_enum, CS530X_IN_RAMP_SUM,
+ CS530X_RAMP_RATE_INC_SHIFT,
+ cs530x_vol_ramp_text);
+
+static SOC_ENUM_SINGLE_DECL(cs530x_ramp_dec_enum, CS530X_IN_RAMP_SUM,
+ CS530X_RAMP_RATE_DEC_SHIFT,
+ cs530x_vol_ramp_text);
+
+static const struct snd_kcontrol_new cs530x_in_1_to_2_controls[] = {
+SOC_SINGLE_EXT_TLV("IN1 Volume", CS530X_IN_VOL_CTRL1_0, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN2 Volume", CS530X_IN_VOL_CTRL1_1, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+
+SOC_ENUM("IN HPF Select", cs530x_in_hpf_enum),
+SOC_ENUM("Input Ramp Up", cs530x_ramp_inc_enum),
+SOC_ENUM("Input Ramp Down", cs530x_ramp_dec_enum),
+
+SOC_SINGLE("ADC1 Invert Switch", CS530X_IN_INV, CS530X_IN1_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC2 Invert Switch", CS530X_IN_INV, CS530X_IN2_INV_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new cs530x_in_3_to_4_controls[] = {
+SOC_SINGLE_EXT_TLV("IN3 Volume", CS530X_IN_VOL_CTRL2_0, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN4 Volume", CS530X_IN_VOL_CTRL2_1, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+
+SOC_SINGLE("ADC3 Invert Switch", CS530X_IN_INV, CS530X_IN3_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC4 Invert Switch", CS530X_IN_INV, CS530X_IN4_INV_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new cs530x_in_5_to_8_controls[] = {
+SOC_SINGLE_EXT_TLV("IN5 Volume", CS530X_IN_VOL_CTRL3_0, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN6 Volume", CS530X_IN_VOL_CTRL3_1, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN7 Volume", CS530X_IN_VOL_CTRL4_0, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN8 Volume", CS530X_IN_VOL_CTRL4_1, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+
+SOC_SINGLE("ADC5 Invert Switch", CS530X_IN_INV, CS530X_IN5_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC6 Invert Switch", CS530X_IN_INV, CS530X_IN6_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC7 Invert Switch", CS530X_IN_INV, CS530X_IN7_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC8 Invert Switch", CS530X_IN_INV, CS530X_IN8_INV_SHIFT, 1, 0),
+};
+
+static int cs530x_adc_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 cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ cs530x->adc_pairs_count++;
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
+ (w->shift * 2), CS530X_IN_MUTE);
+ regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
+ ((w->shift+1) * 2), CS530X_IN_MUTE);
+
+ cs530x->adc_pairs_count--;
+ if (!cs530x->adc_pairs_count) {
+ usleep_range(1000, 1100);
+ return regmap_write(regmap, CS530X_IN_VOL_CTRL5,
+ CS530X_IN_VU);
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
+ (w->shift * 2), CS530X_IN_MUTE);
+ regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
+ ((w->shift+1) * 2), CS530X_IN_MUTE);
+ return regmap_write(regmap, CS530X_IN_VOL_CTRL5,
+ CS530X_IN_VU);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new adc12_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+static const struct snd_kcontrol_new adc34_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+static const struct snd_kcontrol_new adc56_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+static const struct snd_kcontrol_new adc78_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+static const struct snd_kcontrol_new in_hpf_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+/* General DAPM widgets for all devices */
+static const struct snd_soc_dapm_widget cs530x_gen_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("Global Enable", CS530X_CHIP_ENABLE, 0, 0, NULL, 0),
+};
+
+/* ADC's Channels 1 and 2 plus generic ADC DAPM events */
+static const struct snd_soc_dapm_widget cs530x_adc_ch12_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1"),
+SND_SOC_DAPM_INPUT("IN2"),
+SND_SOC_DAPM_ADC_E("ADC1", NULL, CS530X_IN_ENABLES, 0, 0,
+ cs530x_adc_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_ADC("ADC2", NULL, CS530X_IN_ENABLES, 1, 0),
+SND_SOC_DAPM_SWITCH("ADC12 Enable", SND_SOC_NOPM, 0, 0, &adc12_ctrl),
+SND_SOC_DAPM_SWITCH("IN HPF", CS530X_IN_FILTER, CS530X_IN_HPF_EN_SHIFT,
+ 0, &in_hpf_ctrl),
+};
+
+/* ADC's Channels 3 and 4 */
+static const struct snd_soc_dapm_widget cs530x_adc_ch34_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN3"),
+SND_SOC_DAPM_INPUT("IN4"),
+SND_SOC_DAPM_ADC_E("ADC3", NULL, CS530X_IN_ENABLES, 2, 0,
+ cs530x_adc_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_ADC("ADC4", NULL, CS530X_IN_ENABLES, 3, 0),
+SND_SOC_DAPM_SWITCH("ADC34 Enable", SND_SOC_NOPM, 0, 0, &adc34_ctrl),
+};
+
+/* ADC's Channels 5 to 8 */
+static const struct snd_soc_dapm_widget cs530x_adc_ch58_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN5"),
+SND_SOC_DAPM_INPUT("IN6"),
+SND_SOC_DAPM_INPUT("IN7"),
+SND_SOC_DAPM_INPUT("IN8"),
+SND_SOC_DAPM_ADC_E("ADC5", NULL, CS530X_IN_ENABLES, 4, 0,
+ cs530x_adc_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_ADC("ADC6", NULL, CS530X_IN_ENABLES, 5, 0),
+SND_SOC_DAPM_SWITCH("ADC56 Enable", SND_SOC_NOPM, 0, 0, &adc56_ctrl),
+SND_SOC_DAPM_ADC_E("ADC7", NULL, CS530X_IN_ENABLES, 6, 0,
+ cs530x_adc_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_ADC("ADC8", NULL, CS530X_IN_ENABLES, 7, 0),
+SND_SOC_DAPM_SWITCH("ADC78 Enable", SND_SOC_NOPM, 0, 0, &adc78_ctrl),
+};
+
+static const struct snd_soc_dapm_route adc_ch1_2_routes[] = {
+ { "ADC1", NULL, "Global Enable" },
+ { "ADC2", NULL, "Global Enable" },
+
+ { "ADC12 Enable", "Switch", "IN1" },
+ { "ADC12 Enable", "Switch", "IN2" },
+ { "ADC1", NULL, "ADC12 Enable" },
+ { "ADC2", NULL, "ADC12 Enable" },
+ { "IN HPF", "Switch", "ADC1" },
+ { "IN HPF", "Switch", "ADC2" },
+
+ { "AIF Capture", NULL, "IN HPF" },
+ { "AIF Capture", NULL, "ADC1" },
+ { "AIF Capture", NULL, "ADC2" },
+};
+
+static const struct snd_soc_dapm_route adc_ch3_4_routes[] = {
+ { "ADC3", NULL, "Global Enable" },
+ { "ADC4", NULL, "Global Enable" },
+
+ { "ADC34 Enable", "Switch", "IN3" },
+ { "ADC34 Enable", "Switch", "IN4" },
+ { "ADC3", NULL, "ADC34 Enable" },
+ { "ADC4", NULL, "ADC34 Enable" },
+ { "IN HPF", "Switch", "ADC3" },
+ { "IN HPF", "Switch", "ADC4" },
+
+ { "AIF Capture", NULL, "ADC3" },
+ { "AIF Capture", NULL, "ADC4" },
+};
+
+static const struct snd_soc_dapm_route adc_ch5_8_routes[] = {
+ { "ADC5", NULL, "Global Enable" },
+ { "ADC6", NULL, "Global Enable" },
+ { "ADC7", NULL, "Global Enable" },
+ { "ADC8", NULL, "Global Enable" },
+
+ { "ADC56 Enable", "Switch", "IN5" },
+ { "ADC56 Enable", "Switch", "IN6" },
+ { "ADC5", NULL, "ADC56 Enable" },
+ { "ADC6", NULL, "ADC56 Enable" },
+ { "IN HPF", "Switch", "ADC5" },
+ { "IN HPF", "Switch", "ADC6" },
+
+ { "AIF Capture", NULL, "ADC5" },
+ { "AIF Capture", NULL, "ADC6" },
+
+ { "ADC78 Enable", "Switch", "IN7" },
+ { "ADC78 Enable", "Switch", "IN8" },
+ { "ADC7", NULL, "ADC78 Enable" },
+ { "ADC8", NULL, "ADC78 Enable" },
+ { "IN HPF", "Switch", "ADC7" },
+ { "IN HPF", "Switch", "ADC8" },
+
+ { "AIF Capture", NULL, "ADC7" },
+ { "AIF Capture", NULL, "ADC8" },
+};
+
+static void cs530x_add_12_adc_widgets(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+ snd_soc_add_component_controls(component,
+ cs530x_in_1_to_2_controls,
+ ARRAY_SIZE(cs530x_in_1_to_2_controls));
+
+ snd_soc_dapm_new_controls(dapm, cs530x_adc_ch12_dapm_widgets,
+ ARRAY_SIZE(cs530x_adc_ch12_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, adc_ch1_2_routes,
+ ARRAY_SIZE(adc_ch1_2_routes));
+}
+
+static void cs530x_add_34_adc_widgets(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+ snd_soc_add_component_controls(component,
+ cs530x_in_3_to_4_controls,
+ ARRAY_SIZE(cs530x_in_3_to_4_controls));
+
+ snd_soc_dapm_new_controls(dapm, cs530x_adc_ch34_dapm_widgets,
+ ARRAY_SIZE(cs530x_adc_ch34_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, adc_ch3_4_routes,
+ ARRAY_SIZE(adc_ch3_4_routes));
+}
+
+static int cs530x_set_bclk(struct snd_soc_component *component, const int freq)
+{
+ struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+ unsigned int bclk_val;
+
+ switch (freq) {
+ case 2822400:
+ case 3072000:
+ bclk_val = CS530X_BCLK_2P822_3P072;
+ break;
+ case 5644800:
+ case 6144000:
+ bclk_val = CS530X_BCLK_5P6448_6P144;
+ break;
+ case 11289600:
+ case 12288000:
+ bclk_val = CS530X_BCLK_11P2896_12P288;
+ break;
+ case 22579200:
+ case 24576000:
+ bclk_val = CS530X_BCLK_24P5792_24P576;
+ break;
+ default:
+ dev_err(component->dev, "Invalid BCLK frequency %d\n", freq);
+ return -EINVAL;
+ }
+
+ dev_dbg(component->dev, "BCLK frequency is %d\n", freq);
+
+ return regmap_update_bits(regmap, CS530X_ASP_CFG,
+ CS530X_ASP_BCLK_FREQ_MASK, bclk_val);
+}
+
+static int cs530x_set_pll_refclk(struct snd_soc_component *component,
+ const unsigned int freq)
+{
+ struct cs530x_priv *priv = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = priv->regmap;
+ unsigned int refclk;
+
+ switch (freq) {
+ case 2822400:
+ case 3072000:
+ refclk = CS530X_REFCLK_2P822_3P072;
+ break;
+ case 5644800:
+ case 6144000:
+ refclk = CS530X_REFCLK_5P6448_6P144;
+ break;
+ case 11289600:
+ case 12288000:
+ refclk = CS530X_REFCLK_11P2896_12P288;
+ break;
+ case 22579200:
+ case 24576000:
+ refclk = CS530X_REFCLK_24P5792_24P576;
+ break;
+ default:
+ dev_err(component->dev, "Invalid PLL refclk %d\n", freq);
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
+ CS530X_PLL_REFCLK_FREQ_MASK, refclk);
+}
+
+static int cs530x_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 cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+ int ret = 0, fs = params_rate(params), bclk;
+ unsigned int fs_val;
+
+
+ switch (fs) {
+ case 32000:
+ fs_val = CS530X_FS_32K;
+ break;
+ case 44100:
+ case 48000:
+ fs_val = CS530X_FS_48K_44P1K;
+ break;
+ case 88200:
+ case 96000:
+ fs_val = CS530X_FS_96K_88P2K;
+ break;
+ case 176400:
+ case 192000:
+ fs_val = CS530X_FS_192K_176P4K;
+ break;
+ case 356800:
+ case 384000:
+ fs_val = CS530X_FS_384K_356P8K;
+ break;
+ case 705600:
+ case 768000:
+ fs_val = CS530X_FS_768K_705P6K;
+ break;
+ default:
+ dev_err(component->dev, "Invalid sample rate %d\n", fs);
+ return -EINVAL;
+ }
+
+ cs530x->fs = fs;
+ regmap_update_bits(regmap, CS530X_CLK_CFG_1,
+ CS530X_SAMPLE_RATE_MASK, fs_val);
+
+
+ if (regmap_test_bits(regmap, CS530X_SIGNAL_PATH_CFG,
+ CS530X_TDM_EN_MASK)) {
+ dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n",
+ cs530x->tdm_slots, cs530x->tdm_width);
+ bclk = snd_soc_tdm_params_to_bclk(params,
+ cs530x->tdm_width,
+ cs530x->tdm_slots,
+ 1);
+ } else {
+ bclk = snd_soc_params_to_bclk(params);
+ }
+
+ if (!regmap_test_bits(regmap, CS530X_CLK_CFG_0,
+ CS530X_PLL_REFCLK_SRC_MASK)) {
+ ret = cs530x_set_pll_refclk(component, bclk);
+ if (ret)
+ return ret;
+ }
+
+ return cs530x_set_bclk(component, bclk);
+}
+
+static int cs530x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs530x_priv *priv = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = priv->regmap;
+ unsigned int asp_fmt, asp_cfg = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ asp_cfg = CS530X_ASP_PRIMARY;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ asp_fmt = CS530X_ASP_FMT_DSP_A;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ asp_fmt = CS530X_ASP_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ asp_fmt = CS530X_ASP_FMT_LJ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ asp_cfg |= CS530X_ASP_BCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(regmap, CS530X_ASP_CFG,
+ CS530X_ASP_PRIMARY | CS530X_ASP_BCLK_INV,
+ asp_cfg);
+
+ return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG,
+ CS530X_ASP_FMT_MASK, asp_fmt);
+}
+
+static bool cs530x_check_mclk_freq(struct snd_soc_component *component,
+ const unsigned int freq)
+{
+ switch (freq) {
+ case 24576000:
+ case 22579200:
+ case 12288000:
+ case 11289600:
+ return true;
+ default:
+ dev_err(component->dev, "Invalid MCLK %d\n", freq);
+ return false;
+ }
+}
+
+static int cs530x_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 cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+ unsigned int val;
+
+ switch (tx_mask) {
+ case CS530X_0_1_TDM_SLOT_MASK:
+ case CS530X_0_3_TDM_SLOT_MASK:
+ case CS530X_0_7_TDM_SLOT_MASK:
+ val = CS530X_0_7_TDM_SLOT_VAL;
+ break;
+ case CS530X_2_3_TDM_SLOT_MASK:
+ val = CS530X_2_3_TDM_SLOT_VAL;
+ break;
+ case CS530X_4_5_TDM_SLOT_MASK:
+ case CS530X_4_7_TDM_SLOT_MASK:
+ val = CS530X_4_7_TDM_SLOT_VAL;
+ break;
+ case CS530X_6_7_TDM_SLOT_MASK:
+ val = CS530X_6_7_TDM_SLOT_VAL;
+ break;
+ case CS530X_8_9_TDM_SLOT_MASK:
+ case CS530X_8_11_TDM_SLOT_MASK:
+ case CS530X_8_15_TDM_SLOT_MASK:
+ val = CS530X_8_15_TDM_SLOT_VAL;
+ break;
+ case CS530X_10_11_TDM_SLOT_MASK:
+ val = CS530X_10_11_TDM_SLOT_VAL;
+ break;
+ case CS530X_12_13_TDM_SLOT_MASK:
+ case CS530X_12_15_TDM_SLOT_MASK:
+ val = CS530X_12_15_TDM_SLOT_VAL;
+ break;
+ case CS530X_14_15_TDM_SLOT_MASK:
+ val = CS530X_14_15_TDM_SLOT_VAL;
+ break;
+ default:
+ dev_err(component->dev, "Invalid TX slot(s) 0x%x\n", tx_mask);
+ return -EINVAL;
+ }
+
+ cs530x->tdm_width = slot_width;
+ cs530x->tdm_slots = slots;
+
+ return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG,
+ CS530X_ASP_TDM_SLOT_MASK,
+ val << CS530X_ASP_TDM_SLOT_SHIFT);
+}
+
+static const struct snd_soc_dai_ops cs530x_dai_ops = {
+ .set_fmt = cs530x_set_fmt,
+ .hw_params = cs530x_hw_params,
+ .set_tdm_slot = cs530x_set_tdm_slot,
+};
+
+static const struct snd_soc_dai_driver cs530x_dai = {
+ .name = "cs530x-dai",
+ .capture = {
+ .stream_name = "AIF Capture",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &cs530x_dai_ops,
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+};
+
+static int cs530x_set_pll(struct snd_soc_component *component, int pll_id,
+ int source, unsigned int freq_in,
+ unsigned int freq_out)
+{
+ struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+ unsigned int sysclk_src;
+ int ret;
+
+ regmap_read(regmap, CS530X_CLK_CFG_0, &sysclk_src);
+
+ /* Check if the source is the PLL */
+ if ((sysclk_src & CS530X_SYSCLK_SRC_MASK) == 0)
+ return 0;
+
+ switch (source) {
+ case CS530X_PLL_SRC_MCLK:
+ if (!cs530x_check_mclk_freq(component, freq_in))
+ return -EINVAL;
+
+ ret = cs530x_set_pll_refclk(component, freq_in);
+ if (ret)
+ return ret;
+
+ break;
+ case CS530X_PLL_SRC_BCLK:
+ break;
+ default:
+ dev_err(component->dev, "Invalid PLL source %d\n", source);
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
+ CS530X_PLL_REFCLK_SRC_MASK, source);
+}
+
+static int cs530x_component_probe(struct snd_soc_component *component)
+{
+ struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ int num_widgets;
+
+ snd_soc_dapm_new_controls(dapm, cs530x_gen_dapm_widgets,
+ ARRAY_SIZE(cs530x_gen_dapm_widgets));
+
+ switch (cs530x->devtype) {
+ case CS5302:
+ cs530x_add_12_adc_widgets(component);
+ break;
+ case CS5304:
+ cs530x_add_12_adc_widgets(component);
+ cs530x_add_34_adc_widgets(component);
+
+ num_widgets = ARRAY_SIZE(cs530x_in_sum_4ch_controls);
+ snd_soc_add_component_controls(component,
+ cs530x_in_sum_4ch_controls,
+ num_widgets);
+ break;
+
+ case CS5308:
+ cs530x_add_12_adc_widgets(component);
+ cs530x_add_34_adc_widgets(component);
+
+ num_widgets = ARRAY_SIZE(cs530x_in_5_to_8_controls);
+ snd_soc_add_component_controls(component,
+ cs530x_in_5_to_8_controls,
+ num_widgets);
+
+ num_widgets = ARRAY_SIZE(cs530x_in_sum_8ch_controls);
+ snd_soc_add_component_controls(component,
+ cs530x_in_sum_8ch_controls,
+ num_widgets);
+
+ num_widgets = ARRAY_SIZE(cs530x_adc_ch58_dapm_widgets);
+ snd_soc_dapm_new_controls(dapm, cs530x_adc_ch58_dapm_widgets,
+ num_widgets);
+
+ snd_soc_dapm_add_routes(dapm, adc_ch5_8_routes,
+ ARRAY_SIZE(adc_ch5_8_routes));
+ break;
+ default:
+ dev_err(component->dev, "Invalid device type %d\n",
+ cs530x->devtype);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id,
+ int source, unsigned int freq, int dir)
+{
+ struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+
+ switch (source) {
+ case CS530X_SYSCLK_SRC_MCLK:
+ if (freq != 24560000 && freq != 22572000) {
+ dev_err(component->dev, "Invalid MCLK source rate %d\n",
+ freq);
+ return -EINVAL;
+ }
+
+ cs530x->mclk_rate = freq;
+ break;
+ case CS530X_SYSCLK_SRC_PLL:
+ break;
+ default:
+ dev_err(component->dev, "Invalid clock id %d\n", clk_id);
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
+ CS530X_SYSCLK_SRC_MASK,
+ source << CS530X_SYSCLK_SRC_SHIFT);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_cs530x = {
+ .probe = cs530x_component_probe,
+ .set_sysclk = cs530x_set_sysclk,
+ .set_pll = cs530x_set_pll,
+ .endianness = 1,
+};
+
+const struct regmap_config cs530x_regmap = {
+ .reg_bits = 16,
+ .val_bits = 16,
+
+ .max_register = CS530X_MAX_REGISTER,
+ .readable_reg = cs530x_readable_register,
+ .writeable_reg = cs530x_writeable_register,
+
+ .cache_type = REGCACHE_MAPLE,
+ .reg_defaults = cs530x_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults),
+};
+EXPORT_SYMBOL_NS_GPL(cs530x_regmap, SND_SOC_CS530X);
+
+static int cs530x_check_device_id(struct cs530x_priv *cs530x)
+{
+ struct device *dev = cs530x->dev;
+ unsigned int dev_id, rev;
+ int ret;
+
+ ret = regmap_read(cs530x->regmap, CS530X_DEVID, &dev_id);
+ if (ret)
+ return dev_err_probe(dev, ret, "Can't read device ID\n");
+
+ ret = regmap_read(cs530x->regmap, CS530X_REVID, &rev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Can't read REV ID\n");
+
+ dev_dbg(dev, "Device ID 0x%x Rev ID 0x%x\n", dev_id, rev);
+
+ switch (dev_id) {
+ case CS530X_2CH_ADC_DEV_ID:
+ cs530x->num_adcs = 2;
+ break;
+ case CS530X_4CH_ADC_DEV_ID:
+ cs530x->num_adcs = 4;
+ break;
+ case CS530X_8CH_ADC_DEV_ID:
+ cs530x->num_adcs = 8;
+ break;
+ default:
+ return dev_err_probe(dev, -EINVAL, "Invalid device ID 0x%x\n",
+ dev_id);
+ }
+
+ return 0;
+}
+
+static int cs530x_parse_device_properties(struct cs530x_priv *cs530x)
+{
+ struct regmap *regmap = cs530x->regmap;
+ struct device *dev = cs530x->dev;
+ unsigned int val = 0;
+
+ switch (cs530x->num_adcs) {
+ case 8:
+ if (device_property_read_bool(dev, "cirrus,in-hiz-pin78"))
+ val = CS530X_IN78_HIZ;
+
+ if (device_property_read_bool(dev, "cirrus,in-hiz-pin56"))
+ val |= CS530X_IN56_HIZ;
+
+ fallthrough;
+ case 4:
+ if (device_property_read_bool(dev, "cirrus,in-hiz-pin34"))
+ val |= CS530X_IN34_HIZ;
+
+ fallthrough;
+ case 2:
+ if (device_property_read_bool(dev, "cirrus,in-hiz-pin12"))
+ val |= CS530X_IN12_HIZ;
+
+ return regmap_set_bits(regmap, CS530X_IN_HIZ, val);
+ default:
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid number of adcs %d\n",
+ cs530x->num_adcs);
+ }
+}
+
+int cs530x_probe(struct cs530x_priv *cs530x)
+{
+ struct device *dev = cs530x->dev;
+ int ret, i;
+
+ cs530x->dev_dai = devm_kmemdup(dev, &cs530x_dai,
+ sizeof(*(cs530x->dev_dai)),
+ GFP_KERNEL);
+ if (!cs530x->dev_dai)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(cs530x->supplies); i++)
+ cs530x->supplies[i].supply = cs530x_supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs530x->supplies),
+ cs530x->supplies);
+ if (ret != 0)
+ return dev_err_probe(dev, ret, "Failed to request supplies");
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs530x->supplies),
+ cs530x->supplies);
+ if (ret != 0)
+ return dev_err_probe(dev, ret, "Failed to enable supplies");
+
+ cs530x->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(cs530x->reset_gpio)) {
+ ret = dev_err_probe(dev, PTR_ERR(cs530x->reset_gpio),
+ "Reset gpio not available\n");
+ goto err_regulator;
+ }
+
+ if (cs530x->reset_gpio) {
+ usleep_range(2000, 2100);
+ gpiod_set_value_cansleep(cs530x->reset_gpio, 0);
+ }
+
+ usleep_range(5000, 5100);
+ ret = cs530x_check_device_id(cs530x);
+ if (ret)
+ goto err_reset;
+
+ if (!cs530x->reset_gpio) {
+ ret = regmap_write(cs530x->regmap, CS530X_SW_RESET,
+ CS530X_SW_RST_VAL);
+ if (ret) {
+ dev_err_probe(dev, ret, "Soft Reset Failed\n");
+ goto err_reset;
+ }
+ }
+
+ ret = cs530x_parse_device_properties(cs530x);
+ if (ret)
+ goto err_reset;
+
+ cs530x->dev_dai->capture.channels_max = cs530x->num_adcs;
+
+ ret = devm_snd_soc_register_component(dev,
+ &soc_component_dev_cs530x, cs530x->dev_dai, 1);
+ if (ret) {
+ dev_err_probe(dev, ret, "Can't register cs530x component\n");
+ goto err_reset;
+ }
+
+ return 0;
+
+err_reset:
+ gpiod_set_value_cansleep(cs530x->reset_gpio, 1);
+
+err_regulator:
+ regulator_bulk_disable(ARRAY_SIZE(cs530x->supplies),
+ cs530x->supplies);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs530x_probe, SND_SOC_CS530X);
+
+MODULE_DESCRIPTION("CS530X CODEC Driver");
+MODULE_AUTHOR("Paul Handrigan <paulha@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h
new file mode 100644
index 000000000000..f473e33eb835
--- /dev/null
+++ b/sound/soc/codecs/cs530x.h
@@ -0,0 +1,223 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * CS530x CODEC driver internal data
+ *
+ * Copyright (C) 2023-2024 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef _CS530X_H
+#define _CS530X_H
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+/* Devices */
+#define CS530X_2CH_ADC_DEV_ID 0x5302
+#define CS530X_4CH_ADC_DEV_ID 0x5304
+#define CS530X_8CH_ADC_DEV_ID 0x5308
+
+/* Registers */
+
+#define CS530X_DEVID 0x0000000
+#define CS530X_REVID 0x0000004
+#define CS530X_SW_RESET 0x0000022
+
+#define CS530X_CLK_CFG_0 0x0000040
+#define CS530X_CLK_CFG_1 0x0000042
+#define CS530X_CHIP_ENABLE 0x0000044
+#define CS530X_ASP_CFG 0x0000048
+#define CS530X_SIGNAL_PATH_CFG 0x0000050
+#define CS530X_IN_ENABLES 0x0000080
+#define CS530X_IN_RAMP_SUM 0x0000082
+#define CS530X_IN_FILTER 0x0000086
+#define CS530X_IN_HIZ 0x0000088
+#define CS530X_IN_INV 0x000008A
+#define CS530X_IN_VOL_CTRL1_0 0x0000090
+#define CS530X_IN_VOL_CTRL1_1 0x0000092
+#define CS530X_IN_VOL_CTRL2_0 0x0000094
+#define CS530X_IN_VOL_CTRL2_1 0x0000096
+#define CS530X_IN_VOL_CTRL3_0 0x0000098
+#define CS530X_IN_VOL_CTRL3_1 0x000009A
+#define CS530X_IN_VOL_CTRL4_0 0x000009C
+#define CS530X_IN_VOL_CTRL4_1 0x000009E
+#define CS530X_IN_VOL_CTRL5 0x00000A0
+
+#define CS530X_PAD_FN 0x0003D24
+#define CS530X_PAD_LVL 0x0003D28
+
+#define CS530X_MAX_REGISTER CS530X_PAD_LVL
+
+/* Register Fields */
+
+/* REVID */
+#define CS530X_MTLREVID GENMASK(3, 0)
+#define CS530X_AREVID GENMASK(7, 4)
+
+/* SW_RESET */
+#define CS530X_SW_RST_SHIFT 8
+#define CS530X_SW_RST_VAL (0x5A << CS530X_SW_RST_SHIFT)
+
+/* CLK_CFG_0 */
+#define CS530X_PLL_REFCLK_SRC_MASK BIT(0)
+#define CS530X_PLL_REFCLK_FREQ_MASK GENMASK(5, 4)
+#define CS530X_SYSCLK_SRC_MASK BIT(12)
+#define CS530X_SYSCLK_SRC_SHIFT 12
+#define CS530X_REFCLK_2P822_3P072 0
+#define CS530X_REFCLK_5P6448_6P144 0x10
+#define CS530X_REFCLK_11P2896_12P288 0x20
+#define CS530X_REFCLK_24P5792_24P576 0x30
+
+/* CLK_CFG_1 */
+#define CS530X_SAMPLE_RATE_MASK GENMASK(2, 0)
+#define CS530X_FS_32K 0
+#define CS530X_FS_48K_44P1K 1
+#define CS530X_FS_96K_88P2K 2
+#define CS530X_FS_192K_176P4K 3
+#define CS530X_FS_384K_356P8K 4
+#define CS530X_FS_768K_705P6K 5
+
+/* CHIP_ENABLE */
+#define CS530X_GLOBAL_EN BIT(0)
+
+/* ASP_CFG */
+#define CS530X_ASP_BCLK_FREQ_MASK GENMASK(1, 0)
+#define CS530X_ASP_PRIMARY BIT(5)
+#define CS530X_ASP_BCLK_INV BIT(6)
+#define CS530X_BCLK_2P822_3P072 0
+#define CS530X_BCLK_5P6448_6P144 1
+#define CS530X_BCLK_11P2896_12P288 2
+#define CS530X_BCLK_24P5792_24P576 3
+
+/* SIGNAL_PATH_CFG */
+#define CS530X_ASP_FMT_MASK GENMASK(2, 0)
+#define CS530X_ASP_TDM_SLOT_MASK GENMASK(5, 3)
+#define CS530X_ASP_TDM_SLOT_SHIFT 3
+#define CS530X_ASP_CH_REVERSE BIT(9)
+#define CS530X_TDM_EN_MASK BIT(2)
+#define CS530X_ASP_FMT_I2S 0
+#define CS530X_ASP_FMT_LJ 1
+#define CS530X_ASP_FMT_DSP_A 0x6
+
+/* TDM Slots */
+#define CS530X_0_1_TDM_SLOT_MASK GENMASK(1, 0)
+#define CS530X_0_3_TDM_SLOT_MASK GENMASK(3, 0)
+#define CS530X_0_7_TDM_SLOT_MASK GENMASK(7, 0)
+#define CS530X_0_7_TDM_SLOT_VAL 0
+
+#define CS530X_2_3_TDM_SLOT_MASK GENMASK(3, 2)
+#define CS530X_2_3_TDM_SLOT_VAL 1
+
+#define CS530X_4_5_TDM_SLOT_MASK GENMASK(5, 4)
+#define CS530X_4_7_TDM_SLOT_MASK GENMASK(7, 4)
+#define CS530X_4_7_TDM_SLOT_VAL 2
+
+#define CS530X_6_7_TDM_SLOT_MASK GENMASK(7, 6)
+#define CS530X_6_7_TDM_SLOT_VAL 3
+
+#define CS530X_8_9_TDM_SLOT_MASK GENMASK(9, 8)
+#define CS530X_8_11_TDM_SLOT_MASK GENMASK(11, 8)
+#define CS530X_8_15_TDM_SLOT_MASK GENMASK(15, 8)
+#define CS530X_8_15_TDM_SLOT_VAL 4
+
+#define CS530X_10_11_TDM_SLOT_MASK GENMASK(11, 10)
+#define CS530X_10_11_TDM_SLOT_VAL 5
+
+#define CS530X_12_13_TDM_SLOT_MASK GENMASK(13, 12)
+#define CS530X_12_15_TDM_SLOT_MASK GENMASK(15, 12)
+#define CS530X_12_15_TDM_SLOT_VAL 6
+
+#define CS530X_14_15_TDM_SLOT_MASK GENMASK(15, 14)
+#define CS530X_14_15_TDM_SLOT_VAL 7
+
+/* IN_RAMP_SUM */
+#define CS530X_RAMP_RATE_INC_SHIFT 0
+#define CS530X_RAMP_RATE_DEC_SHIFT 4
+#define CS530X_IN_SUM_MODE_SHIFT 13
+
+/* IN_FILTER */
+#define CS530X_IN_FILTER_SHIFT 8
+#define CS530X_IN_HPF_EN_SHIFT 12
+
+/* IN_HIZ */
+#define CS530X_IN12_HIZ BIT(0)
+#define CS530X_IN34_HIZ BIT(1)
+#define CS530X_IN56_HIZ BIT(2)
+#define CS530X_IN78_HIZ BIT(3)
+
+/* IN_INV */
+#define CS530X_IN1_INV_SHIFT 0
+#define CS530X_IN2_INV_SHIFT 1
+#define CS530X_IN3_INV_SHIFT 2
+#define CS530X_IN4_INV_SHIFT 3
+#define CS530X_IN5_INV_SHIFT 4
+#define CS530X_IN6_INV_SHIFT 5
+#define CS530X_IN7_INV_SHIFT 6
+#define CS530X_IN8_INV_SHIFT 7
+
+/* IN_VOL_CTLy_z */
+#define CS530X_IN_MUTE BIT(15)
+
+/* IN_VOL_CTL5 */
+#define CS530X_IN_VU BIT(0)
+
+/* PAD_FN */
+#define CS530X_DOUT2_FN BIT(0)
+#define CS530X_DOUT3_FN BIT(1)
+#define CS530X_DOUT4_FN BIT(2)
+#define CS530X_SPI_CS_FN BIT(3)
+#define CS530X_CONFIG2_FN BIT(6)
+#define CS530X_CONFIG3_FN BIT(7)
+#define CS530X_CONFIG4_FN BIT(8)
+#define CS530X_CONFIG5_FN BIT(9)
+
+/* PAD_LVL */
+#define CS530X_CONFIG2_LVL BIT(6)
+#define CS530X_CONFIG3_LVL BIT(7)
+#define CS530X_CONFIG4_LVL BIT(8)
+#define CS530X_CONFIG5_LVL BIT(9)
+
+/* System Clock Source */
+#define CS530X_SYSCLK_SRC_MCLK 0
+#define CS530X_SYSCLK_SRC_PLL 1
+
+/* PLL Reference Clock Source */
+#define CS530X_PLL_SRC_BCLK 0
+#define CS530X_PLL_SRC_MCLK 1
+
+#define CS530X_NUM_SUPPLIES 2
+
+enum cs530x_type {
+ CS5302,
+ CS5304,
+ CS5308,
+};
+
+/* codec private data */
+struct cs530x_priv {
+ struct regmap *regmap;
+ struct device *dev;
+ struct snd_soc_dai_driver *dev_dai;
+
+ enum cs530x_type devtype;
+ int num_adcs;
+ int num_dacs;
+
+ struct regulator_bulk_data supplies[CS530X_NUM_SUPPLIES];
+
+ unsigned int mclk_rate;
+
+ int tdm_width;
+ int tdm_slots;
+ int fs;
+ int adc_pairs_count;
+
+ struct gpio_desc *reset_gpio;
+};
+
+extern const struct regmap_config cs530x_regmap;
+int cs530x_probe(struct cs530x_priv *cs530x);
+
+#endif
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index c0893146423b..bcbaf28a0b2d 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -12,7 +12,6 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <sound/pcm_params.h>
@@ -901,7 +900,7 @@ static const struct snd_soc_component_driver cs53l30_driver = {
.endianness = 1,
};
-static struct regmap_config cs53l30_regmap = {
+static const struct regmap_config cs53l30_regmap = {
.reg_bits = 8,
.val_bits = 8,
diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c
index e8e22b1a1963..8cfec8dcf839 100644
--- a/sound/soc/codecs/cx2072x.c
+++ b/sound/soc/codecs/cx2072x.c
@@ -63,11 +63,6 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -7400, 100, 0);
static const DECLARE_TLV_DB_SCALE(dac_tlv, -7400, 100, 0);
static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 1200, 0);
-struct cx2072x_eq_ctrl {
- u8 ch;
- u8 band;
-};
-
static const DECLARE_TLV_DB_RANGE(hpf_tlv,
0, 0, TLV_DB_SCALE_ITEM(120, 0, 0),
1, 63, TLV_DB_SCALE_ITEM(30, 30, 0)
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index a2b328f3b39f..f3ef6fb55304 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -1720,7 +1720,7 @@ static int da7213_set_component_pll(struct snd_soc_component *component,
* SND_SOC_DAIFMT_CBC_CFC
* SND_SOC_DAIFMT_CBP_CFP
*/
-static u64 da7213_dai_formats =
+static const u64 da7213_dai_formats =
SND_SOC_POSSIBLE_DAIFMT_I2S |
SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
diff --git a/sound/soc/codecs/es8311.c b/sound/soc/codecs/es8311.c
new file mode 100644
index 000000000000..f557e33c26ad
--- /dev/null
+++ b/sound/soc/codecs/es8311.c
@@ -0,0 +1,973 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * es8311.c -- es8311 ALSA SoC audio driver
+ *
+ * Copyright (C) 2024 Matteo Martelli <matteomartelli3@gmail.com>
+ *
+ * Author: Matteo Martelli <matteomartelli3@gmail.com>
+ */
+
+#include "linux/array_size.h"
+#include "sound/pcm.h"
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "es8311.h"
+
+#define ES8311_NUM_RATES 10
+#define ES8311_RATES (SNDRV_PCM_RATE_8000_96000)
+#define ES8311_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct es8311_priv {
+ struct regmap *regmap;
+ struct clk *mclk;
+ unsigned long mclk_freq;
+ bool provider;
+ unsigned int rates[ES8311_NUM_RATES];
+ struct snd_pcm_hw_constraint_list constraints;
+};
+
+static const DECLARE_TLV_DB_SCALE(es8311_adc_vol_tlv, -9550, 50, 0);
+static const DECLARE_TLV_DB_SCALE(es8311_pga_gain_tlv, 0, 300, 0);
+static const DECLARE_TLV_DB_SCALE(es8311_adc_scale_tlv, 0, 600, 0);
+
+#define ES8311_DB_LRCK_STEPS \
+ "0.25db/4LRCK", \
+ "0.25db/8LRCK", \
+ "0.25db/16LRCK", \
+ "0.25db/32LRCK", \
+ "0.25db/64LRCK", \
+ "0.25db/128LRCK", \
+ "0.25db/256LRCK", \
+ "0.25db/512LRCK", \
+ "0.25db/1024LRCK", \
+ "0.25db/2048LRCK", \
+ "0.25db/4096LRCK", \
+ "0.25db/8192LRCK", \
+ "0.25db/16384LRCK", \
+ "0.25db/32768LRCK", \
+ "0.25db/65536LRCK",
+
+static const char *const es8311_level_winsize_txt[] = {
+ "0.25db/2LRCK",
+ ES8311_DB_LRCK_STEPS
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ es8311_alc_winsize, ES8311_ADC4,
+ ES8311_ADC4_ALC_WINSIZE_SHIFT, es8311_level_winsize_txt);
+static const DECLARE_TLV_DB_RANGE(es8311_level_tlv,
+ 0, 1, TLV_DB_SCALE_ITEM(-3010, 600, 0),
+ 2, 3, TLV_DB_SCALE_ITEM(-2060, 250, 0),
+ 4, 5, TLV_DB_SCALE_ITEM(-1610, 160, 0),
+ 6, 7, TLV_DB_SCALE_ITEM(-1320, 120, 0),
+ 8, 9, TLV_DB_SCALE_ITEM(-1100, 90, 0),
+ 10, 11, TLV_DB_SCALE_ITEM(-930, 80, 0),
+ 12, 15, TLV_DB_SCALE_ITEM(-780, 60, 0),
+);
+
+static const char *const es8311_ramprate_txt[] = {
+ "Disabled",
+ ES8311_DB_LRCK_STEPS
+};
+static SOC_ENUM_SINGLE_DECL(
+ es8311_adc_ramprate, ES8311_ADC1,
+ ES8311_ADC1_RAMPRATE_SHIFT, es8311_ramprate_txt);
+
+static const char *const es8311_automute_winsize_txt[] = {
+ "2048 samples",
+ "4096 samples",
+ "6144 samples",
+ "8192 samples",
+ "10240 samples",
+ "12288 samples",
+ "14336 samples",
+ "16384 samples",
+ "18432 samples",
+ "20480 samples",
+ "22528 samples",
+ "24576 samples",
+ "26624 samples",
+ "28672 samples",
+ "30720 samples",
+ "32768 samples",
+};
+static SOC_ENUM_SINGLE_DECL(
+ es8311_automute_winsize, ES8311_ADC6,
+ ES8311_ADC6_AUTOMUTE_WS_SHIFT, es8311_automute_winsize_txt);
+static const DECLARE_TLV_DB_RANGE(es8311_automute_ng_tlv,
+ 0, 7, TLV_DB_SCALE_ITEM(-9600, 600, 0),
+ 8, 15, TLV_DB_SCALE_ITEM(-5100, 300, 0),
+);
+static const DECLARE_TLV_DB_SCALE(es8311_automute_vol_tlv, -2800, 400, 0);
+
+static const DECLARE_TLV_DB_SCALE(es8311_dac_vol_tlv, -9550, 50, 0);
+static SOC_ENUM_SINGLE_DECL(
+ es8311_drc_winsize, ES8311_DAC4,
+ ES8311_DAC4_DRC_WINSIZE_SHIFT, es8311_level_winsize_txt);
+static SOC_ENUM_SINGLE_DECL(
+ es8311_dac_ramprate, ES8311_DAC6,
+ ES8311_DAC6_RAMPRATE_SHIFT, es8311_ramprate_txt);
+
+static const char *const es8311_out_mode_txt[] = {
+ "Lineout",
+ "Headphones"
+};
+static SOC_ENUM_SINGLE_DECL(
+ es8311_out_mode, ES8311_SYS9,
+ ES8311_SYS9_HPSW_SHIFT, es8311_out_mode_txt);
+
+static const struct snd_kcontrol_new es8311_snd_controls[] = {
+ /* Capture path */
+ SOC_SINGLE_TLV("PGA Capture Volume", ES8311_SYS10,
+ ES8311_SYS10_PGAGAIN_SHIFT, ES8311_SYS10_PGAGAIN_MAX, 0,
+ es8311_pga_gain_tlv),
+ SOC_SINGLE("ADC Polarity Invert Capture Switch", ES8311_ADC2,
+ ES8311_ADC2_INV_SHIFT, 1, 0),
+ SOC_SINGLE_TLV("ADC Scale Capture Volume", ES8311_ADC2,
+ ES8311_ADC2_SCALE_SHIFT, ES8311_ADC2_SCALE_MAX, 0,
+ es8311_adc_scale_tlv),
+ SOC_SINGLE_TLV("ADC Capture Volume", ES8311_ADC3,
+ ES8311_ADC3_VOLUME_SHIFT, ES8311_ADC3_VOLUME_MAX, 0,
+ es8311_adc_vol_tlv),
+ SOC_ENUM("ADC Capture Ramp Rate", es8311_adc_ramprate),
+ SOC_SINGLE("ADC Automute Capture Switch", ES8311_ADC4,
+ ES8311_ADC4_AUTOMUTE_EN_SHIFT, 1, 0),
+ SOC_ENUM("ADC Automute Capture Winsize", es8311_automute_winsize),
+ SOC_SINGLE_TLV("ADC Automute Noise Gate Capture Volume", ES8311_ADC6,
+ ES8311_ADC6_AUTOMUTE_NG_SHIFT,
+ ES8311_ADC6_AUTOMUTE_NG_MAX, 0, es8311_automute_ng_tlv),
+ SOC_SINGLE_TLV("ADC Automute Capture Volume", ES8311_ADC7,
+ ES8311_ADC7_AUTOMUTE_VOL_SHIFT,
+ ES8311_ADC7_AUTOMUTE_VOL_MAX, 0,
+ es8311_automute_vol_tlv),
+ SOC_SINGLE("ADC HPF Capture Switch", ES8311_ADC8, ES8311_ADC8_HPF_SHIFT,
+ 1, 0),
+ SOC_SINGLE("ADC EQ Capture Switch", ES8311_ADC8,
+ ES8311_ADC8_EQBYPASS_SHIFT, 1, 1),
+ SOC_SINGLE("ALC Capture Switch", ES8311_ADC4, ES8311_ADC4_ALC_EN_SHIFT,
+ 1, 0),
+ SOC_SINGLE_TLV("ALC Capture Max Volume", ES8311_ADC5,
+ ES8311_ADC5_ALC_MAXLEVEL_SHIFT,
+ ES8311_ADC5_ALC_MAXLEVEL_MAX, 0, es8311_level_tlv),
+ SOC_SINGLE_TLV("ALC Capture Min Volume", ES8311_ADC5,
+ ES8311_ADC5_ALC_MINLEVEL_SHIFT,
+ ES8311_ADC5_ALC_MINLEVEL_MAX, 0, es8311_level_tlv),
+ SOC_ENUM("ALC Capture Winsize", es8311_alc_winsize),
+
+ /* Playback path */
+ SOC_SINGLE_TLV("DAC Playback Volume", ES8311_DAC2, 0,
+ ES8311_DAC2_VOLUME_MAX, 0, es8311_dac_vol_tlv),
+ SOC_SINGLE("DRC Playback Switch", ES8311_DAC4, ES8311_DAC4_DRC_EN_SHIFT,
+ 1, 0),
+ SOC_SINGLE_TLV("DRC Playback Max Volume", ES8311_DAC5,
+ ES8311_DAC5_DRC_MAXLEVEL_SHIFT,
+ ES8311_DAC5_DRC_MAXLEVEL_MAX, 0, es8311_level_tlv),
+ SOC_SINGLE_TLV("DRC Playback Min Volume", ES8311_DAC5,
+ ES8311_DAC5_DRC_MINLEVEL_SHIFT,
+ ES8311_DAC5_DRC_MINLEVEL_MAX, 0, es8311_level_tlv),
+ SOC_ENUM("DRC Playback Winsize", es8311_drc_winsize),
+ SOC_ENUM("DAC Playback Ramp Rate", es8311_dac_ramprate),
+ SOC_SINGLE("DAC EQ Playback Switch", ES8311_DAC6,
+ ES8311_DAC6_EQBYPASS_SHIFT, 1, 1),
+
+ SOC_ENUM("Output Mode", es8311_out_mode),
+};
+
+static const char *const es8311_diff_src_txt[] = {
+ "Disabled",
+ "MIC1P-MIC1N",
+};
+static SOC_ENUM_SINGLE_DECL(
+ es8311_diff_src_enum, ES8311_SYS10,
+ ES8311_SYS10_LINESEL_SHIFT, es8311_diff_src_txt);
+static const struct snd_kcontrol_new es8311_diff_src_mux =
+ SOC_DAPM_ENUM("Differential Source", es8311_diff_src_enum);
+
+static const char *const es8311_dmic_src_txt[] = {
+ "Disabled",
+ "DMIC from MIC1P",
+};
+static SOC_ENUM_SINGLE_DECL(
+ es8311_dmic_src_enum, ES8311_SYS10,
+ ES8311_SYS10_DMIC_ON_SHIFT, es8311_dmic_src_txt);
+static const struct snd_kcontrol_new es8311_dmic_src_mux =
+ SOC_DAPM_ENUM("Digital Mic Source", es8311_dmic_src_enum);
+
+static const char * const es8311_aif1tx_src_txt[] = {
+ "ADC + ADC",
+ "ADC + 0",
+ "0 + ADC",
+ "0 + 0",
+ "DACL + ADC",
+ "ADC + DACR",
+ "DACL + DACR",
+};
+static SOC_ENUM_SINGLE_DECL(
+ es8311_aif1tx_src_enum, ES8311_GPIO,
+ ES8311_GPIO_ADCDAT_SEL_SHIFT, es8311_aif1tx_src_txt);
+static const struct snd_kcontrol_new es8311_aif1tx_src_mux =
+ SOC_DAPM_ENUM("AIF1TX Source", es8311_aif1tx_src_enum);
+
+static const char * const es8311_dac_src_txt[] = {
+ "Left",
+ "Right"
+};
+static SOC_ENUM_SINGLE_DECL(
+ es8311_dac_src_enum, ES8311_SDP_IN,
+ ES8311_SDP_IN_SEL_SHIFT, es8311_dac_src_txt);
+static const struct snd_kcontrol_new es8311_dac_src_mux =
+ SOC_DAPM_ENUM("Mono DAC Source", es8311_dac_src_enum);
+
+static const struct snd_soc_dapm_widget es8311_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("Bias", ES8311_SYS3, ES8311_SYS3_PDN_IBIASGEN_SHIFT,
+ 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Analog power", ES8311_SYS3,
+ ES8311_SYS3_PDN_ANA_SHIFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Vref", ES8311_SYS3, ES8311_SYS3_PDN_VREF_SHIFT, 1,
+ NULL, 0),
+
+ /* Capture path */
+ SND_SOC_DAPM_INPUT("DMIC"),
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+ &es8311_diff_src_mux),
+ SND_SOC_DAPM_SUPPLY("ADC Bias Gen", ES8311_SYS3,
+ ES8311_SYS3_PDN_ADCBIASGEN_SHIFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC Vref Gen", ES8311_SYS3,
+ ES8311_SYS3_PDN_ADCVREFGEN_SHIFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC Clock", ES8311_CLKMGR1,
+ ES8311_CLKMGR1_CLKADC_ON_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC Analog Clock", ES8311_CLKMGR1,
+ ES8311_CLKMGR1_ANACLKADC_ON_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PGA", ES8311_SYS4, ES8311_SYS4_PDN_PGA_SHIFT, 1, NULL,
+ 0),
+ SND_SOC_DAPM_ADC("Mono ADC", NULL, ES8311_SYS4,
+ ES8311_SYS4_PDN_MOD_SHIFT, 1),
+ SND_SOC_DAPM_MUX("Digital Mic Mux", SND_SOC_NOPM, 0, 0,
+ &es8311_dmic_src_mux),
+ SND_SOC_DAPM_MUX("AIF1TX Source Mux", SND_SOC_NOPM, 0, 0,
+ &es8311_aif1tx_src_mux),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, ES8311_SDP_OUT,
+ ES8311_SDP_MUTE_SHIFT, 1),
+
+ /* Playback path */
+ SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, ES8311_SDP_IN,
+ ES8311_SDP_MUTE_SHIFT, 1),
+ SND_SOC_DAPM_MUX("Mono DAC Source Mux", SND_SOC_NOPM, 0, 0,
+ &es8311_dac_src_mux),
+ SND_SOC_DAPM_DAC("Mono DAC", NULL, ES8311_SYS8,
+ ES8311_SYS8_PDN_DAC_SHIFT, 1),
+ SND_SOC_DAPM_SUPPLY("DAC Clock", ES8311_CLKMGR1,
+ ES8311_CLKMGR1_CLKDAC_ON_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC Analog Clock", ES8311_CLKMGR1,
+ ES8311_CLKMGR1_ANACLKDAC_ON_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC Vref Gen", ES8311_SYS3,
+ ES8311_SYS3_PDN_DACVREFGEN_SHIFT, 1, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("OUT"),
+};
+
+static const struct snd_soc_dapm_route es8311_dapm_routes[] = {
+ /* Capture Path */
+ { "MIC1", NULL, "Bias" },
+ { "MIC1", NULL, "Analog power" },
+ { "MIC1", NULL, "Vref" },
+ { "Differential Mux", "MIC1P-MIC1N", "MIC1" },
+ { "PGA", NULL, "Differential Mux" },
+ { "Mono ADC", NULL, "PGA" },
+ { "Mono ADC", NULL, "ADC Bias Gen" },
+ { "Mono ADC", NULL, "ADC Vref Gen" },
+ { "Mono ADC", NULL, "ADC Clock" },
+ { "Mono ADC", NULL, "ADC Analog Clock" },
+ { "Digital Mic Mux", "Disabled", "Mono ADC" },
+ { "Digital Mic Mux", "DMIC from MIC1P", "DMIC" },
+
+ { "AIF1TX Source Mux", "ADC + ADC", "Digital Mic Mux" },
+ { "AIF1TX Source Mux", "ADC + 0", "Digital Mic Mux" },
+ { "AIF1TX Source Mux", "0 + ADC", "Digital Mic Mux" },
+ { "AIF1TX Source Mux", "DACL + ADC", "Digital Mic Mux" },
+ { "AIF1TX Source Mux", "ADC + DACR", "Digital Mic Mux" },
+
+ { "AIF1TX", NULL, "AIF1TX Source Mux" },
+
+ /* Playback Path */
+ { "Mono DAC Source Mux", "Left", "AIF1RX" },
+ { "Mono DAC Source Mux", "Right", "AIF1RX" },
+ { "Mono DAC", NULL, "Mono DAC Source Mux" },
+ { "Mono DAC", NULL, "DAC Clock" },
+ { "Mono DAC", NULL, "DAC Analog Clock" },
+ { "OUT", NULL, "Mono DAC" },
+ { "OUT", NULL, "Bias" },
+ { "OUT", NULL, "Analog power" },
+ { "OUT", NULL, "Vref" },
+ { "OUT", NULL, "DAC Vref Gen" },
+};
+
+/* Bit clock divider values:
+ * from 1 to 20: the register takes the div value - 1
+ * above 20: the register takes the corresponding idx of the div value
+ * in the following table + 20
+ */
+#define ES8311_BCLK_DIV_IDX_OFFSET 20
+static const unsigned int es8311_bclk_divs[] = {
+ 22, 24, 25, 30, 32, 33, 34, 36, 44, 48, 66, 72
+};
+
+struct es8311_mclk_coeff {
+ unsigned int rate;
+ unsigned int mclk;
+ unsigned int div;
+ unsigned int mult;
+ unsigned int div_adc_dac;
+};
+
+#define ES8311_MCLK_MAX_FREQ 49200000
+
+/* Coefficients for common master clock frequencies based on clock table from
+ * documentation. Limited to have a ratio of adc (or dac) clock to lrclk equal
+ * to 256. This to keep the default adc and dac oversampling and adc scale
+ * settings. Internal mclk dividers and multipliers are dynamically adjusted to
+ * support, respectively, multiples (up to x8) and factors (/2,4,8) of listed
+ * mclks frequencies (see es8311_cmp_adj_mclk_coeff).
+ * All rates are supported when mclk/rate ratio is 32, 64, 128, 256, 384 or 512
+ * (upper limit due to max mclk freq of 49.2MHz).
+ */
+static const struct es8311_mclk_coeff es8311_mclk_coeffs[] = {
+ { 8000, 2048000, 1, 1, 1 },
+ { 8000, 6144000, 3, 1, 1 },
+ { 8000, 18432000, 3, 1, 3 },
+ { 11025, 2822400, 1, 1, 1 },
+ { 11025, 8467200, 3, 1, 1 },
+ { 16000, 4096000, 1, 1, 1 },
+ { 16000, 12288000, 3, 1, 1 },
+ { 16000, 18432000, 3, 2, 3 },
+ { 22050, 5644800, 1, 1, 1 },
+ { 22050, 16934400, 3, 1, 1 },
+ { 32000, 8192000, 1, 1, 1 },
+ { 32000, 12288000, 3, 2, 1 },
+ { 32000, 18432000, 3, 4, 3 },
+ { 44100, 11289600, 1, 1, 1 },
+ { 44100, 33868800, 3, 1, 1 },
+ { 48000, 12288000, 1, 1, 1 },
+ { 48000, 18432000, 3, 2, 1 },
+ { 64000, 8192000, 1, 2, 1 },
+ { 64000, 12288000, 3, 4, 1 },
+ { 88200, 11289600, 1, 2, 1 },
+ { 88200, 33868800, 3, 2, 1 },
+ { 96000, 12288000, 1, 2, 1 },
+ { 96000, 18432000, 3, 4, 1 },
+};
+
+/* Compare coeff with provided mclk_freq and adjust it if needed.
+ * If frequencies match, return 0 and the unaltered coeff copy into out_coeff.
+ * If mclk_freq is a valid multiple or factor of coeff mclk freq, return 0 and
+ * the adjusted coeff copy into out_coeff.
+ * Return -EINVAL otherwise.
+ */
+static int es8311_cmp_adj_mclk_coeff(unsigned int mclk_freq,
+ const struct es8311_mclk_coeff *coeff,
+ struct es8311_mclk_coeff *out_coeff)
+{
+ if (WARN_ON_ONCE(!coeff))
+ return -EINVAL;
+
+ unsigned int div = coeff->div;
+ unsigned int mult = coeff->mult;
+ bool match = false;
+
+ if (coeff->mclk == mclk_freq) {
+ match = true;
+ } else if (mclk_freq % coeff->mclk == 0) {
+ div = mclk_freq / coeff->mclk;
+ div *= coeff->div;
+ if (div <= 8)
+ match = true;
+ } else if (coeff->mclk % mclk_freq == 0) {
+ mult = coeff->mclk / mclk_freq;
+ if (mult == 2 || mult == 4 || mult == 8) {
+ mult *= coeff->mult;
+ if (mult <= 8)
+ match = true;
+ }
+ }
+ if (!match)
+ return -EINVAL;
+ if (out_coeff) {
+ *out_coeff = *coeff;
+ out_coeff->div = div;
+ out_coeff->mult = mult;
+ }
+ return 0;
+}
+
+static int es8311_get_mclk_coeff(unsigned int mclk_freq, unsigned int rate,
+ struct es8311_mclk_coeff *out_coeff)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(es8311_mclk_coeffs); i++) {
+ const struct es8311_mclk_coeff *coeff = &es8311_mclk_coeffs[i];
+
+ if (coeff->rate != rate)
+ continue;
+
+ int ret =
+ es8311_cmp_adj_mclk_coeff(mclk_freq, coeff, out_coeff);
+ if (ret == 0)
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void es8311_set_sysclk_constraints(unsigned int mclk_freq,
+ struct es8311_priv *es8311)
+{
+ unsigned int count = 0;
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(es8311_mclk_coeffs) &&
+ count < ARRAY_SIZE(es8311->rates); i++) {
+ const struct es8311_mclk_coeff *coeff = &es8311_mclk_coeffs[i];
+
+ if (count > 0 && coeff->rate == es8311->rates[count - 1])
+ continue;
+
+ int ret = es8311_cmp_adj_mclk_coeff(mclk_freq, coeff, NULL);
+ if (ret == 0)
+ es8311->rates[count++] = coeff->rate;
+ }
+ if (count) {
+ es8311->constraints.list = es8311->rates;
+ es8311->constraints.count = count;
+ }
+}
+
+static int es8311_mute(struct snd_soc_dai *dai, int mute, int direction)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ unsigned int mask = ES8311_DAC1_DAC_DSMMUTE |
+ ES8311_DAC1_DAC_DEMMUTE;
+ unsigned int val = mute ? mask : 0;
+
+ regmap_update_bits(es8311->regmap, ES8311_DAC1, mask, val);
+ }
+
+ return 0;
+}
+
+static int es8311_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+
+ if (es8311->constraints.list) {
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &es8311->constraints);
+ }
+
+ return 0;
+}
+
+static int es8311_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 es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+ unsigned int wl;
+ int par_width = params_width(params);
+
+ switch (par_width) {
+ case 16:
+ wl = ES8311_SDP_WL_16;
+ break;
+ case 18:
+ wl = ES8311_SDP_WL_18;
+ break;
+ case 20:
+ wl = ES8311_SDP_WL_20;
+ break;
+ case 24:
+ wl = ES8311_SDP_WL_24;
+ break;
+ case 32:
+ wl = ES8311_SDP_WL_32;
+ break;
+ default:
+ return -EINVAL;
+ }
+ unsigned int width = (unsigned int)par_width;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ snd_soc_component_update_bits(component, ES8311_SDP_IN,
+ ES8311_SDP_WL_MASK,
+ wl << ES8311_SDP_WL_SHIFT);
+ } else {
+ snd_soc_component_update_bits(component, ES8311_SDP_OUT,
+ ES8311_SDP_WL_MASK,
+ wl << ES8311_SDP_WL_SHIFT);
+ }
+
+ if (es8311->mclk_freq > ES8311_MCLK_MAX_FREQ) {
+ dev_err(component->dev, "mclk frequency %lu too high\n",
+ es8311->mclk_freq);
+ return -EINVAL;
+ }
+
+ unsigned int mclk_freq = es8311->mclk_freq;
+ unsigned int rate = params_rate(params);
+ unsigned int clkmgr = ES8311_CLKMGR1_MCLK_ON;
+
+ if (!mclk_freq) {
+ if (es8311->provider) {
+ dev_err(component->dev,
+ "mclk not configured, cannot run as master\n");
+ return -EINVAL;
+ }
+ dev_dbg(component->dev,
+ "mclk not configured, use bclk as internal mclk\n");
+
+ clkmgr = ES8311_CLKMGR1_MCLK_SEL;
+
+ mclk_freq = rate * width * 2;
+ }
+
+ struct es8311_mclk_coeff coeff;
+ int ret = es8311_get_mclk_coeff(mclk_freq, rate, &coeff);
+ if (ret) {
+ dev_err(component->dev, "unable to find mclk coefficient\n");
+ return ret;
+ }
+
+ unsigned int mask = ES8311_CLKMGR1_MCLK_SEL | ES8311_CLKMGR1_MCLK_ON |
+ ES8311_CLKMGR1_BCLK_ON;
+
+ clkmgr |= ES8311_CLKMGR1_BCLK_ON;
+ snd_soc_component_update_bits(component, ES8311_CLKMGR1, mask, clkmgr);
+
+ if (WARN_ON_ONCE(coeff.div == 0 || coeff.div > 8 ||
+ coeff.div_adc_dac == 0 || coeff.div_adc_dac > 8))
+ return -EINVAL;
+
+ unsigned int mult;
+
+ switch (coeff.mult) {
+ case 1:
+ mult = 0;
+ break;
+ case 2:
+ mult = 1;
+ break;
+ case 4:
+ mult = 2;
+ break;
+ case 8:
+ mult = 3;
+ break;
+ default:
+ WARN_ON_ONCE(true);
+ return -EINVAL;
+ }
+
+ mask = ES8311_CLKMGR2_DIV_PRE_MASK | ES8311_CLKMGR2_MULT_PRE_MASK;
+ clkmgr = (coeff.div - 1) << ES8311_CLKMGR2_DIV_PRE_SHIFT |
+ mult << ES8311_CLKMGR2_MULT_PRE_SHIFT;
+ snd_soc_component_update_bits(component, ES8311_CLKMGR2, mask, clkmgr);
+
+ mask = ES8311_CLKMGR5_ADC_DIV_MASK | ES8311_CLKMGR5_DAC_DIV_MASK;
+ clkmgr = (coeff.div_adc_dac - 1) << ES8311_CLKMGR5_ADC_DIV_SHIFT |
+ (coeff.div_adc_dac - 1) << ES8311_CLKMGR5_DAC_DIV_SHIFT;
+ snd_soc_component_update_bits(component, ES8311_CLKMGR5, mask, clkmgr);
+
+ if (es8311->provider) {
+ unsigned int div_lrclk = mclk_freq / rate;
+
+ if (WARN_ON_ONCE(div_lrclk == 0 ||
+ div_lrclk > ES8311_CLKMGR_LRCLK_DIV_MAX + 1))
+ return -EINVAL;
+
+ mask = ES8311_CLKMGR7_LRCLK_DIV_H_MASK;
+ clkmgr = (div_lrclk - 1) >> 8;
+ snd_soc_component_update_bits(component, ES8311_CLKMGR7, mask,
+ clkmgr);
+ clkmgr = (div_lrclk - 1) & 0xFF;
+ snd_soc_component_write(component, ES8311_CLKMGR8, clkmgr);
+
+ if (div_lrclk % (2 * width) != 0) {
+ dev_err(component->dev,
+ "unable to divide mclk %u to generate bclk\n",
+ mclk_freq);
+ return -EINVAL;
+ }
+
+ unsigned int div_bclk = div_lrclk / (2 * width);
+
+ mask = ES8311_CLKMGR6_DIV_BCLK_MASK;
+ if (div_bclk <= ES8311_BCLK_DIV_IDX_OFFSET) {
+ clkmgr = div_bclk - 1;
+ } else {
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(es8311_bclk_divs); i++) {
+ if (es8311_bclk_divs[i] == div_bclk)
+ break;
+ }
+ if (i == ARRAY_SIZE(es8311_bclk_divs)) {
+ dev_err(component->dev,
+ "bclk divider %u not supported\n",
+ div_bclk);
+ return -EINVAL;
+ }
+
+ clkmgr = i + ES8311_BCLK_DIV_IDX_OFFSET;
+ }
+ snd_soc_component_update_bits(component, ES8311_CLKMGR6, mask,
+ clkmgr);
+ }
+
+ return 0;
+}
+
+static int es8311_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+
+ if (freq > ES8311_MCLK_MAX_FREQ) {
+ dev_err(component->dev, "invalid frequency %u: too high\n",
+ freq);
+ return -EINVAL;
+ }
+
+ if (es8311->mclk_freq == freq)
+ return 0;
+
+ es8311->mclk_freq = freq;
+ es8311->constraints.list = NULL;
+ es8311->constraints.count = 0;
+
+ if (freq == 0)
+ return 0;
+
+ int ret = clk_set_rate(es8311->mclk, freq);
+ if (ret) {
+ dev_err(component->dev, "unable to set mclk rate\n");
+ return ret;
+ }
+
+ es8311_set_sysclk_constraints(freq, es8311);
+
+ return ret;
+}
+
+static int es8311_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
+ /* Master mode */
+ es8311->provider = true;
+
+ snd_soc_component_update_bits(component, ES8311_RESET,
+ ES8311_RESET_MSC,
+ ES8311_RESET_MSC);
+ break;
+ case SND_SOC_DAIFMT_CBC_CFC:
+ /* Slave mode */
+ es8311->provider = false;
+ snd_soc_component_update_bits(component, ES8311_RESET,
+ ES8311_RESET_MSC, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ unsigned int sdp = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ sdp |= ES8311_SDP_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ sdp |= ES8311_SDP_FMT_LEFT_J;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ dev_err(component->dev, "right justified mode not supported\n");
+ return -EINVAL;
+ case SND_SOC_DAIFMT_DSP_B:
+ sdp |= ES8311_SDP_LRP;
+ fallthrough;
+ case SND_SOC_DAIFMT_DSP_A:
+ sdp |= ES8311_SDP_FMT_DSP;
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ default:
+ dev_err(component->dev,
+ "inverted fsync not supported in dsp mode\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ unsigned int clkmgr = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ sdp |= ES8311_SDP_LRP;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ clkmgr |= ES8311_CLKMGR6_BCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ clkmgr |= ES8311_CLKMGR6_BCLK_INV;
+ sdp |= ES8311_SDP_LRP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ unsigned int mask = ES8311_CLKMGR6_BCLK_INV;
+
+ snd_soc_component_update_bits(component, ES8311_CLKMGR6, mask, clkmgr);
+
+ mask = ES8311_SDP_FMT_MASK | ES8311_SDP_LRP;
+ snd_soc_component_update_bits(component, ES8311_SDP_IN, mask, sdp);
+ snd_soc_component_update_bits(component, ES8311_SDP_OUT, mask, sdp);
+
+ return 0;
+}
+
+static int es8311_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ int ret = clk_prepare_enable(es8311->mclk);
+ if (ret) {
+ dev_err(component->dev,
+ "unable to prepare mclk\n");
+ return ret;
+ }
+
+ snd_soc_component_update_bits(
+ component, ES8311_SYS3,
+ ES8311_SYS3_PDN_VMIDSEL_MASK,
+ ES8311_SYS3_PDN_VMIDSEL_STARTUP_NORMAL_SPEED);
+ }
+
+ break;
+ case SND_SOC_BIAS_OFF:
+ clk_disable_unprepare(es8311->mclk);
+ snd_soc_component_update_bits(
+ component, ES8311_SYS3, ES8311_SYS3_PDN_VMIDSEL_MASK,
+ ES8311_SYS3_PDN_VMIDSEL_POWER_DOWN);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dai_ops es8311_dai_ops = {
+ .startup = es8311_startup,
+ .hw_params = es8311_hw_params,
+ .mute_stream = es8311_mute,
+ .set_sysclk = es8311_set_sysclk,
+ .set_fmt = es8311_set_dai_fmt,
+ .no_capture_mute = 1,
+};
+
+static struct snd_soc_dai_driver es8311_dai = {
+ .name = "es8311",
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ES8311_RATES,
+ .formats = ES8311_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ES8311_RATES,
+ .formats = ES8311_FORMATS,
+ },
+ .ops = &es8311_dai_ops,
+ .symmetric_rate = 1,
+};
+
+static void es8311_reset(struct snd_soc_component *component, bool reset)
+{
+ /* Reset procedure:
+ * (1) power down state machine and reset codec blocks then,
+ * (2) after a short delay, power up state machine and leave reset mode.
+ * Specific delay is not documented, using the same as es8316.
+ */
+ unsigned int mask = ES8311_RESET_CSM_ON | ES8311_RESET_RST_MASK;
+
+ if (reset) {
+ /* Enter reset mode */
+ snd_soc_component_update_bits(component, ES8311_RESET, mask,
+ ES8311_RESET_RST_MASK);
+ } else {
+ /* Leave reset mode */
+ usleep_range(5000, 5500);
+ snd_soc_component_update_bits(component, ES8311_RESET, mask,
+ ES8311_RESET_CSM_ON);
+ }
+}
+
+static int es8311_suspend(struct snd_soc_component *component)
+{
+ struct es8311_priv *es8311;
+
+ es8311 = snd_soc_component_get_drvdata(component);
+
+ es8311_reset(component, true);
+
+ regcache_cache_only(es8311->regmap, true);
+ regcache_mark_dirty(es8311->regmap);
+
+ return 0;
+}
+
+static int es8311_resume(struct snd_soc_component *component)
+{
+ struct es8311_priv *es8311;
+
+ es8311 = snd_soc_component_get_drvdata(component);
+
+ es8311_reset(component, false);
+
+ regcache_cache_only(es8311->regmap, false);
+ regcache_sync(es8311->regmap);
+
+ return 0;
+}
+
+static int es8311_component_probe(struct snd_soc_component *component)
+{
+ struct es8311_priv *es8311;
+
+ es8311 = snd_soc_component_get_drvdata(component);
+
+ es8311->mclk = devm_clk_get_optional(component->dev, "mclk");
+ if (IS_ERR(es8311->mclk)) {
+ dev_err(component->dev, "invalid mclk\n");
+ return PTR_ERR(es8311->mclk);
+ }
+
+ es8311->mclk_freq = clk_get_rate(es8311->mclk);
+ if (es8311->mclk_freq > 0 && es8311->mclk_freq < ES8311_MCLK_MAX_FREQ)
+ es8311_set_sysclk_constraints(es8311->mclk_freq, es8311);
+
+ es8311_reset(component, true);
+ es8311_reset(component, false);
+
+ /* Set minimal power up time */
+ snd_soc_component_write(component, ES8311_SYS1, 0);
+ snd_soc_component_write(component, ES8311_SYS2, 0);
+
+ return 0;
+}
+
+static const struct regmap_config es8311_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = ES8311_REG_MAX,
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static const struct snd_soc_component_driver es8311_component_driver = {
+ .probe = es8311_component_probe,
+ .suspend = es8311_suspend,
+ .resume = es8311_resume,
+ .set_bias_level = es8311_set_bias_level,
+ .controls = es8311_snd_controls,
+ .num_controls = ARRAY_SIZE(es8311_snd_controls),
+ .dapm_widgets = es8311_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(es8311_dapm_widgets),
+ .dapm_routes = es8311_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(es8311_dapm_routes),
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static int es8311_i2c_probe(struct i2c_client *i2c_client)
+{
+ struct es8311_priv *es8311;
+
+ struct device *dev = &i2c_client->dev;
+
+ es8311 = devm_kzalloc(dev, sizeof(*es8311), GFP_KERNEL);
+ if (es8311 == NULL)
+ return -ENOMEM;
+
+ es8311->regmap =
+ devm_regmap_init_i2c(i2c_client, &es8311_regmap_config);
+ if (IS_ERR(es8311->regmap))
+ return PTR_ERR(es8311->regmap);
+
+ i2c_set_clientdata(i2c_client, es8311);
+
+ return devm_snd_soc_register_component(dev, &es8311_component_driver,
+ &es8311_dai, 1);
+}
+
+static const struct i2c_device_id es8311_id[] = {
+ { "es8311" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, es8311_id);
+
+static const struct of_device_id es8311_of_match[] = {
+ {
+ .compatible = "everest,es8311",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, es8311_of_match);
+
+static struct i2c_driver es8311_i2c_driver = {
+ .driver = {
+ .name = "es8311",
+ .of_match_table = es8311_of_match,
+ },
+ .probe = es8311_i2c_probe,
+ .id_table = es8311_id,
+};
+
+module_i2c_driver(es8311_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ES8311 driver");
+MODULE_AUTHOR("Matteo Martelli <matteomartelli3@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8311.h b/sound/soc/codecs/es8311.h
new file mode 100644
index 000000000000..8a3105bb8443
--- /dev/null
+++ b/sound/soc/codecs/es8311.h
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * es8311.c -- es8311 ALSA SoC audio driver
+ *
+ * Copyright (C) 2024 Matteo Martelli <matteomartelli3@gmail.com>
+ *
+ * Author: Matteo Martelli <matteomartelli3@gmail.com>
+ */
+
+#ifndef _ES8311_H
+#define _ES8311_H
+
+#include <linux/bitops.h>
+
+#define ES8311_RESET 0x00
+#define ES8311_RESET_CSM_ON BIT(7)
+#define ES8311_RESET_MSC BIT(6)
+#define ES8311_RESET_RST_MASK GENMASK(4, 0)
+
+/* Clock Manager Registers */
+#define ES8311_CLKMGR1 0x01
+#define ES8311_CLKMGR1_MCLK_SEL BIT(7)
+#define ES8311_CLKMGR1_MCLK_ON BIT(5)
+#define ES8311_CLKMGR1_BCLK_ON BIT(4)
+#define ES8311_CLKMGR1_CLKADC_ON_SHIFT 3
+#define ES8311_CLKMGR1_CLKDAC_ON_SHIFT 2
+#define ES8311_CLKMGR1_ANACLKADC_ON_SHIFT 1
+#define ES8311_CLKMGR1_ANACLKDAC_ON_SHIFT 0
+#define ES8311_CLKMGR2 0x02
+#define ES8311_CLKMGR2_DIV_PRE_MASK GENMASK(7, 5)
+#define ES8311_CLKMGR2_DIV_PRE_SHIFT 5
+#define ES8311_CLKMGR2_DIV_PRE_MAX 0x07
+#define ES8311_CLKMGR2_MULT_PRE_MASK GENMASK(4, 3)
+#define ES8311_CLKMGR2_MULT_PRE_SHIFT 3
+#define ES8311_CLKMGR3 0x03
+#define ES8311_CLKMGR4 0x04
+#define ES8311_CLKMGR5 0x05
+#define ES8311_CLKMGR5_ADC_DIV_MASK GENMASK(7, 4)
+#define ES8311_CLKMGR5_ADC_DIV_SHIFT 4
+#define ES8311_CLKMGR5_DAC_DIV_MASK GENMASK(3, 0)
+#define ES8311_CLKMGR5_DAC_DIV_SHIFT 0
+#define ES8311_CLKMGR6 0x06
+#define ES8311_CLKMGR6_BCLK_INV BIT(5)
+#define ES8311_CLKMGR6_DIV_BCLK_MASK GENMASK(4, 0)
+#define ES8311_CLKMGR7 0x07
+#define ES8311_CLKMGR7_LRCLK_DIV_H_MASK GENMASK(3, 0)
+#define ES8311_CLKMGR8 0x08
+#define ES8311_CLKMGR_LRCLK_DIV_MAX 0x0FFF
+
+/* SDP Mode Registers */
+#define ES8311_SDP_IN 0x09
+#define ES8311_SDP_IN_SEL_SHIFT 7
+#define ES8311_SDP_OUT 0x0A
+/* Following values are the same for both SPD_IN and SDP_OUT */
+#define ES8311_SDP_MUTE_SHIFT 6
+#define ES8311_SDP_LRP BIT(5)
+#define ES8311_SDP_WL_MASK GENMASK(4, 2)
+#define ES8311_SDP_WL_SHIFT 2
+#define ES8311_SDP_WL_24 0x00
+#define ES8311_SDP_WL_20 0x01
+#define ES8311_SDP_WL_18 0x02
+#define ES8311_SDP_WL_16 0x03
+#define ES8311_SDP_WL_32 0x04
+#define ES8311_SDP_FMT_MASK GENMASK(1, 0)
+#define ES8311_SDP_FMT_I2S 0x00
+#define ES8311_SDP_FMT_LEFT_J 0x01
+#define ES8311_SDP_FMT_DSP 0x03
+
+/* System registers */
+#define ES8311_SYS1 0x0B
+#define ES8311_SYS2 0x0C
+#define ES8311_SYS3 0x0D
+#define ES8311_SYS3_PDN_ANA_SHIFT 7
+#define ES8311_SYS3_PDN_IBIASGEN_SHIFT 6
+#define ES8311_SYS3_PDN_ADCBIASGEN_SHIFT 5
+#define ES8311_SYS3_PDN_ADCVREFGEN_SHIFT 4
+#define ES8311_SYS3_PDN_DACVREFGEN_SHIFT 3
+#define ES8311_SYS3_PDN_VREF_SHIFT 2
+#define ES8311_SYS3_PDN_VMIDSEL_MASK GENMASK(1, 0)
+#define ES8311_SYS3_PDN_VMIDSEL_POWER_DOWN 0
+#define ES8311_SYS3_PDN_VMIDSEL_STARTUP_NORMAL_SPEED 1
+#define ES8311_SYS3_PDN_VMIDSEL_NORMAL_OPERATION 2
+#define ES8311_SYS3_PDN_VMIDSEL_STARTUP_FAST_SPEED 3
+#define ES8311_SYS4 0x0E
+#define ES8311_SYS4_PDN_PGA_SHIFT 6
+#define ES8311_SYS4_PDN_MOD_SHIFT 5
+#define ES8311_SYS5 0x0F
+#define ES8311_SYS6 0x10
+#define ES8311_SYS7 0x11
+#define ES8311_SYS8 0x12
+#define ES8311_SYS8_PDN_DAC_SHIFT 1
+#define ES8311_SYS9 0x13
+#define ES8311_SYS9_HPSW_SHIFT 4
+#define ES8311_SYS10 0x14
+#define ES8311_SYS10_DMIC_ON_SHIFT 6
+#define ES8311_SYS10_LINESEL_SHIFT 4
+#define ES8311_SYS10_PGAGAIN_SHIFT 0
+#define ES8311_SYS10_PGAGAIN_MAX 0x0A
+
+/* ADC Registers*/
+#define ES8311_ADC1 0x15
+#define ES8311_ADC1_RAMPRATE_SHIFT 4
+#define ES8311_ADC2 0x16
+#define ES8311_ADC2_INV_SHIFT 4
+#define ES8311_ADC2_SCALE_SHIFT 0
+#define ES8311_ADC2_SCALE_MAX 0x07
+#define ES8311_ADC3 0x17
+#define ES8311_ADC3_VOLUME_SHIFT 0
+#define ES8311_ADC3_VOLUME_MAX 0xFF
+#define ES8311_ADC4 0x18
+#define ES8311_ADC4_ALC_EN_SHIFT 7
+#define ES8311_ADC4_AUTOMUTE_EN_SHIFT 6
+#define ES8311_ADC4_ALC_WINSIZE_SHIFT 0
+#define ES8311_ADC5 0x19
+#define ES8311_ADC5_ALC_MAXLEVEL_SHIFT 4
+#define ES8311_ADC5_ALC_MAXLEVEL_MAX 0x0F
+#define ES8311_ADC5_ALC_MINLEVEL_SHIFT 0
+#define ES8311_ADC5_ALC_MINLEVEL_MAX 0x0F
+#define ES8311_ADC6 0x1A
+#define ES8311_ADC6_AUTOMUTE_WS_SHIFT 4
+#define ES8311_ADC6_AUTOMUTE_NG_SHIFT 0
+#define ES8311_ADC6_AUTOMUTE_NG_MAX 0x0F
+
+#define ES8311_ADC7 0x1B
+#define ES8311_ADC7_AUTOMUTE_VOL_SHIFT 5
+#define ES8311_ADC7_AUTOMUTE_VOL_MAX 0x07
+#define ES8311_ADC8 0x1C
+#define ES8311_ADC8_EQBYPASS_SHIFT 6
+#define ES8311_ADC8_HPF_SHIFT 5
+
+/* DAC Registers */
+#define ES8311_DAC1 0x31
+#define ES8311_DAC1_DAC_DSMMUTE BIT(6)
+#define ES8311_DAC1_DAC_DEMMUTE BIT(5)
+#define ES8311_DAC2 0x32
+#define ES8311_DAC2_VOLUME_MAX 0xFF
+#define ES8311_DAC3 0x33
+#define ES8311_DAC4 0x34
+#define ES8311_DAC4_DRC_EN_SHIFT 7
+#define ES8311_DAC4_DRC_WINSIZE_SHIFT 0
+#define ES8311_DAC5 0x35
+#define ES8311_DAC5_DRC_MAXLEVEL_SHIFT 4
+#define ES8311_DAC5_DRC_MAXLEVEL_MAX 0x0F
+#define ES8311_DAC5_DRC_MINLEVEL_SHIFT 0
+#define ES8311_DAC5_DRC_MINLEVEL_MAX 0x0F
+#define ES8311_DAC6 0x37
+#define ES8311_DAC6_RAMPRATE_SHIFT 4
+#define ES8311_DAC6_EQBYPASS_SHIFT 3
+
+/* GPIO Registers */
+#define ES8311_GPIO 0x44
+#define ES8311_GPIO_ADC2DAC_SEL_SHIFT 7
+#define ES8311_GPIO_ADCDAT_SEL_SHIFT 4
+
+/* Chip Info Registers */
+#define ES8311_CHIPID1 0xFD /* 0x83 */
+#define ES8311_CHIPID2 0xFE /* 0x11 */
+#define ES8311_CHIPVER 0xFF
+
+#define ES8311_REG_MAX 0xFF
+
+#endif
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
index 6a4e42e5e35b..b246694ebb4f 100644
--- a/sound/soc/codecs/es8326.c
+++ b/sound/soc/codecs/es8326.c
@@ -329,11 +329,29 @@ static bool es8326_volatile_register(struct device *dev, unsigned int reg)
}
}
+static bool es8326_writeable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ES8326_BIAS_SW1:
+ case ES8326_BIAS_SW2:
+ case ES8326_BIAS_SW3:
+ case ES8326_BIAS_SW4:
+ case ES8326_ADC_HPFS1:
+ case ES8326_ADC_HPFS2:
+ return false;
+ default:
+ return true;
+ }
+}
+
static const struct regmap_config es8326_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0xff,
+ .use_single_read = true,
+ .use_single_write = true,
.volatile_reg = es8326_volatile_register,
+ .writeable_reg = es8326_writeable_register,
.cache_type = REGCACHE_RBTREE,
};
@@ -877,6 +895,8 @@ static void es8326_jack_detect_handler(struct work_struct *work)
if (es8326->jack->status & SND_JACK_HEADSET) {
/* detect button */
dev_dbg(comp->dev, "button pressed\n");
+ regmap_write(es8326->regmap, ES8326_INT_SOURCE,
+ (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON));
queue_delayed_work(system_wq, &es8326->button_press_work, 10);
goto exit;
}
@@ -972,14 +992,10 @@ static int es8326_calibrate(struct snd_soc_component *component)
return 0;
}
-static int es8326_resume(struct snd_soc_component *component)
+static void es8326_init(struct snd_soc_component *component)
{
struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
- regcache_cache_only(es8326->regmap, false);
- regcache_sync(es8326->regmap);
-
- /* reset internal clock state */
regmap_write(es8326->regmap, ES8326_RESET, 0x1f);
regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E);
regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0);
@@ -1035,7 +1051,6 @@ static int es8326_resume(struct snd_soc_component *component)
es8326_enable_micbias(es8326->component);
usleep_range(50000, 70000);
regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00);
- regmap_write(es8326->regmap, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9);
regmap_write(es8326->regmap, ES8326_INTOUT_IO,
es8326->interrupt_clk);
regmap_write(es8326->regmap, ES8326_SDINOUT1_IO,
@@ -1051,11 +1066,28 @@ static int es8326_resume(struct snd_soc_component *component)
ES8326_MUTE);
regmap_write(es8326->regmap, ES8326_ADC_MUTE, 0x0f);
+ regmap_write(es8326->regmap, ES8326_CLK_DIV_LRCK, 0xff);
- es8326->jack_remove_retry = 0;
- es8326->hp = 0;
- es8326->hpl_vol = 0x03;
- es8326->hpr_vol = 0x03;
+ msleep(200);
+ regmap_write(es8326->regmap, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9);
+}
+
+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_cache_bypass(es8326->regmap, true);
+ regmap_read(es8326->regmap, ES8326_CLK_RESAMPLE, &reg);
+ regcache_cache_bypass(es8326->regmap, false);
+ /* reset internal clock state */
+ if (reg == 0x05)
+ regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON);
+ else
+ es8326_init(component);
+
+ regcache_sync(es8326->regmap);
es8326_irq(es8326->irq, es8326);
return 0;
@@ -1115,7 +1147,7 @@ static int es8326_probe(struct snd_soc_component *component)
}
dev_dbg(component->dev, "interrupt-clk %x", es8326->interrupt_clk);
- es8326_resume(component);
+ es8326_init(component);
return 0;
}
@@ -1211,6 +1243,10 @@ static int es8326_i2c_probe(struct i2c_client *i2c)
}
es8326->irq = i2c->irq;
+ es8326->jack_remove_retry = 0;
+ es8326->hp = 0;
+ es8326->hpl_vol = 0x03;
+ es8326->hpr_vol = 0x03;
INIT_DELAYED_WORK(&es8326->jack_detect_work,
es8326_jack_detect_handler);
INIT_DELAYED_WORK(&es8326->button_press_work,
diff --git a/sound/soc/codecs/framer-codec.c b/sound/soc/codecs/framer-codec.c
index e5fcde9ee308..6f57a3aeecc8 100644
--- a/sound/soc/codecs/framer-codec.c
+++ b/sound/soc/codecs/framer-codec.c
@@ -238,7 +238,7 @@ static int framer_dai_startup(struct snd_pcm_substream *substream,
return 0;
}
-static u64 framer_dai_formats[] = {
+static const u64 framer_dai_formats[] = {
SND_SOC_POSSIBLE_DAIFMT_DSP_B,
};
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index d3abb7ce2153..74caae52e127 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -715,7 +715,7 @@ static int hdmi_codec_mute(struct snd_soc_dai *dai, int mute, int direction)
* For example,
* ${LINUX}/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
*/
-static u64 hdmi_codec_formats =
+static const u64 hdmi_codec_formats =
SND_SOC_POSSIBLE_DAIFMT_NB_NF |
SND_SOC_POSSIBLE_DAIFMT_NB_IF |
SND_SOC_POSSIBLE_DAIFMT_IB_NF |
diff --git a/sound/soc/codecs/idt821034.c b/sound/soc/codecs/idt821034.c
index 2cc7b9166e69..cb7a68c799f8 100644
--- a/sound/soc/codecs/idt821034.c
+++ b/sound/soc/codecs/idt821034.c
@@ -860,7 +860,7 @@ static int idt821034_dai_startup(struct snd_pcm_substream *substream,
return 0;
}
-static u64 idt821034_dai_formats[] = {
+static const u64 idt821034_dai_formats[] = {
SND_SOC_POSSIBLE_DAIFMT_DSP_A |
SND_SOC_POSSIBLE_DAIFMT_DSP_B,
};
diff --git a/sound/soc/codecs/jz4760.c b/sound/soc/codecs/jz4760.c
index 9df58e23d360..6217e611259f 100644
--- a/sound/soc/codecs/jz4760.c
+++ b/sound/soc/codecs/jz4760.c
@@ -821,7 +821,7 @@ static const u8 jz4760_codec_reg_defaults[] = {
0x1F, 0x00, 0x00, 0x00
};
-static struct regmap_config jz4760_codec_regmap_config = {
+static const struct regmap_config jz4760_codec_regmap_config = {
.reg_bits = 7,
.val_bits = 8,
diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c
index 1d0c467ab57b..acb9eaa7ea1c 100644
--- a/sound/soc/codecs/jz4770.c
+++ b/sound/soc/codecs/jz4770.c
@@ -872,7 +872,7 @@ static const u8 jz4770_codec_reg_defaults[] = {
0x07, 0x44, 0x1F, 0x00
};
-static struct regmap_config jz4770_codec_regmap_config = {
+static const struct regmap_config jz4770_codec_regmap_config = {
.reg_bits = 7,
.val_bits = 8,
diff --git a/sound/soc/codecs/lpass-macro-common.c b/sound/soc/codecs/lpass-macro-common.c
index da1b422250b8..6e3b8d0897dd 100644
--- a/sound/soc/codecs/lpass-macro-common.c
+++ b/sound/soc/codecs/lpass-macro-common.c
@@ -11,6 +11,9 @@
#include "lpass-macro-common.h"
+static DEFINE_MUTEX(lpass_codec_mutex);
+static enum lpass_codec_version lpass_codec_version;
+
struct lpass_macro *lpass_macro_pds_init(struct device *dev)
{
struct lpass_macro *l_pds;
@@ -66,5 +69,25 @@ void lpass_macro_pds_exit(struct lpass_macro *pds)
}
EXPORT_SYMBOL_GPL(lpass_macro_pds_exit);
+void lpass_macro_set_codec_version(enum lpass_codec_version version)
+{
+ mutex_lock(&lpass_codec_mutex);
+ lpass_codec_version = version;
+ mutex_unlock(&lpass_codec_mutex);
+}
+EXPORT_SYMBOL_GPL(lpass_macro_set_codec_version);
+
+enum lpass_codec_version lpass_macro_get_codec_version(void)
+{
+ enum lpass_codec_version ver;
+
+ mutex_lock(&lpass_codec_mutex);
+ ver = lpass_codec_version;
+ mutex_unlock(&lpass_codec_mutex);
+
+ return ver;
+}
+EXPORT_SYMBOL_GPL(lpass_macro_get_codec_version);
+
MODULE_DESCRIPTION("Common macro driver");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lpass-macro-common.h b/sound/soc/codecs/lpass-macro-common.h
index d98718b3dc4b..21cb30ab706d 100644
--- a/sound/soc/codecs/lpass-macro-common.h
+++ b/sound/soc/codecs/lpass-macro-common.h
@@ -18,6 +18,19 @@ enum lpass_version {
LPASS_VER_11_0_0,
};
+enum lpass_codec_version {
+ LPASS_CODEC_VERSION_UNKNOWN,
+ LPASS_CODEC_VERSION_1_0,
+ LPASS_CODEC_VERSION_1_1,
+ LPASS_CODEC_VERSION_1_2,
+ LPASS_CODEC_VERSION_2_0,
+ LPASS_CODEC_VERSION_2_1,
+ LPASS_CODEC_VERSION_2_5,
+ LPASS_CODEC_VERSION_2_6,
+ LPASS_CODEC_VERSION_2_7,
+ LPASS_CODEC_VERSION_2_8,
+};
+
struct lpass_macro {
struct device *macro_pd;
struct device *dcodec_pd;
@@ -25,5 +38,33 @@ struct lpass_macro {
struct lpass_macro *lpass_macro_pds_init(struct device *dev);
void lpass_macro_pds_exit(struct lpass_macro *pds);
+void lpass_macro_set_codec_version(enum lpass_codec_version version);
+enum lpass_codec_version lpass_macro_get_codec_version(void);
+
+static inline void lpass_macro_pds_exit_action(void *pds)
+{
+ lpass_macro_pds_exit(pds);
+}
+
+static inline const char *lpass_macro_get_codec_version_string(int version)
+{
+ switch (version) {
+ case LPASS_CODEC_VERSION_2_0:
+ return "v2.0";
+ case LPASS_CODEC_VERSION_2_1:
+ return "v2.1";
+ case LPASS_CODEC_VERSION_2_5:
+ return "v2.5";
+ case LPASS_CODEC_VERSION_2_6:
+ return "v2.6";
+ case LPASS_CODEC_VERSION_2_7:
+ return "v2.7";
+ case LPASS_CODEC_VERSION_2_8:
+ return "v2.8";
+ default:
+ break;
+ }
+ return "NA";
+}
#endif /* __LPASS_MACRO_COMMON_H__ */
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
index f35187d69cac..ce42749660c8 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -158,7 +159,7 @@
#define CDC_RX_INTR_CTRL_LEVEL0 (0x03C0)
#define CDC_RX_INTR_CTRL_BYPASS0 (0x03C8)
#define CDC_RX_INTR_CTRL_SET0 (0x03D0)
-#define CDC_RX_RXn_RX_PATH_CTL(n) (0x0400 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CTL(rx, n) (0x0400 + rx->rxn_reg_stride * n)
#define CDC_RX_RX0_RX_PATH_CTL (0x0400)
#define CDC_RX_PATH_RESET_EN_MASK BIT(6)
#define CDC_RX_PATH_CLK_EN_MASK BIT(5)
@@ -166,45 +167,47 @@
#define CDC_RX_PATH_PGA_MUTE_MASK BIT(4)
#define CDC_RX_PATH_PGA_MUTE_ENABLE BIT(4)
#define CDC_RX_PATH_PCM_RATE_MASK GENMASK(3, 0)
-#define CDC_RX_RXn_RX_PATH_CFG0(n) (0x0404 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CFG0(rx, n) (0x0404 + rx->rxn_reg_stride * n)
#define CDC_RX_RXn_COMP_EN_MASK BIT(1)
#define CDC_RX_RX0_RX_PATH_CFG0 (0x0404)
#define CDC_RX_RXn_CLSH_EN_MASK BIT(6)
#define CDC_RX_DLY_ZN_EN_MASK BIT(3)
#define CDC_RX_DLY_ZN_ENABLE BIT(3)
#define CDC_RX_RXn_HD2_EN_MASK BIT(2)
-#define CDC_RX_RXn_RX_PATH_CFG1(n) (0x0408 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CFG1(rx, n) (0x0408 + rx->rxn_reg_stride * n)
#define CDC_RX_RXn_SIDETONE_EN_MASK BIT(4)
#define CDC_RX_RX0_RX_PATH_CFG1 (0x0408)
#define CDC_RX_RX0_HPH_L_EAR_SEL_MASK BIT(1)
-#define CDC_RX_RXn_RX_PATH_CFG2(n) (0x040C + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CFG2(rx, n) (0x040C + rx->rxn_reg_stride * n)
#define CDC_RX_RXn_HPF_CUT_FREQ_MASK GENMASK(1, 0)
#define CDC_RX_RX0_RX_PATH_CFG2 (0x040C)
-#define CDC_RX_RXn_RX_PATH_CFG3(n) (0x0410 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CFG3(rx, n) (0x0410 + rx->rxn_reg_stride * n)
#define CDC_RX_RX0_RX_PATH_CFG3 (0x0410)
#define CDC_RX_DC_COEFF_SEL_MASK GENMASK(1, 0)
#define CDC_RX_DC_COEFF_SEL_TWO 0x2
-#define CDC_RX_RXn_RX_VOL_CTL(n) (0x0414 + 0x80 * n)
+#define CDC_RX_RXn_RX_VOL_CTL(rx, n) (0x0414 + rx->rxn_reg_stride * n)
#define CDC_RX_RX0_RX_VOL_CTL (0x0414)
-#define CDC_RX_RXn_RX_PATH_MIX_CTL(n) (0x0418 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_MIX_CTL(rx, n) (0x0418 + rx->rxn_reg_stride * n)
#define CDC_RX_RXn_MIX_PCM_RATE_MASK GENMASK(3, 0)
#define CDC_RX_RXn_MIX_RESET_MASK BIT(6)
#define CDC_RX_RXn_MIX_RESET BIT(6)
#define CDC_RX_RXn_MIX_CLK_EN_MASK BIT(5)
#define CDC_RX_RX0_RX_PATH_MIX_CTL (0x0418)
#define CDC_RX_RX0_RX_PATH_MIX_CFG (0x041C)
-#define CDC_RX_RXn_RX_VOL_MIX_CTL(n) (0x0420 + 0x80 * n)
+#define CDC_RX_RXn_RX_VOL_MIX_CTL(rx, n) (0x0420 + rx->rxn_reg_stride * n)
#define CDC_RX_RX0_RX_VOL_MIX_CTL (0x0420)
#define CDC_RX_RX0_RX_PATH_SEC1 (0x0424)
#define CDC_RX_RX0_RX_PATH_SEC2 (0x0428)
#define CDC_RX_RX0_RX_PATH_SEC3 (0x042C)
+#define CDC_RX_RXn_RX_PATH_SEC3(rx, n) (0x042c + rx->rxn_reg_stride * n)
#define CDC_RX_RX0_RX_PATH_SEC4 (0x0430)
#define CDC_RX_RX0_RX_PATH_SEC7 (0x0434)
+#define CDC_RX_RXn_RX_PATH_SEC7(rx, n) (0x0434 + rx->rxn_reg_stride * n)
#define CDC_RX_DSM_OUT_DELAY_SEL_MASK GENMASK(2, 0)
#define CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE 0x2
#define CDC_RX_RX0_RX_PATH_MIX_SEC0 (0x0438)
#define CDC_RX_RX0_RX_PATH_MIX_SEC1 (0x043C)
-#define CDC_RX_RXn_RX_PATH_DSM_CTL(n) (0x0440 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_DSM_CTL(rx, n) (0x0440 + rx->rxn_reg_stride * n)
#define CDC_RX_RXn_DSM_CLK_EN_MASK BIT(0)
#define CDC_RX_RX0_RX_PATH_DSM_CTL (0x0440)
#define CDC_RX_RX0_RX_PATH_DSM_DATA1 (0x0444)
@@ -213,6 +216,7 @@
#define CDC_RX_RX0_RX_PATH_DSM_DATA4 (0x0450)
#define CDC_RX_RX0_RX_PATH_DSM_DATA5 (0x0454)
#define CDC_RX_RX0_RX_PATH_DSM_DATA6 (0x0458)
+/* RX offsets prior to 2.5 codec version */
#define CDC_RX_RX1_RX_PATH_CTL (0x0480)
#define CDC_RX_RX1_RX_PATH_CFG0 (0x0484)
#define CDC_RX_RX1_RX_PATH_CFG1 (0x0488)
@@ -259,6 +263,53 @@
#define CDC_RX_RX2_RX_PATH_MIX_SEC0 (0x0544)
#define CDC_RX_RX2_RX_PATH_MIX_SEC1 (0x0548)
#define CDC_RX_RX2_RX_PATH_DSM_CTL (0x054C)
+
+/* LPASS CODEC version 2.5 rx reg offsets */
+#define CDC_2_5_RX_RX1_RX_PATH_CTL (0x04c0)
+#define CDC_2_5_RX_RX1_RX_PATH_CFG0 (0x04c4)
+#define CDC_2_5_RX_RX1_RX_PATH_CFG1 (0x04c8)
+#define CDC_2_5_RX_RX1_RX_PATH_CFG2 (0x04cC)
+#define CDC_2_5_RX_RX1_RX_PATH_CFG3 (0x04d0)
+#define CDC_2_5_RX_RX1_RX_VOL_CTL (0x04d4)
+#define CDC_2_5_RX_RX1_RX_PATH_MIX_CTL (0x04d8)
+#define CDC_2_5_RX_RX1_RX_PATH_MIX_CFG (0x04dC)
+#define CDC_2_5_RX_RX1_RX_VOL_MIX_CTL (0x04e0)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC1 (0x04e4)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC2 (0x04e8)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC3 (0x04eC)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC4 (0x04f0)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC7 (0x04f4)
+#define CDC_2_5_RX_RX1_RX_PATH_MIX_SEC0 (0x04f8)
+#define CDC_2_5_RX_RX1_RX_PATH_MIX_SEC1 (0x04fC)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_CTL (0x0500)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA1 (0x0504)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA2 (0x0508)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA3 (0x050C)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA4 (0x0510)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA5 (0x0514)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA6 (0x0518)
+
+#define CDC_2_5_RX_RX2_RX_PATH_CTL (0x0580)
+#define CDC_2_5_RX_RX2_RX_PATH_CFG0 (0x0584)
+#define CDC_2_5_RX_RX2_RX_PATH_CFG1 (0x0588)
+#define CDC_2_5_RX_RX2_RX_PATH_CFG2 (0x058C)
+#define CDC_2_5_RX_RX2_RX_PATH_CFG3 (0x0590)
+#define CDC_2_5_RX_RX2_RX_VOL_CTL (0x0594)
+#define CDC_2_5_RX_RX2_RX_PATH_MIX_CTL (0x0598)
+#define CDC_2_5_RX_RX2_RX_PATH_MIX_CFG (0x059C)
+#define CDC_2_5_RX_RX2_RX_VOL_MIX_CTL (0x05a0)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC0 (0x05a4)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC1 (0x05a8)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC2 (0x05aC)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC3 (0x05b0)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC4 (0x05b4)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC5 (0x05b8)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC6 (0x05bC)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC7 (0x05c0)
+#define CDC_2_5_RX_RX2_RX_PATH_MIX_SEC0 (0x05c4)
+#define CDC_2_5_RX_RX2_RX_PATH_MIX_SEC1 (0x05c8)
+#define CDC_2_5_RX_RX2_RX_PATH_DSM_CTL (0x05cC)
+
#define CDC_RX_IDLE_DETECT_PATH_CTL (0x0780)
#define CDC_RX_IDLE_DETECT_CFG0 (0x0784)
#define CDC_RX_IDLE_DETECT_CFG1 (0x0788)
@@ -463,12 +514,6 @@ static const struct comp_coeff_val comp_coeff_table[HPH_MODE_MAX][COMP_MAX_COEFF
},
};
-struct rx_macro_reg_mask_val {
- u16 reg;
- u8 mask;
- u8 val;
-};
-
enum {
INTERP_HPHL,
INTERP_HPHR,
@@ -598,6 +643,8 @@ struct rx_macro {
int rx_mclk_users;
int clsh_users;
int rx_mclk_cnt;
+ enum lpass_codec_version codec_version;
+ int rxn_reg_stride;
bool is_ear_mode_on;
bool hph_pwr_mode;
bool hph_hd2_mode;
@@ -759,6 +806,8 @@ static SOC_ENUM_SINGLE_DECL(rx_int0_dem_inp_enum, CDC_RX_RX0_RX_PATH_CFG1, 0,
rx_int_dem_inp_mux_text);
static SOC_ENUM_SINGLE_DECL(rx_int1_dem_inp_enum, CDC_RX_RX1_RX_PATH_CFG1, 0,
rx_int_dem_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_2_5_int1_dem_inp_enum, CDC_2_5_RX_RX1_RX_PATH_CFG1, 0,
+ rx_int_dem_inp_mux_text);
static SOC_ENUM_SINGLE_DECL(rx_macro_rx0_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
static SOC_ENUM_SINGLE_DECL(rx_macro_rx1_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
@@ -976,49 +1025,6 @@ static const struct reg_default rx_defaults[] = {
{ CDC_RX_RX0_RX_PATH_DSM_DATA4, 0x55 },
{ CDC_RX_RX0_RX_PATH_DSM_DATA5, 0x55 },
{ CDC_RX_RX0_RX_PATH_DSM_DATA6, 0x55 },
- { CDC_RX_RX1_RX_PATH_CTL, 0x04 },
- { CDC_RX_RX1_RX_PATH_CFG0, 0x00 },
- { CDC_RX_RX1_RX_PATH_CFG1, 0x64 },
- { CDC_RX_RX1_RX_PATH_CFG2, 0x8F },
- { CDC_RX_RX1_RX_PATH_CFG3, 0x00 },
- { CDC_RX_RX1_RX_VOL_CTL, 0x00 },
- { CDC_RX_RX1_RX_PATH_MIX_CTL, 0x04 },
- { CDC_RX_RX1_RX_PATH_MIX_CFG, 0x7E },
- { CDC_RX_RX1_RX_VOL_MIX_CTL, 0x00 },
- { CDC_RX_RX1_RX_PATH_SEC1, 0x08 },
- { CDC_RX_RX1_RX_PATH_SEC2, 0x00 },
- { CDC_RX_RX1_RX_PATH_SEC3, 0x00 },
- { CDC_RX_RX1_RX_PATH_SEC4, 0x00 },
- { CDC_RX_RX1_RX_PATH_SEC7, 0x00 },
- { CDC_RX_RX1_RX_PATH_MIX_SEC0, 0x08 },
- { CDC_RX_RX1_RX_PATH_MIX_SEC1, 0x00 },
- { CDC_RX_RX1_RX_PATH_DSM_CTL, 0x08 },
- { CDC_RX_RX1_RX_PATH_DSM_DATA1, 0x00 },
- { CDC_RX_RX1_RX_PATH_DSM_DATA2, 0x00 },
- { CDC_RX_RX1_RX_PATH_DSM_DATA3, 0x00 },
- { CDC_RX_RX1_RX_PATH_DSM_DATA4, 0x55 },
- { CDC_RX_RX1_RX_PATH_DSM_DATA5, 0x55 },
- { CDC_RX_RX1_RX_PATH_DSM_DATA6, 0x55 },
- { CDC_RX_RX2_RX_PATH_CTL, 0x04 },
- { CDC_RX_RX2_RX_PATH_CFG0, 0x00 },
- { CDC_RX_RX2_RX_PATH_CFG1, 0x64 },
- { CDC_RX_RX2_RX_PATH_CFG2, 0x8F },
- { CDC_RX_RX2_RX_PATH_CFG3, 0x00 },
- { CDC_RX_RX2_RX_VOL_CTL, 0x00 },
- { CDC_RX_RX2_RX_PATH_MIX_CTL, 0x04 },
- { CDC_RX_RX2_RX_PATH_MIX_CFG, 0x7E },
- { CDC_RX_RX2_RX_VOL_MIX_CTL, 0x00 },
- { CDC_RX_RX2_RX_PATH_SEC0, 0x04 },
- { CDC_RX_RX2_RX_PATH_SEC1, 0x08 },
- { CDC_RX_RX2_RX_PATH_SEC2, 0x00 },
- { CDC_RX_RX2_RX_PATH_SEC3, 0x00 },
- { CDC_RX_RX2_RX_PATH_SEC4, 0x00 },
- { CDC_RX_RX2_RX_PATH_SEC5, 0x00 },
- { CDC_RX_RX2_RX_PATH_SEC6, 0x00 },
- { CDC_RX_RX2_RX_PATH_SEC7, 0x00 },
- { CDC_RX_RX2_RX_PATH_MIX_SEC0, 0x08 },
- { CDC_RX_RX2_RX_PATH_MIX_SEC1, 0x00 },
- { CDC_RX_RX2_RX_PATH_DSM_CTL, 0x00 },
{ CDC_RX_IDLE_DETECT_PATH_CTL, 0x00 },
{ CDC_RX_IDLE_DETECT_CFG0, 0x07 },
{ CDC_RX_IDLE_DETECT_CFG1, 0x3C },
@@ -1121,6 +1127,99 @@ static const struct reg_default rx_defaults[] = {
{ CDC_RX_DSD1_CFG2, 0x96 },
};
+static const struct reg_default rx_2_5_defaults[] = {
+ { CDC_2_5_RX_RX1_RX_PATH_CTL, 0x04 },
+ { CDC_2_5_RX_RX1_RX_PATH_CFG0, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_CFG1, 0x64 },
+ { CDC_2_5_RX_RX1_RX_PATH_CFG2, 0x8F },
+ { CDC_2_5_RX_RX1_RX_PATH_CFG3, 0x00 },
+ { CDC_2_5_RX_RX1_RX_VOL_CTL, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_MIX_CTL, 0x04 },
+ { CDC_2_5_RX_RX1_RX_PATH_MIX_CFG, 0x7E },
+ { CDC_2_5_RX_RX1_RX_VOL_MIX_CTL, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_SEC1, 0x08 },
+ { CDC_2_5_RX_RX1_RX_PATH_SEC2, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_SEC3, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_SEC4, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_SEC7, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_MIX_SEC0, 0x08 },
+ { CDC_2_5_RX_RX1_RX_PATH_MIX_SEC1, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_DSM_CTL, 0x08 },
+ { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA1, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA2, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA3, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA4, 0x55 },
+ { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA5, 0x55 },
+ { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA6, 0x55 },
+ { CDC_2_5_RX_RX2_RX_PATH_CTL, 0x04 },
+ { CDC_2_5_RX_RX2_RX_PATH_CFG0, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_CFG1, 0x64 },
+ { CDC_2_5_RX_RX2_RX_PATH_CFG2, 0x8F },
+ { CDC_2_5_RX_RX2_RX_PATH_CFG3, 0x00 },
+ { CDC_2_5_RX_RX2_RX_VOL_CTL, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_MIX_CTL, 0x04 },
+ { CDC_2_5_RX_RX2_RX_PATH_MIX_CFG, 0x7E },
+ { CDC_2_5_RX_RX2_RX_VOL_MIX_CTL, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC0, 0x04 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC1, 0x08 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC2, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC3, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC4, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC5, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC6, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC7, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_MIX_SEC0, 0x08 },
+ { CDC_2_5_RX_RX2_RX_PATH_MIX_SEC1, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_DSM_CTL, 0x00 },
+};
+
+static const struct reg_default rx_pre_2_5_defaults[] = {
+ { CDC_RX_RX1_RX_PATH_CTL, 0x04 },
+ { CDC_RX_RX1_RX_PATH_CFG0, 0x00 },
+ { CDC_RX_RX1_RX_PATH_CFG1, 0x64 },
+ { CDC_RX_RX1_RX_PATH_CFG2, 0x8F },
+ { CDC_RX_RX1_RX_PATH_CFG3, 0x00 },
+ { CDC_RX_RX1_RX_VOL_CTL, 0x00 },
+ { CDC_RX_RX1_RX_PATH_MIX_CTL, 0x04 },
+ { CDC_RX_RX1_RX_PATH_MIX_CFG, 0x7E },
+ { CDC_RX_RX1_RX_VOL_MIX_CTL, 0x00 },
+ { CDC_RX_RX1_RX_PATH_SEC1, 0x08 },
+ { CDC_RX_RX1_RX_PATH_SEC2, 0x00 },
+ { CDC_RX_RX1_RX_PATH_SEC3, 0x00 },
+ { CDC_RX_RX1_RX_PATH_SEC4, 0x00 },
+ { CDC_RX_RX1_RX_PATH_SEC7, 0x00 },
+ { CDC_RX_RX1_RX_PATH_MIX_SEC0, 0x08 },
+ { CDC_RX_RX1_RX_PATH_MIX_SEC1, 0x00 },
+ { CDC_RX_RX1_RX_PATH_DSM_CTL, 0x08 },
+ { CDC_RX_RX1_RX_PATH_DSM_DATA1, 0x00 },
+ { CDC_RX_RX1_RX_PATH_DSM_DATA2, 0x00 },
+ { CDC_RX_RX1_RX_PATH_DSM_DATA3, 0x00 },
+ { CDC_RX_RX1_RX_PATH_DSM_DATA4, 0x55 },
+ { CDC_RX_RX1_RX_PATH_DSM_DATA5, 0x55 },
+ { CDC_RX_RX1_RX_PATH_DSM_DATA6, 0x55 },
+ { CDC_RX_RX2_RX_PATH_CTL, 0x04 },
+ { CDC_RX_RX2_RX_PATH_CFG0, 0x00 },
+ { CDC_RX_RX2_RX_PATH_CFG1, 0x64 },
+ { CDC_RX_RX2_RX_PATH_CFG2, 0x8F },
+ { CDC_RX_RX2_RX_PATH_CFG3, 0x00 },
+ { CDC_RX_RX2_RX_VOL_CTL, 0x00 },
+ { CDC_RX_RX2_RX_PATH_MIX_CTL, 0x04 },
+ { CDC_RX_RX2_RX_PATH_MIX_CFG, 0x7E },
+ { CDC_RX_RX2_RX_VOL_MIX_CTL, 0x00 },
+ { CDC_RX_RX2_RX_PATH_SEC0, 0x04 },
+ { CDC_RX_RX2_RX_PATH_SEC1, 0x08 },
+ { CDC_RX_RX2_RX_PATH_SEC2, 0x00 },
+ { CDC_RX_RX2_RX_PATH_SEC3, 0x00 },
+ { CDC_RX_RX2_RX_PATH_SEC4, 0x00 },
+ { CDC_RX_RX2_RX_PATH_SEC5, 0x00 },
+ { CDC_RX_RX2_RX_PATH_SEC6, 0x00 },
+ { CDC_RX_RX2_RX_PATH_SEC7, 0x00 },
+ { CDC_RX_RX2_RX_PATH_MIX_SEC0, 0x08 },
+ { CDC_RX_RX2_RX_PATH_MIX_SEC1, 0x00 },
+ { CDC_RX_RX2_RX_PATH_DSM_CTL, 0x00 },
+
+};
+
static bool rx_is_wronly_register(struct device *dev,
unsigned int reg)
{
@@ -1175,8 +1274,114 @@ static bool rx_is_volatile_register(struct device *dev, unsigned int reg)
return false;
}
+static bool rx_pre_2_5_is_rw_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_RX_RX1_RX_PATH_CTL:
+ case CDC_RX_RX1_RX_PATH_CFG0:
+ case CDC_RX_RX1_RX_PATH_CFG1:
+ case CDC_RX_RX1_RX_PATH_CFG2:
+ case CDC_RX_RX1_RX_PATH_CFG3:
+ case CDC_RX_RX1_RX_VOL_CTL:
+ case CDC_RX_RX1_RX_PATH_MIX_CTL:
+ case CDC_RX_RX1_RX_PATH_MIX_CFG:
+ case CDC_RX_RX1_RX_VOL_MIX_CTL:
+ case CDC_RX_RX1_RX_PATH_SEC1:
+ case CDC_RX_RX1_RX_PATH_SEC2:
+ case CDC_RX_RX1_RX_PATH_SEC3:
+ case CDC_RX_RX1_RX_PATH_SEC4:
+ case CDC_RX_RX1_RX_PATH_SEC7:
+ case CDC_RX_RX1_RX_PATH_MIX_SEC0:
+ case CDC_RX_RX1_RX_PATH_MIX_SEC1:
+ case CDC_RX_RX1_RX_PATH_DSM_CTL:
+ case CDC_RX_RX1_RX_PATH_DSM_DATA1:
+ case CDC_RX_RX1_RX_PATH_DSM_DATA2:
+ case CDC_RX_RX1_RX_PATH_DSM_DATA3:
+ case CDC_RX_RX1_RX_PATH_DSM_DATA4:
+ case CDC_RX_RX1_RX_PATH_DSM_DATA5:
+ case CDC_RX_RX1_RX_PATH_DSM_DATA6:
+ case CDC_RX_RX2_RX_PATH_CTL:
+ case CDC_RX_RX2_RX_PATH_CFG0:
+ case CDC_RX_RX2_RX_PATH_CFG1:
+ case CDC_RX_RX2_RX_PATH_CFG2:
+ case CDC_RX_RX2_RX_PATH_CFG3:
+ case CDC_RX_RX2_RX_VOL_CTL:
+ case CDC_RX_RX2_RX_PATH_MIX_CTL:
+ case CDC_RX_RX2_RX_PATH_MIX_CFG:
+ case CDC_RX_RX2_RX_VOL_MIX_CTL:
+ case CDC_RX_RX2_RX_PATH_SEC0:
+ case CDC_RX_RX2_RX_PATH_SEC1:
+ case CDC_RX_RX2_RX_PATH_SEC2:
+ case CDC_RX_RX2_RX_PATH_SEC3:
+ case CDC_RX_RX2_RX_PATH_SEC4:
+ case CDC_RX_RX2_RX_PATH_SEC5:
+ case CDC_RX_RX2_RX_PATH_SEC6:
+ case CDC_RX_RX2_RX_PATH_SEC7:
+ case CDC_RX_RX2_RX_PATH_MIX_SEC0:
+ case CDC_RX_RX2_RX_PATH_MIX_SEC1:
+ case CDC_RX_RX2_RX_PATH_DSM_CTL:
+ return true;
+ }
+
+ return false;
+}
+
+static bool rx_2_5_is_rw_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_2_5_RX_RX1_RX_PATH_CTL:
+ case CDC_2_5_RX_RX1_RX_PATH_CFG0:
+ case CDC_2_5_RX_RX1_RX_PATH_CFG1:
+ case CDC_2_5_RX_RX1_RX_PATH_CFG2:
+ case CDC_2_5_RX_RX1_RX_PATH_CFG3:
+ case CDC_2_5_RX_RX1_RX_VOL_CTL:
+ case CDC_2_5_RX_RX1_RX_PATH_MIX_CTL:
+ case CDC_2_5_RX_RX1_RX_PATH_MIX_CFG:
+ case CDC_2_5_RX_RX1_RX_VOL_MIX_CTL:
+ case CDC_2_5_RX_RX1_RX_PATH_SEC1:
+ case CDC_2_5_RX_RX1_RX_PATH_SEC2:
+ case CDC_2_5_RX_RX1_RX_PATH_SEC3:
+ case CDC_2_5_RX_RX1_RX_PATH_SEC4:
+ case CDC_2_5_RX_RX1_RX_PATH_SEC7:
+ case CDC_2_5_RX_RX1_RX_PATH_MIX_SEC0:
+ case CDC_2_5_RX_RX1_RX_PATH_MIX_SEC1:
+ case CDC_2_5_RX_RX1_RX_PATH_DSM_CTL:
+ case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA1:
+ case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA2:
+ case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA3:
+ case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA4:
+ case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA5:
+ case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA6:
+ case CDC_2_5_RX_RX2_RX_PATH_CTL:
+ case CDC_2_5_RX_RX2_RX_PATH_CFG0:
+ case CDC_2_5_RX_RX2_RX_PATH_CFG1:
+ case CDC_2_5_RX_RX2_RX_PATH_CFG2:
+ case CDC_2_5_RX_RX2_RX_PATH_CFG3:
+ case CDC_2_5_RX_RX2_RX_VOL_CTL:
+ case CDC_2_5_RX_RX2_RX_PATH_MIX_CTL:
+ case CDC_2_5_RX_RX2_RX_PATH_MIX_CFG:
+ case CDC_2_5_RX_RX2_RX_VOL_MIX_CTL:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC0:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC1:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC2:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC3:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC4:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC5:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC6:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC7:
+ case CDC_2_5_RX_RX2_RX_PATH_MIX_SEC0:
+ case CDC_2_5_RX_RX2_RX_PATH_MIX_SEC1:
+ case CDC_2_5_RX_RX2_RX_PATH_DSM_CTL:
+ return true;
+ }
+
+ return false;
+}
+
static bool rx_is_rw_register(struct device *dev, unsigned int reg)
{
+ struct rx_macro *rx = dev_get_drvdata(dev);
+
switch (reg) {
case CDC_RX_TOP_TOP_CFG0:
case CDC_RX_TOP_SWR_CTRL:
@@ -1306,49 +1511,6 @@ static bool rx_is_rw_register(struct device *dev, unsigned int reg)
case CDC_RX_RX0_RX_PATH_DSM_DATA4:
case CDC_RX_RX0_RX_PATH_DSM_DATA5:
case CDC_RX_RX0_RX_PATH_DSM_DATA6:
- case CDC_RX_RX1_RX_PATH_CTL:
- case CDC_RX_RX1_RX_PATH_CFG0:
- case CDC_RX_RX1_RX_PATH_CFG1:
- case CDC_RX_RX1_RX_PATH_CFG2:
- case CDC_RX_RX1_RX_PATH_CFG3:
- case CDC_RX_RX1_RX_VOL_CTL:
- case CDC_RX_RX1_RX_PATH_MIX_CTL:
- case CDC_RX_RX1_RX_PATH_MIX_CFG:
- case CDC_RX_RX1_RX_VOL_MIX_CTL:
- case CDC_RX_RX1_RX_PATH_SEC1:
- case CDC_RX_RX1_RX_PATH_SEC2:
- case CDC_RX_RX1_RX_PATH_SEC3:
- case CDC_RX_RX1_RX_PATH_SEC4:
- case CDC_RX_RX1_RX_PATH_SEC7:
- case CDC_RX_RX1_RX_PATH_MIX_SEC0:
- case CDC_RX_RX1_RX_PATH_MIX_SEC1:
- case CDC_RX_RX1_RX_PATH_DSM_CTL:
- case CDC_RX_RX1_RX_PATH_DSM_DATA1:
- case CDC_RX_RX1_RX_PATH_DSM_DATA2:
- case CDC_RX_RX1_RX_PATH_DSM_DATA3:
- case CDC_RX_RX1_RX_PATH_DSM_DATA4:
- case CDC_RX_RX1_RX_PATH_DSM_DATA5:
- case CDC_RX_RX1_RX_PATH_DSM_DATA6:
- case CDC_RX_RX2_RX_PATH_CTL:
- case CDC_RX_RX2_RX_PATH_CFG0:
- case CDC_RX_RX2_RX_PATH_CFG1:
- case CDC_RX_RX2_RX_PATH_CFG2:
- case CDC_RX_RX2_RX_PATH_CFG3:
- case CDC_RX_RX2_RX_VOL_CTL:
- case CDC_RX_RX2_RX_PATH_MIX_CTL:
- case CDC_RX_RX2_RX_PATH_MIX_CFG:
- case CDC_RX_RX2_RX_VOL_MIX_CTL:
- case CDC_RX_RX2_RX_PATH_SEC0:
- case CDC_RX_RX2_RX_PATH_SEC1:
- case CDC_RX_RX2_RX_PATH_SEC2:
- case CDC_RX_RX2_RX_PATH_SEC3:
- case CDC_RX_RX2_RX_PATH_SEC4:
- case CDC_RX_RX2_RX_PATH_SEC5:
- case CDC_RX_RX2_RX_PATH_SEC6:
- case CDC_RX_RX2_RX_PATH_SEC7:
- case CDC_RX_RX2_RX_PATH_MIX_SEC0:
- case CDC_RX_RX2_RX_PATH_MIX_SEC1:
- case CDC_RX_RX2_RX_PATH_DSM_CTL:
case CDC_RX_IDLE_DETECT_PATH_CTL:
case CDC_RX_IDLE_DETECT_CFG0:
case CDC_RX_IDLE_DETECT_CFG1:
@@ -1435,6 +1597,22 @@ static bool rx_is_rw_register(struct device *dev, unsigned int reg)
return true;
}
+ switch (rx->codec_version) {
+ case LPASS_CODEC_VERSION_1_0:
+ case LPASS_CODEC_VERSION_1_1:
+ case LPASS_CODEC_VERSION_1_2:
+ case LPASS_CODEC_VERSION_2_0:
+ case LPASS_CODEC_VERSION_2_1:
+ return rx_pre_2_5_is_rw_register(dev, reg);
+ case LPASS_CODEC_VERSION_2_5:
+ case LPASS_CODEC_VERSION_2_6:
+ case LPASS_CODEC_VERSION_2_7:
+ case LPASS_CODEC_VERSION_2_8:
+ return rx_2_5_is_rw_register(dev, reg);
+ default:
+ break;
+ }
+
return false;
}
@@ -1491,8 +1669,6 @@ static const struct regmap_config rx_regmap_config = {
.val_bits = 32, /* 8 but with 32 bit read/write */
.reg_stride = 4,
.cache_type = REGCACHE_FLAT,
- .reg_defaults = rx_defaults,
- .num_reg_defaults = ARRAY_SIZE(rx_defaults),
.max_register = RX_MAX_OFFSET,
.writeable_reg = rx_is_writeable_register,
.volatile_reg = rx_is_volatile_register,
@@ -1504,16 +1680,17 @@ static int rx_macro_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+ struct rx_macro *rx = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned short look_ahead_dly_reg;
unsigned int val;
val = ucontrol->value.enumerated.item[0];
- if (e->reg == CDC_RX_RX0_RX_PATH_CFG1)
- look_ahead_dly_reg = CDC_RX_RX0_RX_PATH_CFG0;
- else if (e->reg == CDC_RX_RX1_RX_PATH_CFG1)
- look_ahead_dly_reg = CDC_RX_RX1_RX_PATH_CFG0;
+ if (e->reg == CDC_RX_RXn_RX_PATH_CFG1(rx, 0))
+ look_ahead_dly_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 0);
+ else if (e->reg == CDC_RX_RXn_RX_PATH_CFG1(rx, 1))
+ look_ahead_dly_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 1);
/* Set Look Ahead Delay */
if (val)
@@ -1534,6 +1711,10 @@ static const struct snd_kcontrol_new rx_int1_dem_inp_mux =
SOC_DAPM_ENUM_EXT("rx_int1_dem_inp", rx_int1_dem_inp_enum,
snd_soc_dapm_get_enum_double, rx_macro_int_dem_inp_mux_put);
+static const struct snd_kcontrol_new rx_2_5_int1_dem_inp_mux =
+ SOC_DAPM_ENUM_EXT("rx_int1_dem_inp", rx_2_5_int1_dem_inp_enum,
+ snd_soc_dapm_get_enum_double, rx_macro_int_dem_inp_mux_put);
+
static int rx_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
int rate_reg_val, u32 sample_rate)
{
@@ -1567,7 +1748,7 @@ static int rx_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
(inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
(inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) {
- int_fs_reg = CDC_RX_RXn_RX_PATH_CTL(j);
+ int_fs_reg = CDC_RX_RXn_RX_PATH_CTL(rx, j);
/* sample_rate is in Hz */
snd_soc_component_update_bits(component, int_fs_reg,
CDC_RX_PATH_PCM_RATE_MASK,
@@ -1600,7 +1781,7 @@ static int rx_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai,
CDC_RX_INTX_2_SEL_MASK);
if (int_mux_cfg1_val == int_2_inp + INTn_2_INP_SEL_RX0) {
- int_fs_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(j);
+ int_fs_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(rx, j);
snd_soc_component_update_bits(component, int_fs_reg,
CDC_RX_RXn_MIX_PCM_RATE_MASK,
rate_reg_val);
@@ -1654,7 +1835,7 @@ static int rx_macro_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int rx_macro_get_channel_map(struct snd_soc_dai *dai,
+static int rx_macro_get_channel_map(const struct snd_soc_dai *dai,
unsigned int *tx_num, unsigned int *tx_slot,
unsigned int *rx_num, unsigned int *rx_slot)
{
@@ -1719,6 +1900,7 @@ static int rx_macro_get_channel_map(struct snd_soc_dai *dai,
static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
{
struct snd_soc_component *component = dai->component;
+ struct rx_macro *rx = snd_soc_component_get_drvdata(component);
uint16_t j, reg, mix_reg, dsm_reg;
u16 int_mux_cfg0, int_mux_cfg1;
u8 int_mux_cfg0_val, int_mux_cfg1_val;
@@ -1729,9 +1911,9 @@ static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
case RX_MACRO_AIF3_PB:
case RX_MACRO_AIF4_PB:
for (j = 0; j < INTERP_MAX; j++) {
- reg = CDC_RX_RXn_RX_PATH_CTL(j);
- mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(j);
- dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(j);
+ reg = CDC_RX_RXn_RX_PATH_CTL(rx, j);
+ mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(rx, j);
+ dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, j);
if (mute) {
snd_soc_component_update_bits(component, reg,
@@ -1748,7 +1930,7 @@ static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
}
if (j == INTERP_AUX)
- dsm_reg = CDC_RX_RX2_RX_PATH_DSM_CTL;
+ dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, 2);
int_mux_cfg0 = CDC_RX_INP_MUX_RX_INT0_CFG0 + j * 8;
int_mux_cfg1 = int_mux_cfg0 + 4;
@@ -1956,10 +2138,11 @@ static int rx_macro_enable_main_path(struct snd_soc_dapm_widget *w,
int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rx_macro *rx = snd_soc_component_get_drvdata(component);
u16 gain_reg, reg;
- reg = CDC_RX_RXn_RX_PATH_CTL(w->shift);
- gain_reg = CDC_RX_RXn_RX_VOL_CTL(w->shift);
+ reg = CDC_RX_RXn_RX_PATH_CTL(rx, w->shift);
+ gain_reg = CDC_RX_RXn_RX_VOL_CTL(rx, w->shift);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1991,7 +2174,7 @@ static int rx_macro_config_compander(struct snd_soc_component *component,
if (comp == INTERP_AUX)
return 0;
- pcm_rate = snd_soc_component_read(component, CDC_RX_RXn_RX_PATH_CTL(comp)) & 0x0F;
+ pcm_rate = snd_soc_component_read(component, CDC_RX_RXn_RX_PATH_CTL(rx, comp)) & 0x0F;
if (pcm_rate < 0x06)
val = 0x03;
else if (pcm_rate < 0x08)
@@ -2002,11 +2185,11 @@ static int rx_macro_config_compander(struct snd_soc_component *component,
val = 0x00;
if (SND_SOC_DAPM_EVENT_ON(event))
- snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(comp),
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, comp),
CDC_RX_DC_COEFF_SEL_MASK, val);
if (SND_SOC_DAPM_EVENT_OFF(event))
- snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(comp),
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, comp),
CDC_RX_DC_COEFF_SEL_MASK, 0x3);
if (!rx->comp_enabled[comp])
return 0;
@@ -2019,14 +2202,14 @@ static int rx_macro_config_compander(struct snd_soc_component *component,
CDC_RX_COMPANDERn_SOFT_RST_MASK, 0x1);
snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
CDC_RX_COMPANDERn_SOFT_RST_MASK, 0x0);
- snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(comp),
+ snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(rx, comp),
CDC_RX_RXn_COMP_EN_MASK, 0x1);
}
if (SND_SOC_DAPM_EVENT_OFF(event)) {
snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
CDC_RX_COMPANDERn_HALT_MASK, 0x1);
- snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(comp),
+ snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(rx, comp),
CDC_RX_RXn_COMP_EN_MASK, 0x0);
snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
CDC_RX_COMPANDERn_CLK_EN_MASK, 0x0);
@@ -2125,13 +2308,13 @@ static int rx_macro_config_aux_hpf(struct snd_soc_component *component,
/* Update Aux HPF control */
if (!rx->is_aux_hpf_on)
snd_soc_component_update_bits(component,
- CDC_RX_RX2_RX_PATH_CFG1, 0x04, 0x00);
+ CDC_RX_RXn_RX_PATH_CFG1(rx, 2), 0x04, 0x00);
}
if (SND_SOC_DAPM_EVENT_OFF(event)) {
/* Reset to default (HPF=ON) */
snd_soc_component_update_bits(component,
- CDC_RX_RX2_RX_PATH_CFG1, 0x04, 0x04);
+ CDC_RX_RXn_RX_PATH_CFG1(rx, 2), 0x04, 0x04);
}
return 0;
@@ -2183,7 +2366,7 @@ static int rx_macro_config_classh(struct snd_soc_component *component,
CDC_RX_CLSH_DECAY_CTRL,
CDC_RX_CLSH_DECAY_RATE_MASK, 0x0);
snd_soc_component_write_field(component,
- CDC_RX_RX0_RX_PATH_CFG0,
+ CDC_RX_RXn_RX_PATH_CFG0(rx, 0),
CDC_RX_RXn_CLSH_EN_MASK, 0x1);
break;
case INTERP_HPHR:
@@ -2199,15 +2382,15 @@ static int rx_macro_config_classh(struct snd_soc_component *component,
CDC_RX_CLSH_DECAY_CTRL,
CDC_RX_CLSH_DECAY_RATE_MASK, 0x0);
snd_soc_component_write_field(component,
- CDC_RX_RX1_RX_PATH_CFG0,
+ CDC_RX_RXn_RX_PATH_CFG0(rx, 1),
CDC_RX_RXn_CLSH_EN_MASK, 0x1);
break;
case INTERP_AUX:
snd_soc_component_update_bits(component,
- CDC_RX_RX2_RX_PATH_CFG0,
+ CDC_RX_RXn_RX_PATH_CFG0(rx, 2),
CDC_RX_RX2_DLY_Z_EN_MASK, 1);
snd_soc_component_write_field(component,
- CDC_RX_RX2_RX_PATH_CFG0,
+ CDC_RX_RXn_RX_PATH_CFG0(rx, 2),
CDC_RX_RX2_CLSH_EN_MASK, 1);
break;
}
@@ -2218,16 +2401,17 @@ static int rx_macro_config_classh(struct snd_soc_component *component,
static void rx_macro_hd2_control(struct snd_soc_component *component,
u16 interp_idx, int event)
{
+ struct rx_macro *rx = snd_soc_component_get_drvdata(component);
u16 hd2_scale_reg, hd2_enable_reg;
switch (interp_idx) {
case INTERP_HPHL:
- hd2_scale_reg = CDC_RX_RX0_RX_PATH_SEC3;
- hd2_enable_reg = CDC_RX_RX0_RX_PATH_CFG0;
+ hd2_scale_reg = CDC_RX_RXn_RX_PATH_SEC3(rx, 0);
+ hd2_enable_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 0);
break;
case INTERP_HPHR:
- hd2_scale_reg = CDC_RX_RX1_RX_PATH_SEC3;
- hd2_enable_reg = CDC_RX_RX1_RX_PATH_CFG0;
+ hd2_scale_reg = CDC_RX_RXn_RX_PATH_SEC3(rx, 1);
+ hd2_enable_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 1);
break;
}
@@ -2482,7 +2666,7 @@ static int rx_macro_hphdelay_lutbypass(struct snd_soc_component *component,
if (interp_idx == INTERP_HPHL) {
if (rx->is_ear_mode_on)
snd_soc_component_write_field(component,
- CDC_RX_RX0_RX_PATH_CFG1,
+ CDC_RX_RXn_RX_PATH_CFG1(rx, 0),
CDC_RX_RX0_HPH_L_EAR_SEL_MASK, 0x1);
else
snd_soc_component_write_field(component,
@@ -2499,7 +2683,7 @@ static int rx_macro_hphdelay_lutbypass(struct snd_soc_component *component,
if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
snd_soc_component_write_field(component,
- CDC_RX_RX0_RX_PATH_CFG1,
+ CDC_RX_RXn_RX_PATH_CFG1(rx, 0),
CDC_RX_RX0_HPH_L_EAR_SEL_MASK, 0x0);
snd_soc_component_update_bits(component, hph_lut_bypass_reg,
CDC_RX_TOP_HPH_LUT_BYPASS_MASK, 0);
@@ -2516,11 +2700,12 @@ static int rx_macro_enable_interp_clk(struct snd_soc_component *component,
u16 main_reg, dsm_reg, rx_cfg2_reg;
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
- main_reg = CDC_RX_RXn_RX_PATH_CTL(interp_idx);
- dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(interp_idx);
+ main_reg = CDC_RX_RXn_RX_PATH_CTL(rx, interp_idx);
+ dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, interp_idx);
if (interp_idx == INTERP_AUX)
- dsm_reg = CDC_RX_RX2_RX_PATH_DSM_CTL;
- rx_cfg2_reg = CDC_RX_RXn_RX_PATH_CFG2(interp_idx);
+ dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, 2);
+
+ rx_cfg2_reg = CDC_RX_RXn_RX_PATH_CFG2(rx, interp_idx);
if (SND_SOC_DAPM_EVENT_ON(event)) {
if (rx->main_clk_users[interp_idx] == 0) {
@@ -2587,10 +2772,11 @@ static int rx_macro_enable_mix_path(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 rx_macro *rx = snd_soc_component_get_drvdata(component);
u16 gain_reg, mix_reg;
- gain_reg = CDC_RX_RXn_RX_VOL_MIX_CTL(w->shift);
- mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(w->shift);
+ gain_reg = CDC_RX_RXn_RX_VOL_MIX_CTL(rx, w->shift);
+ mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(rx, w->shift);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -2621,17 +2807,18 @@ static int rx_macro_enable_rx_path_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 rx_macro *rx = snd_soc_component_get_drvdata(component);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
rx_macro_enable_interp_clk(component, event, w->shift);
- snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(w->shift),
+ snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(rx, w->shift),
CDC_RX_RXn_SIDETONE_EN_MASK, 1);
- snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CTL(w->shift),
+ snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CTL(rx, w->shift),
CDC_RX_PATH_CLK_EN_MASK, 1);
break;
case SND_SOC_DAPM_POST_PMD:
- snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(w->shift),
+ snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(rx, w->shift),
CDC_RX_RXn_SIDETONE_EN_MASK, 0);
rx_macro_enable_interp_clk(component, event, w->shift);
break;
@@ -2801,20 +2988,34 @@ static int rx_macro_iir_filter_info(struct snd_kcontrol *kcontrol,
return 0;
}
-static const struct snd_kcontrol_new rx_macro_snd_controls[] = {
- SOC_SINGLE_S8_TLV("RX_RX0 Digital Volume", CDC_RX_RX0_RX_VOL_CTL,
- -84, 40, digital_gain),
+static const struct snd_kcontrol_new rx_macro_def_snd_controls[] = {
SOC_SINGLE_S8_TLV("RX_RX1 Digital Volume", CDC_RX_RX1_RX_VOL_CTL,
-84, 40, digital_gain),
SOC_SINGLE_S8_TLV("RX_RX2 Digital Volume", CDC_RX_RX2_RX_VOL_CTL,
-84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("RX_RX0 Mix Digital Volume", CDC_RX_RX0_RX_VOL_MIX_CTL,
- -84, 40, digital_gain),
SOC_SINGLE_S8_TLV("RX_RX1 Mix Digital Volume", CDC_RX_RX1_RX_VOL_MIX_CTL,
-84, 40, digital_gain),
SOC_SINGLE_S8_TLV("RX_RX2 Mix Digital Volume", CDC_RX_RX2_RX_VOL_MIX_CTL,
-84, 40, digital_gain),
+};
+
+static const struct snd_kcontrol_new rx_macro_2_5_snd_controls[] = {
+
+ SOC_SINGLE_S8_TLV("RX_RX1 Digital Volume", CDC_2_5_RX_RX1_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX_RX2 Digital Volume", CDC_2_5_RX_RX2_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX_RX1 Mix Digital Volume", CDC_2_5_RX_RX1_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX_RX2 Mix Digital Volume", CDC_2_5_RX_RX2_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+};
+static const struct snd_kcontrol_new rx_macro_snd_controls[] = {
+ SOC_SINGLE_S8_TLV("RX_RX0 Digital Volume", CDC_RX_RX0_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX_RX0 Mix Digital Volume", CDC_RX_RX0_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
SOC_SINGLE_EXT("RX_COMP1 Switch", SND_SOC_NOPM, RX_MACRO_COMP1, 1, 0,
rx_macro_get_compander, rx_macro_set_compander),
SOC_SINGLE_EXT("RX_COMP2 Switch", SND_SOC_NOPM, RX_MACRO_COMP2, 1, 0,
@@ -2932,6 +3133,16 @@ static int rx_macro_enable_echo(struct snd_soc_dapm_widget *w,
return 0;
}
+static const struct snd_soc_dapm_widget rx_macro_2_5_dapm_widgets[] = {
+ SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0,
+ &rx_2_5_int1_dem_inp_mux),
+};
+
+static const struct snd_soc_dapm_widget rx_macro_def_dapm_widgets[] = {
+ SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0,
+ &rx_int1_dem_inp_mux),
+};
+
static const struct snd_soc_dapm_widget rx_macro_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("RX AIF1 PB", "RX_MACRO_AIF1 Playback", 0,
SND_SOC_NOPM, 0, 0),
@@ -3003,8 +3214,6 @@ static const struct snd_soc_dapm_widget rx_macro_dapm_widgets[] = {
SND_SOC_DAPM_MUX("RX INT0 DEM MUX", SND_SOC_NOPM, 0, 0,
&rx_int0_dem_inp_mux),
- SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0,
- &rx_int1_dem_inp_mux),
SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", SND_SOC_NOPM, INTERP_HPHL, 0,
&rx_int0_2_mux, rx_macro_enable_mix_path,
@@ -3399,32 +3608,65 @@ static const struct snd_soc_dapm_route rx_audio_map[] = {
static int rx_macro_component_probe(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+ const struct snd_soc_dapm_widget *widgets;
+ const struct snd_kcontrol_new *controls;
+ unsigned int num_controls, num_widgets;
+ int ret;
snd_soc_component_init_regmap(component, rx->regmap);
- snd_soc_component_update_bits(component, CDC_RX_RX0_RX_PATH_SEC7,
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_SEC7(rx, 0),
CDC_RX_DSM_OUT_DELAY_SEL_MASK,
CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE);
- snd_soc_component_update_bits(component, CDC_RX_RX1_RX_PATH_SEC7,
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_SEC7(rx, 1),
CDC_RX_DSM_OUT_DELAY_SEL_MASK,
CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE);
- snd_soc_component_update_bits(component, CDC_RX_RX2_RX_PATH_SEC7,
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_SEC7(rx, 2),
CDC_RX_DSM_OUT_DELAY_SEL_MASK,
CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE);
- snd_soc_component_update_bits(component, CDC_RX_RX0_RX_PATH_CFG3,
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, 0),
CDC_RX_DC_COEFF_SEL_MASK,
CDC_RX_DC_COEFF_SEL_TWO);
- snd_soc_component_update_bits(component, CDC_RX_RX1_RX_PATH_CFG3,
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, 1),
CDC_RX_DC_COEFF_SEL_MASK,
CDC_RX_DC_COEFF_SEL_TWO);
- snd_soc_component_update_bits(component, CDC_RX_RX2_RX_PATH_CFG3,
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, 2),
CDC_RX_DC_COEFF_SEL_MASK,
CDC_RX_DC_COEFF_SEL_TWO);
+ switch (rx->codec_version) {
+ case LPASS_CODEC_VERSION_1_0:
+ case LPASS_CODEC_VERSION_1_1:
+ case LPASS_CODEC_VERSION_1_2:
+ case LPASS_CODEC_VERSION_2_0:
+ case LPASS_CODEC_VERSION_2_1:
+ controls = rx_macro_def_snd_controls;
+ num_controls = ARRAY_SIZE(rx_macro_def_snd_controls);
+ widgets = rx_macro_def_dapm_widgets;
+ num_widgets = ARRAY_SIZE(rx_macro_def_dapm_widgets);
+ break;
+ case LPASS_CODEC_VERSION_2_5:
+ case LPASS_CODEC_VERSION_2_6:
+ case LPASS_CODEC_VERSION_2_7:
+ case LPASS_CODEC_VERSION_2_8:
+ controls = rx_macro_2_5_snd_controls;
+ num_controls = ARRAY_SIZE(rx_macro_2_5_snd_controls);
+ widgets = rx_macro_2_5_dapm_widgets;
+ num_widgets = ARRAY_SIZE(rx_macro_2_5_dapm_widgets);
+ break;
+ default:
+ return -EINVAL;
+ }
+
rx->component = component;
- return 0;
+ ret = snd_soc_add_component_controls(component, controls, num_controls);
+ if (ret)
+ return ret;
+
+ return snd_soc_dapm_new_controls(dapm, widgets, num_widgets);
}
static int swclk_gate_enable(struct clk_hw *hw)
@@ -3527,7 +3769,7 @@ static int rx_macro_probe(struct platform_device *pdev)
kernel_ulong_t flags;
struct rx_macro *rx;
void __iomem *base;
- int ret;
+ int ret, def_count;
flags = (kernel_ulong_t)device_get_match_data(dev);
@@ -3561,17 +3803,62 @@ static int rx_macro_probe(struct platform_device *pdev)
if (IS_ERR(rx->pds))
return PTR_ERR(rx->pds);
+ ret = devm_add_action_or_reset(dev, lpass_macro_pds_exit_action, rx->pds);
+ if (ret)
+ return ret;
+
base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base)) {
- ret = PTR_ERR(base);
- goto err;
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ rx->codec_version = lpass_macro_get_codec_version();
+ struct reg_default *reg_defaults __free(kfree) = NULL;
+
+ switch (rx->codec_version) {
+ case LPASS_CODEC_VERSION_1_0:
+ case LPASS_CODEC_VERSION_1_1:
+ case LPASS_CODEC_VERSION_1_2:
+ case LPASS_CODEC_VERSION_2_0:
+ case LPASS_CODEC_VERSION_2_1:
+ rx->rxn_reg_stride = 0x80;
+ def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_pre_2_5_defaults);
+ reg_defaults = kmalloc_array(def_count, sizeof(struct reg_default), GFP_KERNEL);
+ if (!reg_defaults)
+ return -ENOMEM;
+ memcpy(&reg_defaults[0], rx_defaults, sizeof(rx_defaults));
+ memcpy(&reg_defaults[ARRAY_SIZE(rx_defaults)],
+ rx_pre_2_5_defaults, sizeof(rx_pre_2_5_defaults));
+ break;
+ case LPASS_CODEC_VERSION_2_5:
+ case LPASS_CODEC_VERSION_2_6:
+ case LPASS_CODEC_VERSION_2_7:
+ case LPASS_CODEC_VERSION_2_8:
+ rx->rxn_reg_stride = 0xc0;
+ def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_2_5_defaults);
+ reg_defaults = kmalloc_array(def_count, sizeof(struct reg_default), GFP_KERNEL);
+ if (!reg_defaults)
+ return -ENOMEM;
+ memcpy(&reg_defaults[0], rx_defaults, sizeof(rx_defaults));
+ memcpy(&reg_defaults[ARRAY_SIZE(rx_defaults)],
+ rx_2_5_defaults, sizeof(rx_2_5_defaults));
+ break;
+ default:
+ dev_err(dev, "Unsupported Codec version (%d)\n", rx->codec_version);
+ return -EINVAL;
}
- rx->regmap = devm_regmap_init_mmio(dev, base, &rx_regmap_config);
- if (IS_ERR(rx->regmap)) {
- ret = PTR_ERR(rx->regmap);
- goto err;
- }
+ struct regmap_config *reg_config __free(kfree) = kmemdup(&rx_regmap_config,
+ sizeof(*reg_config),
+ GFP_KERNEL);
+ if (!reg_config)
+ return -ENOMEM;
+
+ reg_config->reg_defaults = reg_defaults;
+ reg_config->num_reg_defaults = def_count;
+
+ rx->regmap = devm_regmap_init_mmio(dev, base, reg_config);
+ if (IS_ERR(rx->regmap))
+ return PTR_ERR(rx->regmap);
dev_set_drvdata(dev, rx);
@@ -3583,7 +3870,7 @@ static int rx_macro_probe(struct platform_device *pdev)
ret = clk_prepare_enable(rx->macro);
if (ret)
- goto err;
+ return ret;
ret = clk_prepare_enable(rx->dcodec);
if (ret)
@@ -3641,8 +3928,6 @@ err_mclk:
clk_disable_unprepare(rx->dcodec);
err_dcodec:
clk_disable_unprepare(rx->macro);
-err:
- lpass_macro_pds_exit(rx->pds);
return ret;
}
@@ -3656,8 +3941,6 @@ static void rx_macro_remove(struct platform_device *pdev)
clk_disable_unprepare(rx->fsgen);
clk_disable_unprepare(rx->macro);
clk_disable_unprepare(rx->dcodec);
-
- lpass_macro_pds_exit(rx->pds);
}
static const struct of_device_id rx_macro_dt_match[] = {
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
index c98b0b747a92..209c12ec16dd 100644
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -1167,7 +1167,7 @@ static int tx_macro_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int tx_macro_get_channel_map(struct snd_soc_dai *dai,
+static int tx_macro_get_channel_map(const struct snd_soc_dai *dai,
unsigned int *tx_num, unsigned int *tx_slot,
unsigned int *rx_num, unsigned int *rx_slot)
{
diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c
index 6eceeff10bf6..b852cc7ffad9 100644
--- a/sound/soc/codecs/lpass-va-macro.c
+++ b/sound/soc/codecs/lpass-va-macro.c
@@ -892,7 +892,7 @@ static int va_macro_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int va_macro_get_channel_map(struct snd_soc_dai *dai,
+static int va_macro_get_channel_map(const struct snd_soc_dai *dai,
unsigned int *tx_num, unsigned int *tx_slot,
unsigned int *rx_num, unsigned int *rx_slot)
{
@@ -1461,6 +1461,33 @@ undefined_rate:
return dmic_sample_rate;
}
+static void va_macro_set_lpass_codec_version(struct va_macro *va)
+{
+ int core_id_0 = 0, core_id_1 = 0, core_id_2 = 0;
+ int version = LPASS_CODEC_VERSION_UNKNOWN;
+
+ regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_0, &core_id_0);
+ regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_1, &core_id_1);
+ regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_2, &core_id_2);
+
+ if ((core_id_0 == 0x01) && (core_id_1 == 0x0F))
+ version = LPASS_CODEC_VERSION_2_0;
+ if ((core_id_0 == 0x02) && (core_id_1 == 0x0E))
+ version = LPASS_CODEC_VERSION_2_1;
+ if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x50 || core_id_2 == 0x51))
+ version = LPASS_CODEC_VERSION_2_5;
+ if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x60 || core_id_2 == 0x61))
+ version = LPASS_CODEC_VERSION_2_6;
+ if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x70 || core_id_2 == 0x71))
+ version = LPASS_CODEC_VERSION_2_7;
+ if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x80 || core_id_2 == 0x81))
+ version = LPASS_CODEC_VERSION_2_8;
+
+ lpass_macro_set_codec_version(version);
+
+ dev_dbg(va->dev, "LPASS Codec Version %s\n", lpass_macro_get_codec_version_string(version));
+}
+
static int va_macro_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1554,6 +1581,8 @@ static int va_macro_probe(struct platform_device *pdev)
goto err_npl;
}
+ va_macro_set_lpass_codec_version(va);
+
if (va->has_swr_master) {
/* Set default CLK div to 1 */
regmap_update_bits(va->regmap, CDC_VA_TOP_CSR_SWR_MIC_CTL0,
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index 6ce309980cd1..73a588289408 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -44,11 +45,7 @@
#define CDC_WSA_TOP_I2S_CLK (0x00A4)
#define CDC_WSA_TOP_I2S_RESET (0x00A8)
#define CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 (0x0100)
-#define CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK GENMASK(2, 0)
-#define CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK GENMASK(5, 3)
#define CDC_WSA_RX_INP_MUX_RX_INT0_CFG1 (0x0104)
-#define CDC_WSA_RX_INTX_2_SEL_MASK GENMASK(2, 0)
-#define CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK GENMASK(5, 3)
#define CDC_WSA_RX_INP_MUX_RX_INT1_CFG0 (0x0108)
#define CDC_WSA_RX_INP_MUX_RX_INT1_CFG1 (0x010C)
#define CDC_WSA_RX_INP_MUX_RX_MIX_CFG0 (0x0110)
@@ -173,22 +170,7 @@
#define CDC_WSA_COMPANDER0_CTL5 (0x0594)
#define CDC_WSA_COMPANDER0_CTL6 (0x0598)
#define CDC_WSA_COMPANDER0_CTL7 (0x059C)
-#define CDC_WSA_COMPANDER1_CTL0 (0x05C0)
-#define CDC_WSA_COMPANDER1_CTL1 (0x05C4)
-#define CDC_WSA_COMPANDER1_CTL2 (0x05C8)
-#define CDC_WSA_COMPANDER1_CTL3 (0x05CC)
-#define CDC_WSA_COMPANDER1_CTL4 (0x05D0)
-#define CDC_WSA_COMPANDER1_CTL5 (0x05D4)
-#define CDC_WSA_COMPANDER1_CTL6 (0x05D8)
-#define CDC_WSA_COMPANDER1_CTL7 (0x05DC)
-#define CDC_WSA_SOFTCLIP0_CRC (0x0600)
-#define CDC_WSA_SOFTCLIP_CLK_EN_MASK BIT(0)
-#define CDC_WSA_SOFTCLIP_CLK_ENABLE BIT(0)
-#define CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL (0x0604)
-#define CDC_WSA_SOFTCLIP_EN_MASK BIT(0)
-#define CDC_WSA_SOFTCLIP_ENABLE BIT(0)
-#define CDC_WSA_SOFTCLIP1_CRC (0x0640)
-#define CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL (0x0644)
+/* CDC_WSA_COMPANDER1_CTLx and CDC_WSA_SOFTCLIPx differ per LPASS codec versions */
#define CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL (0x0680)
#define CDC_WSA_EC_HQ_EC_CLK_EN_MASK BIT(0)
#define CDC_WSA_EC_HQ_EC_CLK_ENABLE BIT(0)
@@ -217,6 +199,65 @@
#define CDC_WSA_SPLINE_ASRC1_STATUS_FIFO (0x0760)
#define WSA_MAX_OFFSET (0x0760)
+/* LPASS codec version <=2.4 register offsets */
+#define CDC_WSA_COMPANDER1_CTL0 (0x05C0)
+#define CDC_WSA_COMPANDER1_CTL1 (0x05C4)
+#define CDC_WSA_COMPANDER1_CTL2 (0x05C8)
+#define CDC_WSA_COMPANDER1_CTL3 (0x05CC)
+#define CDC_WSA_COMPANDER1_CTL4 (0x05D0)
+#define CDC_WSA_COMPANDER1_CTL5 (0x05D4)
+#define CDC_WSA_COMPANDER1_CTL6 (0x05D8)
+#define CDC_WSA_COMPANDER1_CTL7 (0x05DC)
+#define CDC_WSA_SOFTCLIP0_CRC (0x0600)
+#define CDC_WSA_SOFTCLIP_CLK_EN_MASK BIT(0)
+#define CDC_WSA_SOFTCLIP_CLK_ENABLE BIT(0)
+#define CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL (0x0604)
+#define CDC_WSA_SOFTCLIP_EN_MASK BIT(0)
+#define CDC_WSA_SOFTCLIP_ENABLE BIT(0)
+#define CDC_WSA_SOFTCLIP1_CRC (0x0640)
+#define CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL (0x0644)
+
+/* LPASS codec version >=2.5 register offsets */
+#define CDC_WSA_TOP_FS_UNGATE (0x00AC)
+#define CDC_WSA_TOP_GRP_SEL (0x00B0)
+#define CDC_WSA_TOP_FS_UNGATE2 (0x00DC)
+#define CDC_2_5_WSA_COMPANDER0_CTL8 (0x05A0)
+#define CDC_2_5_WSA_COMPANDER0_CTL9 (0x05A4)
+#define CDC_2_5_WSA_COMPANDER0_CTL10 (0x05A8)
+#define CDC_2_5_WSA_COMPANDER0_CTL11 (0x05AC)
+#define CDC_2_5_WSA_COMPANDER0_CTL12 (0x05B0)
+#define CDC_2_5_WSA_COMPANDER0_CTL13 (0x05B4)
+#define CDC_2_5_WSA_COMPANDER0_CTL14 (0x05B8)
+#define CDC_2_5_WSA_COMPANDER0_CTL15 (0x05BC)
+#define CDC_2_5_WSA_COMPANDER0_CTL16 (0x05C0)
+#define CDC_2_5_WSA_COMPANDER0_CTL17 (0x05C4)
+#define CDC_2_5_WSA_COMPANDER0_CTL18 (0x05C8)
+#define CDC_2_5_WSA_COMPANDER0_CTL19 (0x05CC)
+#define CDC_2_5_WSA_COMPANDER1_CTL0 (0x05E0)
+#define CDC_2_5_WSA_COMPANDER1_CTL1 (0x05E4)
+#define CDC_2_5_WSA_COMPANDER1_CTL2 (0x05E8)
+#define CDC_2_5_WSA_COMPANDER1_CTL3 (0x05EC)
+#define CDC_2_5_WSA_COMPANDER1_CTL4 (0x05F0)
+#define CDC_2_5_WSA_COMPANDER1_CTL5 (0x05F4)
+#define CDC_2_5_WSA_COMPANDER1_CTL6 (0x05F8)
+#define CDC_2_5_WSA_COMPANDER1_CTL7 (0x05FC)
+#define CDC_2_5_WSA_COMPANDER1_CTL8 (0x0600)
+#define CDC_2_5_WSA_COMPANDER1_CTL9 (0x0604)
+#define CDC_2_5_WSA_COMPANDER1_CTL10 (0x0608)
+#define CDC_2_5_WSA_COMPANDER1_CTL11 (0x060C)
+#define CDC_2_5_WSA_COMPANDER1_CTL12 (0x0610)
+#define CDC_2_5_WSA_COMPANDER1_CTL13 (0x0614)
+#define CDC_2_5_WSA_COMPANDER1_CTL14 (0x0618)
+#define CDC_2_5_WSA_COMPANDER1_CTL15 (0x061C)
+#define CDC_2_5_WSA_COMPANDER1_CTL16 (0x0620)
+#define CDC_2_5_WSA_COMPANDER1_CTL17 (0x0624)
+#define CDC_2_5_WSA_COMPANDER1_CTL18 (0x0628)
+#define CDC_2_5_WSA_COMPANDER1_CTL19 (0x062C)
+#define CDC_2_5_WSA_SOFTCLIP0_CRC (0x0640)
+#define CDC_2_5_WSA_SOFTCLIP0_SOFTCLIP_CTRL (0x0644)
+#define CDC_2_5_WSA_SOFTCLIP1_CRC (0x0660)
+#define CDC_2_5_WSA_SOFTCLIP1_SOFTCLIP_CTRL (0x0664)
+
#define WSA_MACRO_RX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
@@ -235,11 +276,8 @@
#define NUM_INTERPOLATORS 2
#define WSA_NUM_CLKS_MAX 5
#define WSA_MACRO_MCLK_FREQ 19200000
-#define WSA_MACRO_MUX_INP_MASK2 0x38
#define WSA_MACRO_MUX_CFG_OFFSET 0x8
#define WSA_MACRO_MUX_CFG1_OFFSET 0x4
-#define WSA_MACRO_RX_COMP_OFFSET 0x40
-#define WSA_MACRO_RX_SOFTCLIP_OFFSET 0x40
#define WSA_MACRO_RX_PATH_OFFSET 0x80
#define WSA_MACRO_RX_PATH_CFG3_OFFSET 0x10
#define WSA_MACRO_RX_PATH_DSMDEM_OFFSET 0x4C
@@ -335,12 +373,34 @@ enum {
WSA_MACRO_MAX_DAIS,
};
+/**
+ * struct wsa_reg_layout - Register layout differences
+ * @rx_intx_1_mix_inp0_sel_mask: register mask for RX_INTX_1_MIX_INP0_SEL_MASK
+ * @rx_intx_1_mix_inp1_sel_mask: register mask for RX_INTX_1_MIX_INP1_SEL_MASK
+ * @rx_intx_1_mix_inp2_sel_mask: register mask for RX_INTX_1_MIX_INP2_SEL_MASK
+ * @rx_intx_2_sel_mask: register mask for RX_INTX_2_SEL_MASK
+ * @compander1_reg_offset: offset between compander registers (compander1 - compander0)
+ * @softclip0_reg_base: base address of softclip0 register
+ * @softclip1_reg_offset: offset between compander registers (softclip1 - softclip0)
+ */
+struct wsa_reg_layout {
+ unsigned int rx_intx_1_mix_inp0_sel_mask;
+ unsigned int rx_intx_1_mix_inp1_sel_mask;
+ unsigned int rx_intx_1_mix_inp2_sel_mask;
+ unsigned int rx_intx_2_sel_mask;
+ unsigned int compander1_reg_offset;
+ unsigned int softclip0_reg_base;
+ unsigned int softclip1_reg_offset;
+};
+
struct wsa_macro {
struct device *dev;
int comp_enabled[WSA_MACRO_COMP_MAX];
int ec_hq[WSA_MACRO_RX1 + 1];
u16 prim_int_users[WSA_MACRO_RX1 + 1];
u16 wsa_mclk_users;
+ enum lpass_codec_version codec_version;
+ const struct wsa_reg_layout *reg_layout;
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];
@@ -359,16 +419,44 @@ struct wsa_macro {
};
#define to_wsa_macro(_hw) container_of(_hw, struct wsa_macro, hw)
+static const struct wsa_reg_layout wsa_codec_v2_1 = {
+ .rx_intx_1_mix_inp0_sel_mask = GENMASK(2, 0),
+ .rx_intx_1_mix_inp1_sel_mask = GENMASK(5, 3),
+ .rx_intx_1_mix_inp2_sel_mask = GENMASK(5, 3),
+ .rx_intx_2_sel_mask = GENMASK(2, 0),
+ .compander1_reg_offset = 0x40,
+ .softclip0_reg_base = 0x600,
+ .softclip1_reg_offset = 0x40,
+};
+
+static const struct wsa_reg_layout wsa_codec_v2_5 = {
+ .rx_intx_1_mix_inp0_sel_mask = GENMASK(3, 0),
+ .rx_intx_1_mix_inp1_sel_mask = GENMASK(7, 4),
+ .rx_intx_1_mix_inp2_sel_mask = GENMASK(7, 4),
+ .rx_intx_2_sel_mask = GENMASK(3, 0),
+ .compander1_reg_offset = 0x60,
+ .softclip0_reg_base = 0x640,
+ .softclip1_reg_offset = 0x20,
+};
+
static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400);
-static const char *const rx_text[] = {
+static const char *const rx_text_v2_1[] = {
"ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "DEC0", "DEC1"
};
-static const char *const rx_mix_text[] = {
+static const char *const rx_text_v2_5[] = {
+ "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", "RX5", "RX6", "RX7", "RX8", "DEC0", "DEC1"
+};
+
+static const char *const rx_mix_text_v2_1[] = {
"ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1"
};
+static const char *const rx_mix_text_v2_5[] = {
+ "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", "RX5", "RX6", "RX7", "RX8"
+};
+
static const char *const rx_mix_ec_text[] = {
"ZERO", "RX_MIX_TX0", "RX_MIX_TX1"
};
@@ -390,68 +478,124 @@ static SOC_ENUM_SINGLE_EXT_DECL(wsa_macro_ear_spkr_pa_gain_enum,
wsa_macro_ear_spkr_pa_gain_text);
/* RX INT0 */
-static const struct soc_enum rx0_prim_inp0_chain_enum =
+static const struct soc_enum rx0_prim_inp0_chain_enum_v2_1 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
- 0, 7, rx_text);
+ 0, 7, rx_text_v2_1);
-static const struct soc_enum rx0_prim_inp1_chain_enum =
+static const struct soc_enum rx0_prim_inp1_chain_enum_v2_1 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
- 3, 7, rx_text);
+ 3, 7, rx_text_v2_1);
+
+static const struct soc_enum rx0_prim_inp2_chain_enum_v2_1 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
+ 3, 7, rx_text_v2_1);
-static const struct soc_enum rx0_prim_inp2_chain_enum =
+static const struct soc_enum rx0_mix_chain_enum_v2_1 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
- 3, 7, rx_text);
+ 0, 5, rx_mix_text_v2_1);
+
+static const struct soc_enum rx0_prim_inp0_chain_enum_v2_5 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
+ 0, 12, rx_text_v2_5);
+
+static const struct soc_enum rx0_prim_inp1_chain_enum_v2_5 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
+ 4, 12, rx_text_v2_5);
-static const struct soc_enum rx0_mix_chain_enum =
+static const struct soc_enum rx0_prim_inp2_chain_enum_v2_5 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
- 0, 5, rx_mix_text);
+ 4, 12, rx_text_v2_5);
+
+static const struct soc_enum rx0_mix_chain_enum_v2_5 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
+ 0, 10, rx_mix_text_v2_5);
static const struct soc_enum rx0_sidetone_mix_enum =
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_sidetone_mix_text);
-static const struct snd_kcontrol_new rx0_prim_inp0_mux =
- SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum);
+static const struct snd_kcontrol_new rx0_prim_inp0_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx0_prim_inp1_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx0_prim_inp2_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx0_mix_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum_v2_1);
-static const struct snd_kcontrol_new rx0_prim_inp1_mux =
- SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum);
+static const struct snd_kcontrol_new rx0_prim_inp0_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum_v2_5);
-static const struct snd_kcontrol_new rx0_prim_inp2_mux =
- SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum);
+static const struct snd_kcontrol_new rx0_prim_inp1_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum_v2_5);
-static const struct snd_kcontrol_new rx0_mix_mux =
- SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum);
+static const struct snd_kcontrol_new rx0_prim_inp2_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum_v2_5);
+
+static const struct snd_kcontrol_new rx0_mix_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum_v2_5);
static const struct snd_kcontrol_new rx0_sidetone_mix_mux =
SOC_DAPM_ENUM("WSA_RX0 SIDETONE MIX Mux", rx0_sidetone_mix_enum);
/* RX INT1 */
-static const struct soc_enum rx1_prim_inp0_chain_enum =
+static const struct soc_enum rx1_prim_inp0_chain_enum_v2_1 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
- 0, 7, rx_text);
+ 0, 7, rx_text_v2_1);
-static const struct soc_enum rx1_prim_inp1_chain_enum =
+static const struct soc_enum rx1_prim_inp1_chain_enum_v2_1 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
- 3, 7, rx_text);
+ 3, 7, rx_text_v2_1);
-static const struct soc_enum rx1_prim_inp2_chain_enum =
+static const struct soc_enum rx1_prim_inp2_chain_enum_v2_1 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
- 3, 7, rx_text);
+ 3, 7, rx_text_v2_1);
-static const struct soc_enum rx1_mix_chain_enum =
+static const struct soc_enum rx1_mix_chain_enum_v2_1 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
- 0, 5, rx_mix_text);
+ 0, 5, rx_mix_text_v2_1);
-static const struct snd_kcontrol_new rx1_prim_inp0_mux =
- SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum);
+static const struct soc_enum rx1_prim_inp0_chain_enum_v2_5 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
+ 0, 12, rx_text_v2_5);
-static const struct snd_kcontrol_new rx1_prim_inp1_mux =
- SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum);
+static const struct soc_enum rx1_prim_inp1_chain_enum_v2_5 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
+ 4, 12, rx_text_v2_5);
-static const struct snd_kcontrol_new rx1_prim_inp2_mux =
- SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum);
+static const struct soc_enum rx1_prim_inp2_chain_enum_v2_5 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
+ 4, 12, rx_text_v2_5);
+
+static const struct soc_enum rx1_mix_chain_enum_v2_5 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
+ 0, 10, rx_mix_text_v2_5);
+
+static const struct snd_kcontrol_new rx1_prim_inp0_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx1_prim_inp1_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx1_prim_inp2_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx1_mix_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx1_prim_inp0_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum_v2_5);
-static const struct snd_kcontrol_new rx1_mix_mux =
- SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum);
+static const struct snd_kcontrol_new rx1_prim_inp1_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum_v2_5);
+
+static const struct snd_kcontrol_new rx1_prim_inp2_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum_v2_5);
+
+static const struct snd_kcontrol_new rx1_mix_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum_v2_5);
static const struct soc_enum rx_mix_ec0_enum =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_MIX_CFG0,
@@ -490,14 +634,6 @@ static const struct reg_default wsa_defaults[] = {
{ CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, 0x00},
{ CDC_WSA_RX_INP_MUX_RX_EC_CFG0, 0x00},
{ CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, 0x00},
- { CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x02},
- { CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x00},
- { CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x02},
- { CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x00},
- { CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x02},
- { CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x00},
- { CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x02},
- { CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x00},
{ CDC_WSA_INTR_CTRL_CFG, 0x00},
{ CDC_WSA_INTR_CTRL_CLR_COMMIT, 0x00},
{ CDC_WSA_INTR_CTRL_PIN1_MASK0, 0xFF},
@@ -562,18 +698,6 @@ static const struct reg_default wsa_defaults[] = {
{ CDC_WSA_COMPANDER0_CTL5, 0x00},
{ CDC_WSA_COMPANDER0_CTL6, 0x01},
{ CDC_WSA_COMPANDER0_CTL7, 0x28},
- { CDC_WSA_COMPANDER1_CTL0, 0x60},
- { CDC_WSA_COMPANDER1_CTL1, 0xDB},
- { CDC_WSA_COMPANDER1_CTL2, 0xFF},
- { CDC_WSA_COMPANDER1_CTL3, 0x35},
- { CDC_WSA_COMPANDER1_CTL4, 0xFF},
- { CDC_WSA_COMPANDER1_CTL5, 0x00},
- { CDC_WSA_COMPANDER1_CTL6, 0x01},
- { CDC_WSA_COMPANDER1_CTL7, 0x28},
- { CDC_WSA_SOFTCLIP0_CRC, 0x00},
- { CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38},
- { CDC_WSA_SOFTCLIP1_CRC, 0x00},
- { CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38},
{ CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL, 0x00},
{ CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0, 0x01},
{ CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL, 0x00},
@@ -598,6 +722,79 @@ static const struct reg_default wsa_defaults[] = {
{ CDC_WSA_SPLINE_ASRC1_STATUS_FIFO, 0x00},
};
+static const struct reg_default wsa_defaults_v2_1[] = {
+ { CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x02},
+ { CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x00},
+ { CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x02},
+ { CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x00},
+ { CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x02},
+ { CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x00},
+ { CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x02},
+ { CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x00},
+ { CDC_WSA_COMPANDER1_CTL0, 0x60},
+ { CDC_WSA_COMPANDER1_CTL1, 0xDB},
+ { CDC_WSA_COMPANDER1_CTL2, 0xFF},
+ { CDC_WSA_COMPANDER1_CTL3, 0x35},
+ { CDC_WSA_COMPANDER1_CTL4, 0xFF},
+ { CDC_WSA_COMPANDER1_CTL5, 0x00},
+ { CDC_WSA_COMPANDER1_CTL6, 0x01},
+ { CDC_WSA_COMPANDER1_CTL7, 0x28},
+ { CDC_WSA_SOFTCLIP0_CRC, 0x00},
+ { CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38},
+ { CDC_WSA_SOFTCLIP1_CRC, 0x00},
+ { CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38},
+};
+
+static const struct reg_default wsa_defaults_v2_5[] = {
+ { CDC_WSA_TOP_FS_UNGATE, 0xFF},
+ { CDC_WSA_TOP_GRP_SEL, 0x08},
+ { CDC_WSA_TOP_FS_UNGATE2, 0x1F},
+ { CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x04},
+ { CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x02},
+ { CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x04},
+ { CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x02},
+ { CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x04},
+ { CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x02},
+ { CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x04},
+ { CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x02},
+ { CDC_2_5_WSA_COMPANDER0_CTL8, 0x00},
+ { CDC_2_5_WSA_COMPANDER0_CTL9, 0x00},
+ { CDC_2_5_WSA_COMPANDER0_CTL10, 0x06},
+ { CDC_2_5_WSA_COMPANDER0_CTL11, 0x12},
+ { CDC_2_5_WSA_COMPANDER0_CTL12, 0x1E},
+ { CDC_2_5_WSA_COMPANDER0_CTL13, 0x24},
+ { CDC_2_5_WSA_COMPANDER0_CTL14, 0x24},
+ { CDC_2_5_WSA_COMPANDER0_CTL15, 0x24},
+ { CDC_2_5_WSA_COMPANDER0_CTL16, 0x00},
+ { CDC_2_5_WSA_COMPANDER0_CTL17, 0x24},
+ { CDC_2_5_WSA_COMPANDER0_CTL18, 0x2A},
+ { CDC_2_5_WSA_COMPANDER0_CTL19, 0x16},
+ { CDC_2_5_WSA_COMPANDER1_CTL0, 0x60},
+ { CDC_2_5_WSA_COMPANDER1_CTL1, 0xDB},
+ { CDC_2_5_WSA_COMPANDER1_CTL2, 0xFF},
+ { CDC_2_5_WSA_COMPANDER1_CTL3, 0x35},
+ { CDC_2_5_WSA_COMPANDER1_CTL4, 0xFF},
+ { CDC_2_5_WSA_COMPANDER1_CTL5, 0x00},
+ { CDC_2_5_WSA_COMPANDER1_CTL6, 0x01},
+ { CDC_2_5_WSA_COMPANDER1_CTL7, 0x28},
+ { CDC_2_5_WSA_COMPANDER1_CTL8, 0x00},
+ { CDC_2_5_WSA_COMPANDER1_CTL9, 0x00},
+ { CDC_2_5_WSA_COMPANDER1_CTL10, 0x06},
+ { CDC_2_5_WSA_COMPANDER1_CTL11, 0x12},
+ { CDC_2_5_WSA_COMPANDER1_CTL12, 0x1E},
+ { CDC_2_5_WSA_COMPANDER1_CTL13, 0x24},
+ { CDC_2_5_WSA_COMPANDER1_CTL14, 0x24},
+ { CDC_2_5_WSA_COMPANDER1_CTL15, 0x24},
+ { CDC_2_5_WSA_COMPANDER1_CTL16, 0x00},
+ { CDC_2_5_WSA_COMPANDER1_CTL17, 0x24},
+ { CDC_2_5_WSA_COMPANDER1_CTL18, 0x2A},
+ { CDC_2_5_WSA_COMPANDER1_CTL19, 0x16},
+ { CDC_2_5_WSA_SOFTCLIP0_CRC, 0x00},
+ { CDC_2_5_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38},
+ { CDC_2_5_WSA_SOFTCLIP1_CRC, 0x00},
+ { CDC_2_5_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38},
+};
+
static bool wsa_is_wronly_register(struct device *dev,
unsigned int reg)
{
@@ -611,8 +808,77 @@ static bool wsa_is_wronly_register(struct device *dev,
return false;
}
+static bool wsa_is_rw_register_v2_1(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_WSA_COMPANDER1_CTL0:
+ case CDC_WSA_COMPANDER1_CTL1:
+ case CDC_WSA_COMPANDER1_CTL2:
+ case CDC_WSA_COMPANDER1_CTL3:
+ case CDC_WSA_COMPANDER1_CTL4:
+ case CDC_WSA_COMPANDER1_CTL5:
+ case CDC_WSA_COMPANDER1_CTL7:
+ case CDC_WSA_SOFTCLIP0_CRC:
+ case CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL:
+ case CDC_WSA_SOFTCLIP1_CRC:
+ case CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL:
+ return true;
+ }
+
+ return false;
+}
+
+static bool wsa_is_rw_register_v2_5(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_WSA_TOP_FS_UNGATE:
+ case CDC_WSA_TOP_GRP_SEL:
+ case CDC_WSA_TOP_FS_UNGATE2:
+ case CDC_2_5_WSA_COMPANDER0_CTL8:
+ case CDC_2_5_WSA_COMPANDER0_CTL9:
+ case CDC_2_5_WSA_COMPANDER0_CTL10:
+ case CDC_2_5_WSA_COMPANDER0_CTL11:
+ case CDC_2_5_WSA_COMPANDER0_CTL12:
+ case CDC_2_5_WSA_COMPANDER0_CTL13:
+ case CDC_2_5_WSA_COMPANDER0_CTL14:
+ case CDC_2_5_WSA_COMPANDER0_CTL15:
+ case CDC_2_5_WSA_COMPANDER0_CTL16:
+ case CDC_2_5_WSA_COMPANDER0_CTL17:
+ case CDC_2_5_WSA_COMPANDER0_CTL18:
+ case CDC_2_5_WSA_COMPANDER0_CTL19:
+ case CDC_2_5_WSA_COMPANDER1_CTL0:
+ case CDC_2_5_WSA_COMPANDER1_CTL1:
+ case CDC_2_5_WSA_COMPANDER1_CTL2:
+ case CDC_2_5_WSA_COMPANDER1_CTL3:
+ case CDC_2_5_WSA_COMPANDER1_CTL4:
+ case CDC_2_5_WSA_COMPANDER1_CTL5:
+ case CDC_2_5_WSA_COMPANDER1_CTL7:
+ case CDC_2_5_WSA_COMPANDER1_CTL8:
+ case CDC_2_5_WSA_COMPANDER1_CTL9:
+ case CDC_2_5_WSA_COMPANDER1_CTL10:
+ case CDC_2_5_WSA_COMPANDER1_CTL11:
+ case CDC_2_5_WSA_COMPANDER1_CTL12:
+ case CDC_2_5_WSA_COMPANDER1_CTL13:
+ case CDC_2_5_WSA_COMPANDER1_CTL14:
+ case CDC_2_5_WSA_COMPANDER1_CTL15:
+ case CDC_2_5_WSA_COMPANDER1_CTL16:
+ case CDC_2_5_WSA_COMPANDER1_CTL17:
+ case CDC_2_5_WSA_COMPANDER1_CTL18:
+ case CDC_2_5_WSA_COMPANDER1_CTL19:
+ case CDC_2_5_WSA_SOFTCLIP0_CRC:
+ case CDC_2_5_WSA_SOFTCLIP0_SOFTCLIP_CTRL:
+ case CDC_2_5_WSA_SOFTCLIP1_CRC:
+ case CDC_2_5_WSA_SOFTCLIP1_SOFTCLIP_CTRL:
+ return true;
+ }
+
+ return false;
+}
+
static bool wsa_is_rw_register(struct device *dev, unsigned int reg)
{
+ struct wsa_macro *wsa = dev_get_drvdata(dev);
+
switch (reg) {
case CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL:
case CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL:
@@ -702,17 +968,6 @@ static bool wsa_is_rw_register(struct device *dev, unsigned int reg)
case CDC_WSA_COMPANDER0_CTL4:
case CDC_WSA_COMPANDER0_CTL5:
case CDC_WSA_COMPANDER0_CTL7:
- case CDC_WSA_COMPANDER1_CTL0:
- case CDC_WSA_COMPANDER1_CTL1:
- case CDC_WSA_COMPANDER1_CTL2:
- case CDC_WSA_COMPANDER1_CTL3:
- case CDC_WSA_COMPANDER1_CTL4:
- case CDC_WSA_COMPANDER1_CTL5:
- case CDC_WSA_COMPANDER1_CTL7:
- case CDC_WSA_SOFTCLIP0_CRC:
- case CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL:
- case CDC_WSA_SOFTCLIP1_CRC:
- case CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL:
case CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL:
case CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0:
case CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL:
@@ -728,7 +983,10 @@ static bool wsa_is_rw_register(struct device *dev, unsigned int reg)
return true;
}
- return false;
+ if (wsa->codec_version >= LPASS_CODEC_VERSION_2_5)
+ return wsa_is_rw_register_v2_5(dev, reg);
+
+ return wsa_is_rw_register_v2_1(dev, reg);
}
static bool wsa_is_writeable_register(struct device *dev, unsigned int reg)
@@ -742,8 +1000,30 @@ static bool wsa_is_writeable_register(struct device *dev, unsigned int reg)
return ret;
}
+static bool wsa_is_readable_register_v2_1(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_WSA_COMPANDER1_CTL6:
+ return true;
+ }
+
+ return wsa_is_rw_register(dev, reg);
+}
+
+static bool wsa_is_readable_register_v2_5(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_2_5_WSA_COMPANDER1_CTL6:
+ return true;
+ }
+
+ return wsa_is_rw_register(dev, reg);
+}
+
static bool wsa_is_readable_register(struct device *dev, unsigned int reg)
{
+ struct wsa_macro *wsa = dev_get_drvdata(dev);
+
switch (reg) {
case CDC_WSA_INTR_CTRL_CLR_COMMIT:
case CDC_WSA_INTR_CTRL_PIN1_CLEAR0:
@@ -751,7 +1031,6 @@ static bool wsa_is_readable_register(struct device *dev, unsigned int reg)
case CDC_WSA_INTR_CTRL_PIN1_STATUS0:
case CDC_WSA_INTR_CTRL_PIN2_STATUS0:
case CDC_WSA_COMPANDER0_CTL6:
- case CDC_WSA_COMPANDER1_CTL6:
case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB:
case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB:
case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB:
@@ -765,17 +1044,41 @@ static bool wsa_is_readable_register(struct device *dev, unsigned int reg)
return true;
}
- return wsa_is_rw_register(dev, reg);
+ if (wsa->codec_version >= LPASS_CODEC_VERSION_2_5)
+ return wsa_is_readable_register_v2_5(dev, reg);
+
+ return wsa_is_readable_register_v2_1(dev, reg);
+}
+
+static bool wsa_is_volatile_register_v2_1(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_WSA_COMPANDER1_CTL6:
+ return true;
+ }
+
+ return false;
+}
+
+static bool wsa_is_volatile_register_v2_5(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_2_5_WSA_COMPANDER1_CTL6:
+ return true;
+ }
+
+ return false;
}
static bool wsa_is_volatile_register(struct device *dev, unsigned int reg)
{
+ struct wsa_macro *wsa = dev_get_drvdata(dev);
+
/* Update volatile list for rx/tx macros */
switch (reg) {
case CDC_WSA_INTR_CTRL_PIN1_STATUS0:
case CDC_WSA_INTR_CTRL_PIN2_STATUS0:
case CDC_WSA_COMPANDER0_CTL6:
- case CDC_WSA_COMPANDER1_CTL6:
case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB:
case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB:
case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB:
@@ -788,7 +1091,11 @@ static bool wsa_is_volatile_register(struct device *dev, unsigned int reg)
case CDC_WSA_SPLINE_ASRC1_STATUS_FIFO:
return true;
}
- return false;
+
+ if (wsa->codec_version >= LPASS_CODEC_VERSION_2_5)
+ return wsa_is_volatile_register_v2_5(dev, reg);
+
+ return wsa_is_volatile_register_v2_1(dev, reg);
}
static const struct regmap_config wsa_regmap_config = {
@@ -797,8 +1104,7 @@ static const struct regmap_config wsa_regmap_config = {
.val_bits = 32, /* 8 but with 32 bit read/write */
.reg_stride = 4,
.cache_type = REGCACHE_FLAT,
- .reg_defaults = wsa_defaults,
- .num_reg_defaults = ARRAY_SIZE(wsa_defaults),
+ /* .reg_defaults and .num_reg_defaults set in probe() */
.max_register = WSA_MAX_OFFSET,
.writeable_reg = wsa_is_writeable_register,
.volatile_reg = wsa_is_volatile_register,
@@ -872,11 +1178,11 @@ static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
for (j = 0; j < NUM_INTERPOLATORS; j++) {
int_mux_cfg1 = int_mux_cfg0 + WSA_MACRO_MUX_CFG1_OFFSET;
inp0_sel = snd_soc_component_read_field(component, int_mux_cfg0,
- CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK);
- inp1_sel = snd_soc_component_read_field(component, int_mux_cfg0,
- CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK);
+ wsa->reg_layout->rx_intx_1_mix_inp0_sel_mask);
+ inp1_sel = snd_soc_component_read_field(component, int_mux_cfg0,
+ wsa->reg_layout->rx_intx_1_mix_inp1_sel_mask);
inp2_sel = snd_soc_component_read_field(component, int_mux_cfg1,
- CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK);
+ wsa->reg_layout->rx_intx_1_mix_inp2_sel_mask);
if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
(inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
@@ -917,7 +1223,7 @@ static int wsa_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai,
int_mux_cfg1 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG1;
for (j = 0; j < NUM_INTERPOLATORS; j++) {
int_mux_cfg1_val = snd_soc_component_read_field(component, int_mux_cfg1,
- CDC_WSA_RX_INTX_2_SEL_MASK);
+ wsa->reg_layout->rx_intx_2_sel_mask);
if (int_mux_cfg1_val == int_2_inp + INTn_2_INP_SEL_RX0) {
int_fs_reg = CDC_WSA_RX0_RX_PATH_MIX_CTL +
@@ -992,7 +1298,7 @@ static int wsa_macro_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int wsa_macro_get_channel_map(struct snd_soc_dai *dai,
+static int wsa_macro_get_channel_map(const struct snd_soc_dai *dai,
unsigned int *tx_num, unsigned int *tx_slot,
unsigned int *rx_num, unsigned int *rx_slot)
{
@@ -1300,7 +1606,7 @@ static int wsa_macro_config_compander(struct snd_soc_component *component,
return 0;
comp_ctl0_reg = CDC_WSA_COMPANDER0_CTL0 +
- (comp * WSA_MACRO_RX_COMP_OFFSET);
+ (comp * wsa->reg_layout->compander1_reg_offset);
rx_path_cfg0_reg = CDC_WSA_RX0_RX_PATH_CFG0 +
(comp * WSA_MACRO_RX_PATH_OFFSET);
@@ -1346,8 +1652,8 @@ static void wsa_macro_enable_softclip_clk(struct snd_soc_component *component,
int path,
bool enable)
{
- u16 softclip_clk_reg = CDC_WSA_SOFTCLIP0_CRC +
- (path * WSA_MACRO_RX_SOFTCLIP_OFFSET);
+ u16 softclip_clk_reg = wsa->reg_layout->softclip0_reg_base +
+ (path * wsa->reg_layout->softclip1_reg_offset);
u8 softclip_mux_mask = (1 << path);
u8 softclip_mux_value = (1 << path);
@@ -1392,7 +1698,7 @@ static int wsa_macro_config_softclip(struct snd_soc_component *component,
return 0;
softclip_ctrl_reg = CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL +
- (softclip_path * WSA_MACRO_RX_SOFTCLIP_OFFSET);
+ (softclip_path * wsa->reg_layout->softclip1_reg_offset);
if (SND_SOC_DAPM_EVENT_ON(event)) {
/* Enable Softclip clock and mux */
@@ -1417,6 +1723,7 @@ static int wsa_macro_config_softclip(struct snd_soc_component *component,
static bool wsa_macro_adie_lb(struct snd_soc_component *component,
int interp_idx)
{
+ struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
u16 int_mux_cfg0, int_mux_cfg1;
u8 int_n_inp0, int_n_inp1, int_n_inp2;
@@ -1424,19 +1731,19 @@ static bool wsa_macro_adie_lb(struct snd_soc_component *component,
int_mux_cfg1 = int_mux_cfg0 + 4;
int_n_inp0 = snd_soc_component_read_field(component, int_mux_cfg0,
- CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK);
+ wsa->reg_layout->rx_intx_1_mix_inp0_sel_mask);
if (int_n_inp0 == INTn_1_INP_SEL_DEC0 ||
int_n_inp0 == INTn_1_INP_SEL_DEC1)
return true;
int_n_inp1 = snd_soc_component_read_field(component, int_mux_cfg0,
- CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK);
+ wsa->reg_layout->rx_intx_1_mix_inp1_sel_mask);
if (int_n_inp1 == INTn_1_INP_SEL_DEC0 ||
int_n_inp1 == INTn_1_INP_SEL_DEC1)
return true;
int_n_inp2 = snd_soc_component_read_field(component, int_mux_cfg1,
- CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK);
+ wsa->reg_layout->rx_intx_1_mix_inp2_sel_mask);
if (int_n_inp2 == INTn_1_INP_SEL_DEC0 ||
int_n_inp2 == INTn_1_INP_SEL_DEC1)
return true;
@@ -2074,19 +2381,6 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("WSA RX_MIX0", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("WSA RX_MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux),
- SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux),
- SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux),
- SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX0,
- 0, &rx0_mix_mux, wsa_macro_enable_mix_path,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MUX("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux),
- SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux),
- SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux),
- SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX1,
- 0, &rx1_mix_mux, wsa_macro_enable_mix_path,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
SND_SOC_DAPM_MIXER_E("WSA_RX INT0 MIX", SND_SOC_NOPM, 0, 0, NULL, 0,
wsa_macro_enable_main_path, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MIXER_E("WSA_RX INT1 MIX", SND_SOC_NOPM, 1, 0, NULL, 0,
@@ -2137,6 +2431,36 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = {
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
};
+static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets_v2_1[] = {
+ SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux_v2_1),
+ SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux_v2_1),
+ SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux_v2_1),
+ SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX0,
+ 0, &rx0_mix_mux_v2_1, wsa_macro_enable_mix_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux_v2_1),
+ SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux_v2_1),
+ SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux_v2_1),
+ SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX1,
+ 0, &rx1_mix_mux_v2_1, wsa_macro_enable_mix_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets_v2_5[] = {
+ SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux_v2_5),
+ SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux_v2_5),
+ SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux_v2_5),
+ SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX0,
+ 0, &rx0_mix_mux_v2_5, wsa_macro_enable_mix_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux_v2_5),
+ SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux_v2_5),
+ SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux_v2_5),
+ SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX1,
+ 0, &rx1_mix_mux_v2_5, wsa_macro_enable_mix_path,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
static const struct snd_soc_dapm_route wsa_audio_map[] = {
/* VI Feedback */
{"WSA_AIF_VI Mixer", "WSA_SPKR_VI_1", "VIINPUT_WSA"},
@@ -2282,7 +2606,10 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
static int wsa_macro_component_probe(struct snd_soc_component *comp)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(comp);
struct wsa_macro *wsa = snd_soc_component_get_drvdata(comp);
+ const struct snd_soc_dapm_widget *widgets;
+ unsigned int num_widgets;
snd_soc_component_init_regmap(comp, wsa->regmap);
@@ -2299,7 +2626,27 @@ static int wsa_macro_component_probe(struct snd_soc_component *comp)
wsa_macro_set_spkr_mode(comp, WSA_MACRO_SPKR_MODE_1);
- return 0;
+ switch (wsa->codec_version) {
+ case LPASS_CODEC_VERSION_1_0:
+ case LPASS_CODEC_VERSION_1_1:
+ case LPASS_CODEC_VERSION_1_2:
+ case LPASS_CODEC_VERSION_2_0:
+ case LPASS_CODEC_VERSION_2_1:
+ widgets = wsa_macro_dapm_widgets_v2_1;
+ num_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets_v2_1);
+ break;
+ case LPASS_CODEC_VERSION_2_5:
+ case LPASS_CODEC_VERSION_2_6:
+ case LPASS_CODEC_VERSION_2_7:
+ case LPASS_CODEC_VERSION_2_8:
+ widgets = wsa_macro_dapm_widgets_v2_5;
+ num_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets_v2_5);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return snd_soc_dapm_new_controls(dapm, widgets, num_widgets);
}
static int swclk_gate_enable(struct clk_hw *hw)
@@ -2382,7 +2729,7 @@ static int wsa_macro_probe(struct platform_device *pdev)
struct wsa_macro *wsa;
kernel_ulong_t flags;
void __iomem *base;
- int ret;
+ int ret, def_count;
flags = (kernel_ulong_t)device_get_match_data(dev);
@@ -2416,7 +2763,56 @@ static int wsa_macro_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
- wsa->regmap = devm_regmap_init_mmio(dev, base, &wsa_regmap_config);
+ wsa->codec_version = lpass_macro_get_codec_version();
+ struct reg_default *reg_defaults __free(kfree) = NULL;
+
+ switch (wsa->codec_version) {
+ case LPASS_CODEC_VERSION_1_0:
+ case LPASS_CODEC_VERSION_1_1:
+ case LPASS_CODEC_VERSION_1_2:
+ case LPASS_CODEC_VERSION_2_0:
+ case LPASS_CODEC_VERSION_2_1:
+ wsa->reg_layout = &wsa_codec_v2_1;
+ def_count = ARRAY_SIZE(wsa_defaults) + ARRAY_SIZE(wsa_defaults_v2_1);
+ reg_defaults = kmalloc_array(def_count, sizeof(*reg_defaults),
+ GFP_KERNEL);
+ if (!reg_defaults)
+ return -ENOMEM;
+ memcpy(&reg_defaults[0], wsa_defaults, sizeof(wsa_defaults));
+ memcpy(&reg_defaults[ARRAY_SIZE(wsa_defaults)],
+ wsa_defaults_v2_1, sizeof(wsa_defaults_v2_1));
+ break;
+
+ case LPASS_CODEC_VERSION_2_5:
+ case LPASS_CODEC_VERSION_2_6:
+ case LPASS_CODEC_VERSION_2_7:
+ case LPASS_CODEC_VERSION_2_8:
+ wsa->reg_layout = &wsa_codec_v2_5;
+ def_count = ARRAY_SIZE(wsa_defaults) + ARRAY_SIZE(wsa_defaults_v2_5);
+ reg_defaults = kmalloc_array(def_count, sizeof(*reg_defaults),
+ GFP_KERNEL);
+ if (!reg_defaults)
+ return -ENOMEM;
+ memcpy(&reg_defaults[0], wsa_defaults, sizeof(wsa_defaults));
+ memcpy(&reg_defaults[ARRAY_SIZE(wsa_defaults)],
+ wsa_defaults_v2_5, sizeof(wsa_defaults_v2_5));
+ break;
+
+ default:
+ dev_err(dev, "Unsupported Codec version (%d)\n", wsa->codec_version);
+ return -EINVAL;
+ }
+
+ struct regmap_config *reg_config __free(kfree) = kmemdup(&wsa_regmap_config,
+ sizeof(*reg_config),
+ GFP_KERNEL);
+ if (!reg_config)
+ return -ENOMEM;
+
+ reg_config->reg_defaults = reg_defaults;
+ reg_config->num_reg_defaults = def_count;
+
+ wsa->regmap = devm_regmap_init_mmio(dev, base, reg_config);
if (IS_ERR(wsa->regmap))
return PTR_ERR(wsa->regmap);
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 8b56ee550c09..8b0645c63462 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -1318,6 +1318,7 @@ static int max98088_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+ int ret;
switch (level) {
case SND_SOC_BIAS_ON:
@@ -1333,10 +1334,13 @@ static int max98088_set_bias_level(struct snd_soc_component *component,
*/
if (!IS_ERR(max98088->mclk)) {
if (snd_soc_component_get_bias_level(component) ==
- SND_SOC_BIAS_ON)
+ SND_SOC_BIAS_ON) {
clk_disable_unprepare(max98088->mclk);
- else
- clk_prepare_enable(max98088->mclk);
+ } else {
+ ret = clk_prepare_enable(max98088->mclk);
+ if (ret)
+ return ret;
+ }
}
break;
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
index 57fa2db1e148..1bae253618fd 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -13,7 +13,6 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/time.h>
diff --git a/sound/soc/codecs/max98504.c b/sound/soc/codecs/max98504.c
index 93412b966b33..6b6a7ece4cec 100644
--- a/sound/soc/codecs/max98504.c
+++ b/sound/soc/codecs/max98504.c
@@ -220,8 +220,10 @@ static int max98504_set_tdm_slot(struct snd_soc_dai *dai,
return 0;
}
static int max98504_set_channel_map(struct snd_soc_dai *dai,
- unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
+ unsigned int tx_num,
+ const unsigned int *tx_slot,
+ unsigned int rx_num,
+ const unsigned int *rx_slot)
{
struct max98504_priv *max98504 = snd_soc_dai_get_drvdata(dai);
struct regmap *map = max98504->regmap;
diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c
index 0284e29c11d3..9247b90d1b99 100644
--- a/sound/soc/codecs/mt6358.c
+++ b/sound/soc/codecs/mt6358.c
@@ -96,7 +96,7 @@ struct mt6358_priv {
int wov_enabled;
- unsigned int dmic_one_wire_mode;
+ int dmic_one_wire_mode;
};
int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt,
@@ -577,6 +577,39 @@ static int mt6358_put_wov(struct snd_kcontrol *kcontrol,
return 0;
}
+static int mt6358_dmic_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct mt6358_priv *priv = snd_soc_component_get_drvdata(c);
+
+ ucontrol->value.integer.value[0] = priv->dmic_one_wire_mode;
+ dev_dbg(priv->dev, "%s() dmic_mode = %d", __func__, priv->dmic_one_wire_mode);
+
+ return 0;
+}
+
+static int mt6358_dmic_mode_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct mt6358_priv *priv = snd_soc_component_get_drvdata(c);
+ int enabled = ucontrol->value.integer.value[0];
+
+ if (enabled < 0 || enabled > 1)
+ return -EINVAL;
+
+ if (priv->dmic_one_wire_mode != enabled) {
+ priv->dmic_one_wire_mode = enabled;
+ dev_dbg(priv->dev, "%s() dmic_mode = %d", __func__, priv->dmic_one_wire_mode);
+
+ return 1;
+ }
+ dev_dbg(priv->dev, "%s() dmic_mode = %d", __func__, priv->dmic_one_wire_mode);
+
+ return 0;
+}
+
static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0);
static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 600, 0);
@@ -599,6 +632,9 @@ static const struct snd_kcontrol_new mt6358_snd_controls[] = {
SOC_SINGLE_BOOL_EXT("Wake-on-Voice Phase2 Switch", 0,
mt6358_get_wov, mt6358_put_wov),
+
+ SOC_SINGLE_BOOL_EXT("Dmic Mode Switch", 0,
+ mt6358_dmic_mode_get, mt6358_dmic_mode_set),
};
/* MUX */
diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c
index e6909e64dfa3..e1cbaf8a944d 100644
--- a/sound/soc/codecs/nau8822.c
+++ b/sound/soc/codecs/nau8822.c
@@ -14,6 +14,7 @@
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
@@ -612,20 +613,6 @@ static const struct snd_soc_dapm_route nau8822_dapm_routes[] = {
{"Right DAC", NULL, "Digital Loopback"},
};
-static int nau8822_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
- unsigned int freq, int dir)
-{
- struct snd_soc_component *component = dai->component;
- struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
-
- nau8822->div_id = clk_id;
- nau8822->sysclk = freq;
- dev_dbg(component->dev, "master sysclk %dHz, source %s\n", freq,
- clk_id == NAU8822_CLK_PLL ? "PLL" : "MCLK");
-
- return 0;
-}
-
static int nau8822_calc_pll(unsigned int pll_in, unsigned int fs,
struct nau8822_pll *pll_param)
{
@@ -782,6 +769,35 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
return 0;
}
+static int nau8822_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = dai->component;
+ struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
+ unsigned long mclk_freq;
+
+ nau8822->div_id = clk_id;
+ nau8822->sysclk = freq;
+
+ if (nau8822->mclk) {
+ mclk_freq = clk_get_rate(nau8822->mclk);
+ if (mclk_freq != freq) {
+ int ret = nau8822_set_pll(dai, NAU8822_CLK_MCLK,
+ NAU8822_CLK_MCLK, mclk_freq, freq);
+ if (ret) {
+ dev_err(component->dev, "Failed to set PLL\n");
+ return ret;
+ }
+ nau8822->div_id = NAU8822_CLK_PLL;
+ }
+ }
+
+ dev_dbg(component->dev, "master sysclk %dHz, source %s\n", freq,
+ nau8822->div_id == NAU8822_CLK_PLL ? "PLL" : "MCLK");
+
+ return 0;
+}
+
static int nau8822_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
@@ -848,7 +864,7 @@ static int nau8822_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
- int val_len = 0, val_rate = 0;
+ int div = 0, val_len = 0, val_rate = 0;
unsigned int ctrl_val, bclk_fs, bclk_div;
/* make BCLK and LRC divide configuration if the codec as master. */
@@ -915,8 +931,10 @@ static int nau8822_hw_params(struct snd_pcm_substream *substream,
/* If the master clock is from MCLK, provide the runtime FS for driver
* to get the master clock prescaler configuration.
*/
- if (nau8822->div_id == NAU8822_CLK_MCLK)
- nau8822_config_clkdiv(dai, 0, params_rate(params));
+ if (nau8822->div_id != NAU8822_CLK_MCLK)
+ div = nau8822->pll.mclk_scaler;
+
+ nau8822_config_clkdiv(dai, div, params_rate(params));
return 0;
}
@@ -940,15 +958,34 @@ static int nau8822_mute(struct snd_soc_dai *dai, int mute, int direction)
static int nau8822_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
+
switch (level) {
case SND_SOC_BIAS_ON:
+ break;
+
case SND_SOC_BIAS_PREPARE:
+ if (nau8822->mclk &&
+ snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_ON) {
+ int ret = clk_prepare_enable(nau8822->mclk);
+
+ if (ret) {
+ dev_err(component->dev,
+ "Failed to enable MCLK: %d\n", ret);
+ return ret;
+ }
+ }
+
snd_soc_component_update_bits(component,
NAU8822_REG_POWER_MANAGEMENT_1,
NAU8822_REFIMP_MASK, NAU8822_REFIMP_80K);
break;
case SND_SOC_BIAS_STANDBY:
+ if (nau8822->mclk &&
+ snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_OFF)
+ clk_disable_unprepare(nau8822->mclk);
+
snd_soc_component_update_bits(component,
NAU8822_REG_POWER_MANAGEMENT_1,
NAU8822_IOBUF_EN | NAU8822_ABIAS_EN,
@@ -1125,6 +1162,11 @@ static int nau8822_i2c_probe(struct i2c_client *i2c)
}
i2c_set_clientdata(i2c, nau8822);
+ nau8822->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+ if (IS_ERR(nau8822->mclk))
+ return dev_err_probe(&i2c->dev, PTR_ERR(nau8822->mclk),
+ "Error getting mclk\n");
+
nau8822->regmap = devm_regmap_init_i2c(i2c, &nau8822_regmap_config);
if (IS_ERR(nau8822->regmap)) {
ret = PTR_ERR(nau8822->regmap);
diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h
index 6ecd46e45923..13fe0a091e9e 100644
--- a/sound/soc/codecs/nau8822.h
+++ b/sound/soc/codecs/nau8822.h
@@ -215,6 +215,7 @@ struct nau8822_pll {
struct nau8822 {
struct device *dev;
struct regmap *regmap;
+ struct clk *mclk;
struct nau8822_pll pll;
int sysclk;
int div_id;
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
index f92b95b21cae..12540397fd4d 100644
--- a/sound/soc/codecs/nau8824.c
+++ b/sound/soc/codecs/nau8824.c
@@ -506,6 +506,7 @@ static int system_clock_control(struct snd_soc_dapm_widget *w,
struct regmap *regmap = nau8824->regmap;
unsigned int value;
bool clk_fll, error;
+ int ret;
if (SND_SOC_DAPM_EVENT_OFF(event)) {
dev_dbg(nau8824->dev, "system clock control : POWER OFF\n");
@@ -520,8 +521,15 @@ static int system_clock_control(struct snd_soc_dapm_widget *w,
} else {
nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0);
}
+
+ clk_disable_unprepare(nau8824->mclk);
} else {
dev_dbg(nau8824->dev, "system clock control : POWER ON\n");
+
+ ret = clk_prepare_enable(nau8824->mclk);
+ if (ret)
+ return ret;
+
/* Check the clock source setting is proper or not
* no matter the source is from FLL or MCLK.
*/
@@ -563,16 +571,21 @@ static int dmic_clock_control(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
int src;
+ unsigned int freq;
+
+ freq = clk_get_rate(nau8824->mclk);
+ if (!freq)
+ freq = nau8824->fs * 256;
/* The DMIC clock is gotten from system clock (256fs) divided by
* DMIC_SRC (1, 2, 4, 8, 16, 32). The clock has to be equal or
* less than 3.072 MHz.
*/
for (src = 0; src < 5; src++) {
- if ((0x1 << (8 - src)) * nau8824->fs <= DMIC_CLK)
+ if (freq / (0x1 << src) <= DMIC_CLK)
break;
}
- dev_dbg(nau8824->dev, "dmic src %d for mclk %d\n", src, nau8824->fs * 256);
+ dev_dbg(nau8824->dev, "dmic src %d for mclk %d\n", src, freq);
regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
NAU8824_CLK_DMIC_SRC_MASK, (src << NAU8824_CLK_DMIC_SRC_SFT));
@@ -1871,6 +1884,10 @@ static int nau8824_read_device_properties(struct device *dev,
if (ret)
nau8824->jack_eject_debounce = 1;
+ nau8824->mclk = devm_clk_get_optional(dev, "mclk");
+ if (IS_ERR(nau8824->mclk))
+ return PTR_ERR(nau8824->mclk);
+
return 0;
}
diff --git a/sound/soc/codecs/nau8824.h b/sound/soc/codecs/nau8824.h
index 5fcfc43dfc85..d8e19515133c 100644
--- a/sound/soc/codecs/nau8824.h
+++ b/sound/soc/codecs/nau8824.h
@@ -434,6 +434,7 @@ struct nau8824 {
struct snd_soc_jack *jack;
struct work_struct jdet_work;
struct semaphore jd_sem;
+ struct clk *mclk;
int fs;
int irq;
int resume_lock;
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index 9d6431338fb7..fac0617ab95b 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -11,7 +11,6 @@
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -563,7 +562,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static u64 pcm3168a_dai_formats[] = {
+static const u64 pcm3168a_dai_formats[] = {
/*
* Select below from Sound Card, not here
* SND_SOC_DAIFMT_CBC_CFC
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c
index 4be476a280e1..92bcf5179779 100644
--- a/sound/soc/codecs/pcm512x-i2c.c
+++ b/sound/soc/codecs/pcm512x-i2c.c
@@ -39,6 +39,7 @@ static const struct i2c_device_id pcm512x_i2c_id[] = {
{ "pcm5122", },
{ "pcm5141", },
{ "pcm5142", },
+ { "pcm5242", },
{ "tas5754", },
{ "tas5756", },
{ }
@@ -51,6 +52,7 @@ static const struct of_device_id pcm512x_of_match[] = {
{ .compatible = "ti,pcm5122", },
{ .compatible = "ti,pcm5141", },
{ .compatible = "ti,pcm5142", },
+ { .compatible = "ti,pcm5242", },
{ .compatible = "ti,tas5754", },
{ .compatible = "ti,tas5756", },
{ }
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c
index 4d29e7196380..6629b862f47d 100644
--- a/sound/soc/codecs/pcm512x-spi.c
+++ b/sound/soc/codecs/pcm512x-spi.c
@@ -36,6 +36,7 @@ static const struct spi_device_id pcm512x_spi_id[] = {
{ "pcm5122", },
{ "pcm5141", },
{ "pcm5142", },
+ { "pcm5242", },
{ },
};
MODULE_DEVICE_TABLE(spi, pcm512x_spi_id);
@@ -45,6 +46,7 @@ static const struct of_device_id pcm512x_of_match[] = {
{ .compatible = "ti,pcm5122", },
{ .compatible = "ti,pcm5141", },
{ .compatible = "ti,pcm5142", },
+ { .compatible = "ti,pcm5242", },
{ }
};
MODULE_DEVICE_TABLE(of, pcm512x_of_match);
diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c
index 86e126783a1d..6641e7c1ddf4 100644
--- a/sound/soc/codecs/pcm6240.c
+++ b/sound/soc/codecs/pcm6240.c
@@ -18,6 +18,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_irq.h>
+#include <linux/of_address.h>
#include <linux/regmap.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -57,12 +58,6 @@ static const char *const pcmdev_ctrl_name[] = {
"%s i2c%d Dev%d Ch%d Fine Volume",
};
-static const char *const pcmdev_ctrl_name_with_prefix[] = {
- "%s Dev%d Ch%d Ana Volume",
- "%s Dev%d Ch%d Digi Volume",
- "%s Dev%d Ch%d Fine Volume",
-};
-
static const struct pcmdevice_mixer_control adc5120_analog_gain_ctl[] = {
{
.shift = 1,
@@ -1365,10 +1360,7 @@ static int pcmdev_gain_ctrl_add(struct pcmdevice_priv *pcm_dev,
name_id = pcmdev_gain_ctl_info[id][ctl_id].pcmdev_ctrl_name_id;
- if (comp->name_prefix)
- ctrl_name = pcmdev_ctrl_name_with_prefix[name_id];
- else
- ctrl_name = pcmdev_ctrl_name[name_id];
+ ctrl_name = pcmdev_ctrl_name[name_id];
for (chn = 1; chn <= nr_chn; chn++) {
name = devm_kzalloc(pcm_dev->dev,
@@ -1377,13 +1369,9 @@ static int pcmdev_gain_ctrl_add(struct pcmdevice_priv *pcm_dev,
ret = -ENOMEM;
goto out;
}
- if (comp->name_prefix)
- scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
- ctrl_name, comp->name_prefix, dev_no, chn);
- else
- scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
- ctrl_name, pcm_dev->upper_dev_name, adap->nr,
- dev_no, chn);
+ scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ ctrl_name, pcm_dev->upper_dev_name, adap->nr,
+ dev_no, chn);
pcmdev_controls[mix_index].tlv.p =
pcmdev_gain_ctl_info[id][ctl_id].gain;
pcmdev_ctrl = devm_kmemdup(pcm_dev->dev,
@@ -1437,13 +1425,8 @@ static int pcmdev_profile_ctrl_add(struct pcmdevice_priv *pcm_dev)
if (!name)
return -ENOMEM;
- if (comp->name_prefix)
- scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
- "%s Profile id", comp->name_prefix);
- else
- scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
- "%s i2c%d Profile id", pcm_dev->upper_dev_name,
- adap->nr);
+ scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ "%s i2c%d Profile id", pcm_dev->upper_dev_name, adap->nr);
pcmdev_ctrl->name = name;
pcmdev_ctrl->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
pcmdev_ctrl->info = pcmdevice_info_profile;
@@ -2081,16 +2064,10 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c)
struct device_node *np;
unsigned int dev_addrs[PCMDEVICE_MAX_I2C_DEVICES];
int ret = 0, i = 0, ndev = 0;
-#ifdef CONFIG_OF
- const __be32 *reg, *reg_end;
- int len, sw, aw;
-#endif
pcm_dev = devm_kzalloc(&i2c->dev, sizeof(*pcm_dev), GFP_KERNEL);
- if (!pcm_dev) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!pcm_dev)
+ return -ENOMEM;
pcm_dev->chip_id = (id != NULL) ? id->driver_data : 0;
@@ -2120,27 +2097,19 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c)
i2c_set_clientdata(i2c, pcm_dev);
mutex_init(&pcm_dev->codec_lock);
np = pcm_dev->dev->of_node;
-#ifdef CONFIG_OF
- aw = of_n_addr_cells(np);
- sw = of_n_size_cells(np);
- if (sw == 0) {
- reg = (const __be32 *)of_get_property(np,
- "reg", &len);
- reg_end = reg + len/sizeof(*reg);
- ndev = 0;
- do {
- dev_addrs[ndev] = of_read_number(reg, aw);
- reg += aw;
- ndev++;
- } while (reg < reg_end);
+
+ if (IS_ENABLED(CONFIG_OF)) {
+ u64 addr;
+
+ for (i = 0; i < PCMDEVICE_MAX_I2C_DEVICES; i++) {
+ if (of_property_read_reg(np, i, &addr, NULL))
+ break;
+ dev_addrs[ndev++] = addr;
+ }
} else {
ndev = 1;
dev_addrs[0] = i2c->addr;
}
-#else
- ndev = 1;
- dev_addrs[0] = i2c->addr;
-#endif
pcm_dev->irq_info.gpio = of_irq_get(np, 0);
for (i = 0; i < ndev; i++)
diff --git a/sound/soc/codecs/peb2466.c b/sound/soc/codecs/peb2466.c
index 5dec69be0acb..76ee7e3f4d9b 100644
--- a/sound/soc/codecs/peb2466.c
+++ b/sound/soc/codecs/peb2466.c
@@ -814,7 +814,7 @@ static int peb2466_dai_startup(struct snd_pcm_substream *substream,
&peb2466_sample_bits_constr);
}
-static u64 peb2466_dai_formats[] = {
+static const u64 peb2466_dai_formats[] = {
SND_SOC_POSSIBLE_DAIFMT_DSP_A |
SND_SOC_POSSIBLE_DAIFMT_DSP_B,
};
diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c
index d4da98469f8b..5fea600bc3a4 100644
--- a/sound/soc/codecs/rk817_codec.c
+++ b/sound/soc/codecs/rk817_codec.c
@@ -10,7 +10,6 @@
#include <linux/mfd/rk808.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <sound/core.h>
diff --git a/sound/soc/codecs/rt1318.c b/sound/soc/codecs/rt1318.c
new file mode 100644
index 000000000000..83b29b441be9
--- /dev/null
+++ b/sound/soc/codecs/rt1318.c
@@ -0,0 +1,1354 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt1318.c -- RT1318 ALSA SoC audio amplifier driver
+// Author: Jack Yu <jack.yu@realtek.com>
+//
+// Copyright(c) 2024 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/acpi.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/rt1318.h>
+
+#include "rt1318.h"
+
+static struct reg_sequence init_list[] = {
+ { 0x0000C000, 0x01},
+ { 0x0000F20D, 0x00},
+ { 0x0000F212, 0x3E},
+ { 0x0000C001, 0x02},
+ { 0x0000C003, 0x22},
+ { 0x0000C004, 0x44},
+ { 0x0000C005, 0x44},
+ { 0x0000C007, 0x64},
+ { 0x0000C00E, 0xE7},
+ { 0x0000F223, 0x7F},
+ { 0x0000F224, 0xDB},
+ { 0x0000F225, 0xEE},
+ { 0x0000F226, 0x3F},
+ { 0x0000F227, 0x0F},
+ { 0x0000F21A, 0x78},
+ { 0x0000F242, 0x3C},
+ { 0x0000C120, 0x40},
+ { 0x0000C125, 0x03},
+ { 0x0000C321, 0x0A},
+ { 0x0000C200, 0xD8},
+ { 0x0000C201, 0x27},
+ { 0x0000C202, 0x0F},
+ { 0x0000C400, 0x0E},
+ { 0x0000C401, 0x43},
+ { 0x0000C402, 0xE0},
+ { 0x0000C403, 0x00},
+ { 0x0000C404, 0x4C},
+ { 0x0000C406, 0x40},
+ { 0x0000C407, 0x02},
+ { 0x0000C408, 0x3F},
+ { 0x0000C300, 0x01},
+ { 0x0000C125, 0x03},
+ { 0x0000DF00, 0x10},
+ { 0x0000F20B, 0x2A},
+ { 0x0000DF5F, 0x01},
+ { 0x0000DF60, 0xA7},
+ { 0x0000C203, 0x84},
+ { 0x0000C206, 0x78},
+ { 0x0000F10A, 0x09},
+ { 0x0000F10B, 0x4C},
+ { 0x0000F104, 0xF4},
+ { 0x0000F105, 0x03},
+ { 0x0000F109, 0xE0},
+ { 0x0000F10B, 0x5C},
+ { 0x0000F104, 0xF4},
+ { 0x0000F105, 0x04},
+ { 0x0000F109, 0x65},
+ { 0x0000F10B, 0x5C},
+ { 0x0000F104, 0xF4},
+ { 0x0000F105, 0x02},
+ { 0x0000F109, 0x30},
+ { 0x0000F10B, 0x5C},
+ { 0x0000E706, 0x0F},
+ { 0x0000E707, 0x30},
+ { 0x0000E806, 0x0F},
+ { 0x0000E807, 0x30},
+ { 0x0000CE04, 0x03},
+ { 0x0000CE05, 0x5F},
+ { 0x0000CE06, 0xA2},
+ { 0x0000CE07, 0x6B},
+ { 0x0000CF04, 0x03},
+ { 0x0000CF05, 0x5F},
+ { 0x0000CF06, 0xA2},
+ { 0x0000CF07, 0x6B},
+ { 0x0000CE60, 0xE3},
+ { 0x0000C130, 0x51},
+ { 0x0000E000, 0xA8},
+ { 0x0000F102, 0x00},
+ { 0x0000F103, 0x00},
+ { 0x0000F104, 0xF5},
+ { 0x0000F105, 0x23},
+ { 0x0000F109, 0x04},
+ { 0x0000F10A, 0x0B},
+ { 0x0000F10B, 0x4C},
+ { 0x0000F10B, 0x5C},
+ { 0x41001888, 0x00},
+ { 0x0000C121, 0x0B},
+ { 0x0000F102, 0x00},
+ { 0x0000F103, 0x00},
+ { 0x0000F104, 0xF5},
+ { 0x0000F105, 0x23},
+ { 0x0000F109, 0x00},
+ { 0x0000F10A, 0x0B},
+ { 0x0000F10B, 0x4C},
+ { 0x0000F10B, 0x5C},
+ { 0x0000F800, 0x20},
+ { 0x0000CA00, 0x80},
+ { 0x0000CA10, 0x00},
+ { 0x0000CA02, 0x78},
+ { 0x0000CA12, 0x78},
+ { 0x0000ED00, 0x90},
+ { 0x0000E604, 0x00},
+ { 0x0000DB00, 0x0C},
+ { 0x0000DD00, 0x0C},
+ { 0x0000DC19, 0x00},
+ { 0x0000DC1A, 0x6A},
+ { 0x0000DC1B, 0xAA},
+ { 0x0000DC1C, 0xAB},
+ { 0x0000DC1D, 0x00},
+ { 0x0000DC1E, 0x16},
+ { 0x0000DC1F, 0xDB},
+ { 0x0000DC20, 0x6D},
+ { 0x0000DE19, 0x00},
+ { 0x0000DE1A, 0x6A},
+ { 0x0000DE1B, 0xAA},
+ { 0x0000DE1C, 0xAB},
+ { 0x0000DE1D, 0x00},
+ { 0x0000DE1E, 0x16},
+ { 0x0000DE1F, 0xDB},
+ { 0x0000DE20, 0x6D},
+ { 0x0000DB32, 0x00},
+ { 0x0000DD32, 0x00},
+ { 0x0000DB33, 0x0A},
+ { 0x0000DD33, 0x0A},
+ { 0x0000DB34, 0x1A},
+ { 0x0000DD34, 0x1A},
+ { 0x0000DB15, 0xEF},
+ { 0x0000DD15, 0xEF},
+ { 0x0000DB17, 0xEF},
+ { 0x0000DD17, 0xEF},
+ { 0x0000DB94, 0x70},
+ { 0x0000DD94, 0x70},
+ { 0x0000DB19, 0x40},
+ { 0x0000DD19, 0x40},
+ { 0x0000DB12, 0xC0},
+ { 0x0000DD12, 0xC0},
+ { 0x0000DB00, 0x4C},
+ { 0x0000DB04, 0x05},
+ { 0x0000DB05, 0x03},
+ { 0x0000DD04, 0x05},
+ { 0x0000DD05, 0x03},
+ { 0x0000DBBB, 0x09},
+ { 0x0000DBBC, 0x30},
+ { 0x0000DBBD, 0xF0},
+ { 0x0000DBBE, 0xF1},
+ { 0x0000DDBB, 0x09},
+ { 0x0000DDBC, 0x30},
+ { 0x0000DDBD, 0xF0},
+ { 0x0000DDBE, 0xF1},
+ { 0x0000DB01, 0x79},
+ { 0x0000DD01, 0x79},
+ { 0x0000DB08, 0x40},
+ { 0x0000DD08, 0x40},
+ { 0x0000DC52, 0xEF},
+ { 0x0000DE52, 0xEF},
+ { 0x0000DB00, 0xCC},
+ { 0x0000CC2C, 0x00},
+ { 0x0000CC2D, 0x2A},
+ { 0x0000CC2E, 0x83},
+ { 0x0000CC2F, 0xA8},
+ { 0x0000CD2C, 0x00},
+ { 0x0000CD2D, 0x2A},
+ { 0x0000CD2E, 0x83},
+ { 0x0000CD2F, 0xA8},
+ { 0x0000CC24, 0x00},
+ { 0x0000CC25, 0x51},
+ { 0x0000CC26, 0xEB},
+ { 0x0000CC27, 0x85},
+ { 0x0000CD24, 0x00},
+ { 0x0000CD25, 0x51},
+ { 0x0000CD26, 0xEB},
+ { 0x0000CD27, 0x85},
+ { 0x0000CC20, 0x00},
+ { 0x0000CC21, 0x00},
+ { 0x0000CC22, 0x43},
+ { 0x0000CD20, 0x00},
+ { 0x0000CD21, 0x00},
+ { 0x0000CD22, 0x43},
+ { 0x0000CC16, 0x0F},
+ { 0x0000CC17, 0x00},
+ { 0x0000CD16, 0x0F},
+ { 0x0000CD17, 0x00},
+ { 0x0000CC29, 0x5D},
+ { 0x0000CC2A, 0xC0},
+ { 0x0000CD29, 0x5D},
+ { 0x0000CD2A, 0xC0},
+ { 0x0000CC31, 0x20},
+ { 0x0000CC32, 0x00},
+ { 0x0000CC33, 0x00},
+ { 0x0000CC34, 0x00},
+ { 0x0000CD31, 0x20},
+ { 0x0000CD32, 0x00},
+ { 0x0000CD33, 0x00},
+ { 0x0000CD34, 0x00},
+ { 0x0000CC36, 0x79},
+ { 0x0000CC37, 0x99},
+ { 0x0000CC38, 0x99},
+ { 0x0000CC39, 0x99},
+ { 0x0000CD36, 0x79},
+ { 0x0000CD37, 0x99},
+ { 0x0000CD38, 0x99},
+ { 0x0000CD39, 0x99},
+ { 0x0000CC09, 0x00},
+ { 0x0000CC0A, 0x07},
+ { 0x0000CC0B, 0x5F},
+ { 0x0000CC0C, 0x6F},
+ { 0x0000CD09, 0x00},
+ { 0x0000CD0A, 0x07},
+ { 0x0000CD0B, 0x5F},
+ { 0x0000CD0C, 0x6F},
+ { 0x0000CC0E, 0x00},
+ { 0x0000CC0F, 0x03},
+ { 0x0000CC10, 0xAF},
+ { 0x0000CC11, 0xB7},
+ { 0x0000CD0E, 0x00},
+ { 0x0000CD0F, 0x03},
+ { 0x0000CD10, 0xAF},
+ { 0x0000CD11, 0xB7},
+ { 0x0000CCD6, 0x00},
+ { 0x0000CCD7, 0x03},
+ { 0x0000CDD6, 0x00},
+ { 0x0000CDD7, 0x03},
+ { 0x0000CCD8, 0x00},
+ { 0x0000CCD9, 0x03},
+ { 0x0000CDD8, 0x00},
+ { 0x0000CDD9, 0x03},
+ { 0x0000CCDA, 0x00},
+ { 0x0000CCDB, 0x03},
+ { 0x0000CDDA, 0x00},
+ { 0x0000CDDB, 0x03},
+ { 0x0000C320, 0x20},
+ { 0x0000C203, 0x9C},
+};
+#define rt1318_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+static const struct reg_default rt1318_reg[] = {
+ { 0xc000, 0x00 },
+ { 0xc001, 0x43 },
+ { 0xc003, 0x22 },
+ { 0xc004, 0x44 },
+ { 0xc005, 0x44 },
+ { 0xc006, 0x33 },
+ { 0xc007, 0x64 },
+ { 0xc008, 0x05 },
+ { 0xc00a, 0xfc },
+ { 0xc00b, 0x0f },
+ { 0xc00c, 0x0e },
+ { 0xc00d, 0xef },
+ { 0xc00e, 0xe5 },
+ { 0xc00f, 0xff },
+ { 0xc120, 0xc0 },
+ { 0xc121, 0x00 },
+ { 0xc122, 0x00 },
+ { 0xc123, 0x14 },
+ { 0xc125, 0x00 },
+ { 0xc130, 0x59 },
+ { 0xc200, 0x00 },
+ { 0xc201, 0x00 },
+ { 0xc202, 0x00 },
+ { 0xc203, 0x04 },
+ { 0xc204, 0x00 },
+ { 0xc205, 0x00 },
+ { 0xc206, 0x68 },
+ { 0xc207, 0x70 },
+ { 0xc208, 0x00 },
+ { 0xc20a, 0x00 },
+ { 0xc20b, 0x01 },
+ { 0xc20c, 0x7f },
+ { 0xc20d, 0x01 },
+ { 0xc20e, 0x7f },
+ { 0xc300, 0x00 },
+ { 0xc301, 0x00 },
+ { 0xc303, 0x80 },
+ { 0xc320, 0x00 },
+ { 0xc321, 0x09 },
+ { 0xc322, 0x02 },
+ { 0xc400, 0x00 },
+ { 0xc401, 0x00 },
+ { 0xc402, 0x00 },
+ { 0xc403, 0x00 },
+ { 0xc404, 0x00 },
+ { 0xc405, 0x00 },
+ { 0xc406, 0x00 },
+ { 0xc407, 0x00 },
+ { 0xc408, 0x00 },
+ { 0xc410, 0x04 },
+ { 0xc430, 0x00 },
+ { 0xc431, 0x00 },
+ { 0xca00, 0x10 },
+ { 0xca01, 0x00 },
+ { 0xca02, 0x0b },
+ { 0xca10, 0x10 },
+ { 0xca11, 0x00 },
+ { 0xca12, 0x0b },
+ { 0xce04, 0x08 },
+ { 0xce05, 0x00 },
+ { 0xce06, 0x00 },
+ { 0xce07, 0x00 },
+ { 0xce60, 0x63 },
+ { 0xcf04, 0x08 },
+ { 0xcf05, 0x00 },
+ { 0xcf06, 0x00 },
+ { 0xcf07, 0x00 },
+ { 0xdb00, 0x00 },
+ { 0xdb08, 0x40 },
+ { 0xdb12, 0x00 },
+ { 0xdb35, 0x00 },
+ { 0xdbb5, 0x00 },
+ { 0xdbb6, 0x40 },
+ { 0xdbb7, 0x00 },
+ { 0xdbb8, 0x00 },
+ { 0xdbc5, 0x00 },
+ { 0xdbc6, 0x00 },
+ { 0xdbc7, 0x00 },
+ { 0xdbc8, 0x00 },
+ { 0xdd08, 0x40 },
+ { 0xdd12, 0x00 },
+ { 0xdd35, 0x00 },
+ { 0xddb5, 0x00 },
+ { 0xddb6, 0x40 },
+ { 0xddb7, 0x00 },
+ { 0xddb8, 0x00 },
+ { 0xddc5, 0x00 },
+ { 0xddc6, 0x00 },
+ { 0xddc7, 0x00 },
+ { 0xddc8, 0x00 },
+ { 0xdd93, 0x00 },
+ { 0xdd94, 0x64 },
+ { 0xdf00, 0x00 },
+ { 0xdf5f, 0x00 },
+ { 0xdf60, 0x00 },
+ { 0xe000, 0x08 },
+ { 0xe300, 0xa0 },
+ { 0xe400, 0x22 },
+ { 0xe706, 0x2f },
+ { 0xe707, 0x2f },
+ { 0xe806, 0x2f },
+ { 0xe807, 0x2f },
+ { 0xea00, 0x43 },
+ { 0xed00, 0x80 },
+ { 0xed01, 0x0f },
+ { 0xed02, 0xff },
+ { 0xed03, 0x00 },
+ { 0xed04, 0x00 },
+ { 0xed05, 0x0f },
+ { 0xed06, 0xff },
+ { 0xf010, 0x10 },
+ { 0xf011, 0xec },
+ { 0xf012, 0x68 },
+ { 0xf013, 0x21 },
+ { 0xf102, 0x00 },
+ { 0xf103, 0x00 },
+ { 0xf104, 0x00 },
+ { 0xf105, 0x00 },
+ { 0xf106, 0x00 },
+ { 0xf107, 0x00 },
+ { 0xf108, 0x00 },
+ { 0xf109, 0x00 },
+ { 0xf10a, 0x03 },
+ { 0xf10b, 0x40 },
+ { 0xf20b, 0x28 },
+ { 0xf20d, 0x00 },
+ { 0xf212, 0x00 },
+ { 0xf21a, 0x00 },
+ { 0xf223, 0x40 },
+ { 0xf224, 0x00 },
+ { 0xf225, 0x00 },
+ { 0xf226, 0x00 },
+ { 0xf227, 0x00 },
+ { 0xf242, 0x0c },
+ { 0xf800, 0x00 },
+ { 0xf801, 0x12 },
+ { 0xf802, 0xe0 },
+ { 0xf803, 0x2f },
+ { 0xf804, 0x00 },
+ { 0xf805, 0x00 },
+ { 0xf806, 0x07 },
+ { 0xf807, 0xff },
+};
+
+static bool rt1318_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0xc000:
+ case 0xc301:
+ case 0xc410:
+ case 0xc430 ... 0xc431:
+ case 0xdb06:
+ case 0xdb12:
+ case 0xdb1d ... 0xdb1f:
+ case 0xdb35:
+ case 0xdb37:
+ case 0xdb8a ... 0xdb92:
+ case 0xdbc5 ... 0xdbc8:
+ case 0xdc2b ... 0xdc49:
+ case 0xdd0b:
+ case 0xdd12:
+ case 0xdd1d ... 0xdd1f:
+ case 0xdd35:
+ case 0xdd8a ... 0xdd92:
+ case 0xddc5 ... 0xddc8:
+ case 0xde2b ... 0xde44:
+ case 0xdf4a ... 0xdf55:
+ case 0xe224 ... 0xe23b:
+ case 0xea01:
+ case 0xebc5:
+ case 0xebc8:
+ case 0xebcb ... 0xebcc:
+ case 0xed03 ... 0xed06:
+ case 0xf010 ... 0xf014:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool rt1318_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0xc000 ... 0xc00f:
+ case 0xc120 ... 0xc130:
+ case 0xc200 ... 0xc20e:
+ case 0xc300 ... 0xc303:
+ case 0xc320 ... 0xc322:
+ case 0xc400 ... 0xc408:
+ case 0xc430 ... 0xc431:
+ case 0xca00 ... 0xca02:
+ case 0xca10 ... 0xca12:
+ case 0xcb00 ... 0xcb0b:
+ case 0xcc00 ... 0xcce5:
+ case 0xcd00 ... 0xcde5:
+ case 0xce00 ... 0xce6a:
+ case 0xcf00 ... 0xcf53:
+ case 0xd000 ... 0xd0cc:
+ case 0xd100 ... 0xd1b9:
+ case 0xdb00 ... 0xdc53:
+ case 0xdd00 ... 0xde53:
+ case 0xdf00 ... 0xdf6b:
+ case 0xe000:
+ case 0xe300:
+ case 0xe400:
+ case 0xe706 ... 0xe707:
+ case 0xe806 ... 0xe807:
+ case 0xea00:
+ case 0xeb00 ... 0xebcc:
+ case 0xec00 ... 0xecb9:
+ case 0xed00 ... 0xed06:
+ case 0xf010 ... 0xf014:
+ case 0xf102 ... 0xf10b:
+ case 0xf20b:
+ case 0xf20d ... 0xf242:
+ case 0xf800 ... 0xf807:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int rt1318_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_update_bits(rt1318->regmap, RT1318_PWR_STA1,
+ RT1318_PDB_CTRL_MASK, RT1318_PDB_CTRL_HIGH);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(rt1318->regmap, RT1318_PWR_STA1,
+ RT1318_PDB_CTRL_MASK, RT1318_PDB_CTRL_LOW);
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int rt1318_dvol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ rt1318->rt1318_dvol = ucontrol->value.integer.value[0];
+
+ if (rt1318->rt1318_dvol <= RT1318_DVOL_STEP && rt1318->rt1318_dvol >= 0) {
+ regmap_write(rt1318->regmap, RT1318_DA_VOL_L_8,
+ rt1318->rt1318_dvol >> 8);
+ regmap_write(rt1318->regmap, RT1318_DA_VOL_L_1_7,
+ rt1318->rt1318_dvol & 0xff);
+ regmap_write(rt1318->regmap, RT1318_DA_VOL_R_8,
+ rt1318->rt1318_dvol >> 8);
+ regmap_write(rt1318->regmap, RT1318_DA_VOL_R_1_7,
+ rt1318->rt1318_dvol & 0xff);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int rt1318_dvol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = rt1318->rt1318_dvol;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new rt1318_snd_controls[] = {
+ SOC_SINGLE_EXT("Amp Playback Volume", SND_SOC_NOPM, 0, 383, 0,
+ rt1318_dvol_get, rt1318_dvol_put),
+};
+
+static const struct snd_soc_dapm_widget rt1318_dapm_widgets[] = {
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ /* DACs */
+ SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0,
+ rt1318_dac_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ /* Output Lines */
+ SND_SOC_DAPM_OUTPUT("Amp"),
+};
+
+static const struct snd_soc_dapm_route rt1318_dapm_routes[] = {
+ {"DAC", NULL, "AIF1RX"},
+ {"Amp", NULL, "DAC"},
+};
+
+static int rt1318_get_clk_info(int sclk, int rate)
+{
+ int i, pd[] = {1, 2, 4, 8, 16, 24};
+
+ if (sclk <= 0 || rate <= 0)
+ return -EINVAL;
+
+ rate = rate << 8;
+ for (i = 0; i < ARRAY_SIZE(pd); i++)
+ if (sclk == rate * pd[i])
+ return i;
+
+ return -EINVAL;
+}
+
+static int rt1318_clk_ip_info(struct snd_soc_component *component, int lrclk)
+{
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ switch (lrclk) {
+ case RT1318_LRCLK_48000:
+ case RT1318_LRCLK_44100:
+ case RT1318_LRCLK_16000:
+ regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON,
+ RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK,
+ RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON4);
+ break;
+ case RT1318_LRCLK_96000:
+ regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON,
+ RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK,
+ RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON2);
+ break;
+ case RT1318_LRCLK_192000:
+ regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON,
+ RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK,
+ RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON1);
+ break;
+ default:
+ dev_err(component->dev, "Unsupported clock rate.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rt1318_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+ int data_len = 0, ch_len = 0;
+ int pre_div, ret;
+
+ rt1318->lrck = params_rate(params);
+ pre_div = rt1318_get_clk_info(rt1318->sysclk, rt1318->lrck);
+ if (pre_div < 0) {
+ dev_err(component->dev, "Unsupported clock setting\n");
+ return -EINVAL;
+ }
+ ret = rt1318_clk_ip_info(component, rt1318->lrck);
+ if (ret < 0) {
+ dev_err(component->dev, "Unsupported clock setting\n");
+ return -EINVAL;
+ }
+
+ switch (params_width(params)) {
+ case 16:
+ break;
+ case 20:
+ data_len = RT1318_I2S_DL_20;
+ ch_len = RT1318_I2S_DL_20;
+ break;
+ case 24:
+ data_len = RT1318_I2S_DL_24;
+ ch_len = RT1318_I2S_DL_24;
+ break;
+ case 32:
+ data_len = RT1318_I2S_DL_32;
+ ch_len = RT1318_I2S_DL_32;
+ break;
+ case 8:
+ data_len = RT1318_I2S_DL_8;
+ ch_len = RT1318_I2S_DL_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(rt1318->regmap, RT1318_CLK2,
+ RT1318_DIV_AP_MASK | RT1318_DIV_DAMOD_MASK,
+ pre_div << RT1318_DIV_AP_SFT |
+ pre_div << RT1318_DIV_DAMOD_SFT);
+ regmap_update_bits(rt1318->regmap, RT1318_CLK3,
+ RT1318_AD_STO1_MASK | RT1318_AD_STO2_MASK,
+ pre_div << RT1318_AD_STO1_SFT |
+ pre_div << RT1318_AD_STO2_SFT);
+ regmap_update_bits(rt1318->regmap, RT1318_CLK4,
+ RT1318_AD_ANA_STO1_MASK | RT1318_AD_ANA_STO2_MASK,
+ pre_div << RT1318_AD_ANA_STO1_SFT |
+ pre_div << RT1318_AD_ANA_STO2_SFT);
+ regmap_update_bits(rt1318->regmap, RT1318_CLK5,
+ RT1318_DIV_FIFO_IN_MASK | RT1318_DIV_FIFO_OUT_MASK,
+ pre_div << RT1318_DIV_FIFO_IN_SFT |
+ pre_div << RT1318_DIV_FIFO_OUT_SFT);
+ regmap_update_bits(rt1318->regmap, RT1318_CLK6,
+ RT1318_DIV_NLMS_MASK | RT1318_DIV_AD_MONO_MASK |
+ RT1318_DIV_POST_G_MASK, pre_div << RT1318_DIV_NLMS_SFT |
+ pre_div << RT1318_DIV_AD_MONO_SFT |
+ pre_div << RT1318_DIV_POST_G_SFT);
+
+ regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL2,
+ RT1318_I2S_DL_MASK, data_len << RT1318_I2S_DL_SFT);
+ regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL3,
+ RT1318_I2S_TX_CHL_MASK | RT1318_I2S_RX_CHL_MASK,
+ ch_len << RT1318_I2S_TX_CHL_SFT |
+ ch_len << RT1318_I2S_RX_CHL_SFT);
+
+ return 0;
+}
+
+static int rt1318_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+ unsigned int reg_val = 0, reg_val2 = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg_val2 |= RT1318_TDM_BCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg_val |= RT1318_FMT_LEFT_J;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_A:
+ reg_val |= RT1318_FMT_PCM_A_R;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_B:
+ reg_val |= RT1318_FMT_PCM_B_R;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL1,
+ RT1318_I2S_FMT_MASK, reg_val);
+ regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL1,
+ RT1318_TDM_BCLK_MASK, reg_val2);
+
+ return 0;
+}
+
+static int rt1318_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+ int reg_val = 0;
+
+ if (freq == rt1318->sysclk && clk_id == rt1318->sysclk_src)
+ return 0;
+
+ switch (clk_id) {
+ case RT1318_SCLK_S_BCLK:
+ reg_val |= RT1318_SYSCLK_BCLK;
+ break;
+ case RT1318_SCLK_S_SDW:
+ reg_val |= RT1318_SYSCLK_SDW;
+ break;
+ case RT1318_SCLK_S_PLL2F:
+ reg_val |= RT1318_SYSCLK_PLL2F;
+ break;
+ case RT1318_SCLK_S_PLL2B:
+ reg_val |= RT1318_SYSCLK_PLL2B;
+ break;
+ case RT1318_SCLK_S_MCLK:
+ reg_val |= RT1318_SYSCLK_MCLK;
+ break;
+ case RT1318_SCLK_S_RC0:
+ reg_val |= RT1318_SYSCLK_RC1;
+ break;
+ case RT1318_SCLK_S_RC1:
+ reg_val |= RT1318_SYSCLK_RC2;
+ break;
+ case RT1318_SCLK_S_RC2:
+ reg_val |= RT1318_SYSCLK_RC3;
+ break;
+ default:
+ dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+ return -EINVAL;
+ }
+
+ rt1318->sysclk = freq;
+ rt1318->sysclk_src = clk_id;
+ dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_SYSCLK_SEL_MASK, reg_val);
+
+ return 0;
+}
+
+static const struct pll_calc_map pll_preset_table[] = {
+ {512000, 4096000, 22, 190, 0, true, false},
+ {1024000, 4096000, 22, 94, 0, true, false},
+ {1024000, 16384000, 4, 190, 0, true, false},
+ {1411200, 11289600, 6, 62, 0, true, false},
+ {1536000, 12288000, 6, 62, 0, true, false},
+ {2822400, 11289600, 6, 62, 0, true, false},
+ {2822400, 45158400, 0, 62, 0, true, false},
+ {2822400, 49152000, 0, 62, 0, true, false},
+ {3072000, 12288000, 6, 62, 0, true, false},
+ {3072000, 24576000, 2, 62, 0, true, false},
+ {3072000, 49152000, 0, 62, 0, true, false},
+ {6144000, 24576000, 2, 94, 4, false, false},
+ {6144000, 49152000, 0, 30, 0, true, false},
+ {6144000, 98304000, 0, 94, 4, false, true},
+ {12288000, 49152000, 0, 62, 6, false, false},
+};
+
+static int rt1318_pll_calc(const unsigned int freq_in,
+ const unsigned int freq_out, struct rt1318_pll_code *pll_code)
+{
+ int max_n = RT1318_PLL_N_MAX, max_m = RT1318_PLL_M_MAX;
+ int i, k, red, n_t, pll_out, in_t, out_t;
+ int n = 0, m = 0, m_t = 0;
+ int red_t = abs(freq_out - freq_in);
+ bool m_bypass = false, k_bypass = false;
+
+ if (RT1318_PLL_INP_MAX < freq_in || RT1318_PLL_INP_MIN > freq_in)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(pll_preset_table); i++) {
+ if (freq_in == pll_preset_table[i].pll_in &&
+ freq_out == pll_preset_table[i].pll_out) {
+ k = pll_preset_table[i].k;
+ m = pll_preset_table[i].m;
+ n = pll_preset_table[i].n;
+ m_bypass = pll_preset_table[i].m_bp;
+ k_bypass = pll_preset_table[i].k_bp;
+ goto code_find;
+ }
+ }
+
+ k = 100000000 / freq_out - 2;
+ if (k > RT1318_PLL_K_MAX)
+ k = RT1318_PLL_K_MAX;
+ if (k < 0) {
+ k = 0;
+ k_bypass = true;
+ }
+ for (n_t = 0; n_t <= max_n; n_t++) {
+ in_t = freq_in / (k_bypass ? 1 : (k + 2));
+ pll_out = freq_out / (n_t + 2);
+ if (in_t < 0)
+ continue;
+ if (in_t == pll_out) {
+ m_bypass = true;
+ n = n_t;
+ goto code_find;
+ }
+ red = abs(in_t - pll_out);
+ if (red < red_t) {
+ m_bypass = true;
+ n = n_t;
+ m = m_t;
+ if (red == 0)
+ goto code_find;
+ red_t = red;
+ }
+ for (m_t = 0; m_t <= max_m; m_t++) {
+ out_t = in_t / (m_t + 2);
+ red = abs(out_t - pll_out);
+ if (red < red_t) {
+ m_bypass = false;
+ n = n_t;
+ m = m_t;
+ if (red == 0)
+ goto code_find;
+ red_t = red;
+ }
+ }
+ }
+ pr_debug("Only get approximation about PLL\n");
+
+code_find:
+
+ pll_code->m_bp = m_bypass;
+ pll_code->k_bp = k_bypass;
+ pll_code->m_code = m;
+ pll_code->n_code = n;
+ pll_code->k_code = k;
+ return 0;
+}
+
+static int rt1318_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+ struct rt1318_pll_code pll_code;
+ int ret;
+
+ if (!freq_in || !freq_out) {
+ dev_dbg(component->dev, "PLL disabled\n");
+ rt1318->pll_in = 0;
+ rt1318->pll_out = 0;
+ return 0;
+ }
+
+ if (source == rt1318->pll_src && freq_in == rt1318->pll_in &&
+ freq_out == rt1318->pll_out)
+ return 0;
+
+ switch (source) {
+ case RT1318_PLL_S_BCLK0:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_BCLK0);
+ break;
+ case RT1318_PLL_S_BCLK1:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_BCLK1);
+ break;
+ case RT1318_PLL_S_RC:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_RC);
+ break;
+ case RT1318_PLL_S_MCLK:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_MCLK);
+ break;
+ case RT1318_PLL_S_SDW_IN_PLL:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_SDW1);
+ break;
+ case RT1318_PLL_S_SDW_0:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_SDW2);
+ break;
+ case RT1318_PLL_S_SDW_1:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_SDW3);
+ break;
+ case RT1318_PLL_S_SDW_2:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_SDW4);
+ break;
+ default:
+ dev_err(component->dev, "Unknown PLL source %d\n", source);
+ return -EINVAL;
+ }
+
+ ret = rt1318_pll_calc(freq_in, freq_out, &pll_code);
+ if (ret < 0) {
+ dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+ return ret;
+ }
+
+ dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+ pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+ pll_code.n_code, pll_code.k_code);
+
+ regmap_update_bits(rt1318->regmap, RT1318_PLL1_K,
+ RT1318_K_PLL1_MASK, pll_code.k_code);
+ regmap_update_bits(rt1318->regmap, RT1318_PLL1_M,
+ RT1318_M_PLL1_MASK, (pll_code.m_bp ? 0 : pll_code.m_code));
+ regmap_update_bits(rt1318->regmap, RT1318_PLL1_N_8,
+ RT1318_N_8_PLL1_MASK, pll_code.n_code >> 8);
+ regmap_update_bits(rt1318->regmap, RT1318_PLL1_N_7_0,
+ RT1318_N_7_0_PLL1_MASK, pll_code.n_code);
+
+ rt1318->pll_in = freq_in;
+ rt1318->pll_out = freq_out;
+ rt1318->pll_src = source;
+
+ return 0;
+}
+
+static int rt1318_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 rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+ unsigned int cn = 0, cl = 0, rx_slotnum;
+ int ret = 0, first_bit;
+
+ switch (slots) {
+ case 4:
+ cn |= RT1318_I2S_CH_TX_4CH;
+ cn |= RT1318_I2S_CH_RX_4CH;
+ break;
+ case 6:
+ cn |= RT1318_I2S_CH_TX_6CH;
+ cn |= RT1318_I2S_CH_RX_6CH;
+ break;
+ case 8:
+ cn |= RT1318_I2S_CH_TX_8CH;
+ cn |= RT1318_I2S_CH_RX_8CH;
+ break;
+ case 2:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (slot_width) {
+ case 20:
+ cl |= RT1318_I2S_TX_CHL_20;
+ cl |= RT1318_I2S_RX_CHL_20;
+ break;
+ case 24:
+ cl |= RT1318_I2S_TX_CHL_24;
+ cl |= RT1318_I2S_RX_CHL_24;
+ break;
+ case 32:
+ cl |= RT1318_I2S_TX_CHL_32;
+ cl |= RT1318_I2S_RX_CHL_32;
+ break;
+ case 8:
+ cl |= RT1318_I2S_TX_CHL_8;
+ cl |= RT1318_I2S_RX_CHL_8;
+ break;
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Rx slot configuration */
+ rx_slotnum = hweight_long(rx_mask);
+ if (rx_slotnum != 1) {
+ ret = -EINVAL;
+ dev_err(component->dev, "too many rx slots or zero slot\n");
+ goto _set_tdm_err_;
+ }
+
+ first_bit = __ffs(rx_mask);
+ switch (first_bit) {
+ case 0:
+ case 2:
+ case 4:
+ case 6:
+ regmap_update_bits(rt1318->regmap,
+ RT1318_TDM_CTRL9,
+ RT1318_TDM_I2S_TX_L_DAC1_1_MASK |
+ RT1318_TDM_I2S_TX_R_DAC1_1_MASK,
+ (first_bit << RT1318_TDM_I2S_TX_L_DAC1_1_SFT) |
+ ((first_bit + 1) << RT1318_TDM_I2S_TX_R_DAC1_1_SFT));
+ break;
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ regmap_update_bits(rt1318->regmap,
+ RT1318_TDM_CTRL9,
+ RT1318_TDM_I2S_TX_L_DAC1_1_MASK |
+ RT1318_TDM_I2S_TX_R_DAC1_1_MASK,
+ ((first_bit - 1) << RT1318_TDM_I2S_TX_L_DAC1_1_SFT) |
+ (first_bit << RT1318_TDM_I2S_TX_R_DAC1_1_SFT));
+ break;
+ default:
+ ret = -EINVAL;
+ goto _set_tdm_err_;
+ }
+
+ regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL2,
+ RT1318_I2S_CH_TX_MASK | RT1318_I2S_CH_RX_MASK, cn);
+ regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL3,
+ RT1318_I2S_TX_CHL_MASK | RT1318_I2S_RX_CHL_MASK, cl);
+
+_set_tdm_err_:
+ return ret;
+}
+
+static int rt1318_probe(struct snd_soc_component *component)
+{
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ rt1318->component = component;
+
+ schedule_work(&rt1318->cali_work);
+ rt1318->rt1318_dvol = RT1318_DVOL_STEP;
+
+ return 0;
+}
+
+static void rt1318_remove(struct snd_soc_component *component)
+{
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ cancel_work_sync(&rt1318->cali_work);
+}
+
+#ifdef CONFIG_PM
+static int rt1318_suspend(struct snd_soc_component *component)
+{
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(rt1318->regmap, true);
+ regcache_mark_dirty(rt1318->regmap);
+ return 0;
+}
+
+static int rt1318_resume(struct snd_soc_component *component)
+{
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(rt1318->regmap, false);
+ regcache_sync(rt1318->regmap);
+ return 0;
+}
+#else
+#define rt1318_suspend NULL
+#define rt1318_resume NULL
+#endif
+
+#define RT1318_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT1318_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt1318_aif_dai_ops = {
+ .hw_params = rt1318_hw_params,
+ .set_fmt = rt1318_set_dai_fmt,
+ .set_sysclk = rt1318_set_dai_sysclk,
+ .set_pll = rt1318_set_dai_pll,
+ .set_tdm_slot = rt1318_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver rt1318_dai[] = {
+ {
+ .name = "rt1318-aif",
+ .id = 0,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT1318_STEREO_RATES,
+ .formats = RT1318_FORMATS,
+ },
+ .ops = &rt1318_aif_dai_ops,
+ }
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt1318 = {
+ .probe = rt1318_probe,
+ .remove = rt1318_remove,
+ .suspend = rt1318_suspend,
+ .resume = rt1318_resume,
+ .controls = rt1318_snd_controls,
+ .num_controls = ARRAY_SIZE(rt1318_snd_controls),
+ .dapm_widgets = rt1318_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt1318_dapm_widgets),
+ .dapm_routes = rt1318_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt1318_dapm_routes),
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static const struct regmap_config rt1318_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt1318_readable_register,
+ .volatile_reg = rt1318_volatile_register,
+ .max_register = 0x41001888,
+ .reg_defaults = rt1318_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt1318_reg),
+ .cache_type = REGCACHE_RBTREE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static const struct i2c_device_id rt1318_i2c_id[] = {
+ { "rt1318" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rt1318_i2c_id);
+
+static const struct of_device_id rt1318_of_match[] = {
+ { .compatible = "realtek,rt1318", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt1318_of_match);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt1318_acpi_match[] = {
+ { "10EC1318", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, rt1318_acpi_match);
+#endif
+
+static int rt1318_parse_dt(struct rt1318_priv *rt1318, struct device *dev)
+{
+ device_property_read_u32(dev, "realtek,r0_l",
+ &rt1318->pdata.init_r0_l);
+ device_property_read_u32(dev, "realtek,r0_r",
+ &rt1318->pdata.init_r0_r);
+
+ return 0;
+}
+
+static void rt1318_calibration_sequence(struct rt1318_priv *rt1318)
+{
+ regmap_write(rt1318->regmap, RT1318_CLK1, 0x22);
+ regmap_write(rt1318->regmap, RT1318_PLL1_N_7_0, 0x06);
+ regmap_write(rt1318->regmap, RT1318_STP_TEMP_L, 0xCC);
+ regmap_write(rt1318->regmap, RT1318_STP_SEL_L, 0x40);
+ regmap_write(rt1318->regmap, RT1318_STP_SEL_R, 0x40);
+ regmap_write(rt1318->regmap, RT1318_SINE_GEN0, 0x20);
+ regmap_write(rt1318->regmap, RT1318_SPK_VOL_TH, 0x00);
+ regmap_write(rt1318->regmap, RT1318_FEEDBACK_PATH, 0x0B);
+ regmap_write(rt1318->regmap, RT1318_TCON, 0x1C);
+ regmap_write(rt1318->regmap, RT1318_TCON_RELATE, 0x58);
+ regmap_write(rt1318->regmap, RT1318_TCON_RELATE, 0x78);
+ regmap_write(rt1318->regmap, RT1318_STP_R0_EN_L, 0xC2);
+}
+
+static void rt1318_r0_calculate(struct rt1318_priv *rt1318)
+{
+ unsigned int r0_l, r0_l_byte0, r0_l_byte1, r0_l_byte2, r0_l_byte3;
+ unsigned int r0_r, r0_r_byte0, r0_r_byte1, r0_r_byte2, r0_r_byte3;
+ unsigned int r0_l_integer, r0_l_factor, r0_r_integer, r0_r_factor;
+ unsigned int format = 16777216; /* 2^24 */
+
+ regmap_read(rt1318->regmap, RT1318_R0_L_24, &r0_l_byte0);
+ regmap_read(rt1318->regmap, RT1318_R0_L_23_16, &r0_l_byte1);
+ regmap_read(rt1318->regmap, RT1318_R0_L_15_8, &r0_l_byte2);
+ regmap_read(rt1318->regmap, RT1318_R0_L_7_0, &r0_l_byte3);
+ r0_l = r0_l_byte0 << 24 | r0_l_byte1 << 16 | r0_l_byte2 << 8 | r0_l_byte3;
+ r0_l_integer = format / r0_l;
+ r0_l_factor = (format * 10) / r0_l - r0_l_integer * 10;
+
+ regmap_read(rt1318->regmap, RT1318_R0_R_24, &r0_r_byte0);
+ regmap_read(rt1318->regmap, RT1318_R0_R_23_16, &r0_r_byte1);
+ regmap_read(rt1318->regmap, RT1318_R0_R_15_8, &r0_r_byte2);
+ regmap_read(rt1318->regmap, RT1318_R0_R_7_0, &r0_r_byte3);
+ r0_r = r0_r_byte0 << 24 | r0_r_byte1 << 16 | r0_r_byte2 << 8 | r0_r_byte3;
+ r0_r_integer = format / r0_r;
+ r0_r_factor = (format * 10) / r0_r - r0_r_integer * 10;
+
+ dev_dbg(rt1318->component->dev, "r0_l_ch:%d.%d ohm\n", r0_l_integer, r0_l_factor);
+ dev_dbg(rt1318->component->dev, "r0_r_ch:%d.%d ohm\n", r0_r_integer, r0_r_factor);
+}
+
+static void rt1318_r0_restore(struct rt1318_priv *rt1318)
+{
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_L_24,
+ (rt1318->pdata.init_r0_l >> 24) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_L_23_16,
+ (rt1318->pdata.init_r0_l >> 16) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_L_15_8,
+ (rt1318->pdata.init_r0_l >> 8) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_L_7_0,
+ (rt1318->pdata.init_r0_l >> 0) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_R_24,
+ (rt1318->pdata.init_r0_r >> 24) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_R_23_16,
+ (rt1318->pdata.init_r0_r >> 16) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_R_15_8,
+ (rt1318->pdata.init_r0_r >> 8) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_R_7_0,
+ (rt1318->pdata.init_r0_r >> 0) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_STP_SEL_L, 0x80);
+ regmap_write(rt1318->regmap, RT1318_STP_SEL_R, 0x80);
+ regmap_write(rt1318->regmap, RT1318_R0_CMP_L_FLAG, 0xc0);
+ regmap_write(rt1318->regmap, RT1318_R0_CMP_R_FLAG, 0xc0);
+ regmap_write(rt1318->regmap, RT1318_STP_R0_EN_L, 0xc0);
+ regmap_write(rt1318->regmap, RT1318_STP_R0_EN_R, 0xc0);
+ regmap_write(rt1318->regmap, RT1318_STP_TEMP_L, 0xcc);
+ regmap_write(rt1318->regmap, RT1318_TCON, 0x9c);
+}
+
+static int rt1318_calibrate(struct rt1318_priv *rt1318)
+{
+ int chk_cnt = 30, count = 0;
+ int val, val2;
+
+ regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x1);
+ usleep_range(0, 10000);
+ rt1318_calibration_sequence(rt1318);
+
+ while (count < chk_cnt) {
+ msleep(100);
+ regmap_read(rt1318->regmap, RT1318_R0_CMP_L_FLAG, &val);
+ regmap_read(rt1318->regmap, RT1318_R0_CMP_R_FLAG, &val2);
+ val = (val >> 1) & 0x1;
+ val2 = (val2 >> 1) & 0x1;
+ if (val & val2) {
+ dev_dbg(rt1318->component->dev, "Calibration done.\n");
+ break;
+ }
+ count++;
+ if (count == chk_cnt) {
+ regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x0);
+ return RT1318_R0_CALIB_NOT_DONE;
+ }
+ }
+ regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x0);
+ regmap_read(rt1318->regmap, RT1318_R0_CMP_L_FLAG, &val);
+ regmap_read(rt1318->regmap, RT1318_R0_CMP_R_FLAG, &val2);
+ if ((val & 0x1) & (val2 & 0x1))
+ return RT1318_R0_IN_RANGE;
+ else
+ return RT1318_R0_OUT_OF_RANGE;
+}
+
+static void rt1318_calibration_work(struct work_struct *work)
+{
+ struct rt1318_priv *rt1318 =
+ container_of(work, struct rt1318_priv, cali_work);
+ int ret;
+
+ if (rt1318->pdata.init_r0_l && rt1318->pdata.init_r0_r)
+ rt1318_r0_restore(rt1318);
+ else {
+ ret = rt1318_calibrate(rt1318);
+ if (ret == RT1318_R0_IN_RANGE)
+ rt1318_r0_calculate(rt1318);
+ dev_dbg(rt1318->component->dev, "Calibrate R0 result:%d\n", ret);
+ }
+}
+
+static int rt1318_i2c_probe(struct i2c_client *i2c)
+{
+ struct rt1318_platform_data *pdata = dev_get_platdata(&i2c->dev);
+ struct rt1318_priv *rt1318;
+ int ret, val, val2, dev_id;
+
+ rt1318 = devm_kzalloc(&i2c->dev, sizeof(struct rt1318_priv),
+ GFP_KERNEL);
+ if (!rt1318)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, rt1318);
+
+ if (pdata)
+ rt1318->pdata = *pdata;
+ else
+ rt1318_parse_dt(rt1318, &i2c->dev);
+
+ rt1318->regmap = devm_regmap_init_i2c(i2c, &rt1318_regmap);
+ if (IS_ERR(rt1318->regmap)) {
+ ret = PTR_ERR(rt1318->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ regmap_read(rt1318->regmap, RT1318_DEV_ID1, &val);
+ regmap_read(rt1318->regmap, RT1318_DEV_ID2, &val2);
+ dev_id = (val << 8) | val2;
+ if (dev_id != 0x6821) {
+ dev_err(&i2c->dev,
+ "Device with ID register %#x is not rt1318\n",
+ dev_id);
+ return -ENODEV;
+ }
+
+ ret = regmap_register_patch(rt1318->regmap, init_list,
+ ARRAY_SIZE(init_list));
+ if (ret != 0)
+ dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+ INIT_WORK(&rt1318->cali_work, rt1318_calibration_work);
+
+ return devm_snd_soc_register_component(&i2c->dev,
+ &soc_component_dev_rt1318, rt1318_dai, ARRAY_SIZE(rt1318_dai));
+}
+
+static struct i2c_driver rt1318_i2c_driver = {
+ .driver = {
+ .name = "rt1318",
+ .of_match_table = of_match_ptr(rt1318_of_match),
+ .acpi_match_table = ACPI_PTR(rt1318_acpi_match),
+ },
+ .probe = rt1318_i2c_probe,
+ .id_table = rt1318_i2c_id,
+};
+module_i2c_driver(rt1318_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT1318 driver");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt1318.h b/sound/soc/codecs/rt1318.h
new file mode 100644
index 000000000000..cec40b484216
--- /dev/null
+++ b/sound/soc/codecs/rt1318.h
@@ -0,0 +1,342 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt1318.h -- Platform data for RT1318
+ *
+ * Copyright 2024 Realtek Semiconductor Corp.
+ */
+#include <sound/rt1318.h>
+
+#ifndef __RT1318_H__
+#define __RT1318_H__
+
+struct rt1318_priv {
+ struct snd_soc_component *component;
+ struct rt1318_platform_data pdata;
+ struct work_struct cali_work;
+ struct regmap *regmap;
+
+ unsigned int r0_l_integer;
+ unsigned int r0_l_factor;
+ unsigned int r0_r_integer;
+ unsigned int r0_r_factor;
+ int rt1318_init;
+ int rt1318_dvol;
+ int sysclk_src;
+ int sysclk;
+ int lrck;
+ int bclk;
+ int master;
+ int pll_src;
+ int pll_in;
+ int pll_out;
+};
+
+#define RT1318_PLL_INP_MAX 40000000
+#define RT1318_PLL_INP_MIN 256000
+#define RT1318_PLL_N_MAX 0x1ff
+#define RT1318_PLL_K_MAX 0x1f
+#define RT1318_PLL_M_MAX 0x1f
+
+#define RT1318_LRCLK_192000 192000
+#define RT1318_LRCLK_96000 96000
+#define RT1318_LRCLK_48000 48000
+#define RT1318_LRCLK_44100 44100
+#define RT1318_LRCLK_16000 16000
+#define RT1318_DVOL_STEP 383
+
+#define RT1318_CLK1 0xc001
+#define RT1318_CLK2 0xc003
+#define RT1318_CLK3 0xc004
+#define RT1318_CLK4 0xc005
+#define RT1318_CLK5 0xc006
+#define RT1318_CLK6 0xc007
+#define RT1318_CLK7 0xc008
+#define RT1318_PWR_STA1 0xc121
+#define RT1318_SPK_VOL_TH 0xc130
+#define RT1318_TCON 0xc203
+#define RT1318_SRC_TCON 0xc204
+#define RT1318_TCON_RELATE 0xc206
+#define RT1318_DA_VOL_L_8 0xc20b
+#define RT1318_DA_VOL_L_1_7 0xc20c
+#define RT1318_DA_VOL_R_8 0xc20d
+#define RT1318_DA_VOL_R_1_7 0xc20e
+#define RT1318_FEEDBACK_PATH 0xc321
+#define RT1318_STP_TEMP_L 0xdb00
+#define RT1318_STP_SEL_L 0xdb08
+#define RT1318_STP_R0_EN_L 0xdb12
+#define RT1318_R0_CMP_L_FLAG 0xdb35
+#define RT1318_PRE_R0_L_24 0xdbb5
+#define RT1318_PRE_R0_L_23_16 0xdbb6
+#define RT1318_PRE_R0_L_15_8 0xdbb7
+#define RT1318_PRE_R0_L_7_0 0xdbb8
+#define RT1318_R0_L_24 0xdbc5
+#define RT1318_R0_L_23_16 0xdbc6
+#define RT1318_R0_L_15_8 0xdbc7
+#define RT1318_R0_L_7_0 0xdbc8
+#define RT1318_STP_SEL_R 0xdd08
+#define RT1318_STP_R0_EN_R 0xdd12
+#define RT1318_R0_CMP_R_FLAG 0xdd35
+#define RT1318_PRE_R0_R_24 0xddb5
+#define RT1318_PRE_R0_R_23_16 0xddb6
+#define RT1318_PRE_R0_R_15_8 0xddb7
+#define RT1318_PRE_R0_R_7_0 0xddb8
+#define RT1318_R0_R_24 0xddc5
+#define RT1318_R0_R_23_16 0xddc6
+#define RT1318_R0_R_15_8 0xddc7
+#define RT1318_R0_R_7_0 0xddc8
+#define RT1318_DEV_ID1 0xf012
+#define RT1318_DEV_ID2 0xf013
+#define RT1318_PLL1_K 0xf20d
+#define RT1318_PLL1_M 0xf20f
+#define RT1318_PLL1_N_8 0xf211
+#define RT1318_PLL1_N_7_0 0xf212
+#define RT1318_SINE_GEN0 0xf800
+#define RT1318_TDM_CTRL1 0xf900
+#define RT1318_TDM_CTRL2 0xf901
+#define RT1318_TDM_CTRL3 0xf902
+#define RT1318_TDM_CTRL9 0xf908
+
+
+/* Clock-1 (0xC001) */
+#define RT1318_PLLIN_MASK (0x7 << 4)
+#define RT1318_PLLIN_BCLK0 (0x0 << 4)
+#define RT1318_PLLIN_BCLK1 (0x1 << 4)
+#define RT1318_PLLIN_RC (0x2 << 4)
+#define RT1318_PLLIN_MCLK (0x3 << 4)
+#define RT1318_PLLIN_SDW1 (0x4 << 4)
+#define RT1318_PLLIN_SDW2 (0x5 << 4)
+#define RT1318_PLLIN_SDW3 (0x6 << 4)
+#define RT1318_PLLIN_SDW4 (0x7 << 4)
+#define RT1318_SYSCLK_SEL_MASK (0x7 << 0)
+#define RT1318_SYSCLK_BCLK (0x0 << 0)
+#define RT1318_SYSCLK_SDW (0x1 << 0)
+#define RT1318_SYSCLK_PLL2F (0x2 << 0)
+#define RT1318_SYSCLK_PLL2B (0x3 << 0)
+#define RT1318_SYSCLK_MCLK (0x4 << 0)
+#define RT1318_SYSCLK_RC1 (0x5 << 0)
+#define RT1318_SYSCLK_RC2 (0x6 << 0)
+#define RT1318_SYSCLK_RC3 (0x7 << 0)
+/* Clock-2 (0xC003) */
+#define RT1318_DIV_AP_MASK (0x3 << 4)
+#define RT1318_DIV_AP_SFT 4
+#define RT1318_DIV_AP_DIV1 (0x0 << 4)
+#define RT1318_DIV_AP_DIV2 (0x1 << 4)
+#define RT1318_DIV_AP_DIV4 (0x2 << 4)
+#define RT1318_DIV_AP_DIV8 (0x3 << 4)
+#define RT1318_DIV_DAMOD_MASK (0x3 << 0)
+#define RT1318_DIV_DAMOD_SFT 0
+#define RT1318_DIV_DAMOD_DIV1 (0x0 << 0)
+#define RT1318_DIV_DAMOD_DIV2 (0x1 << 0)
+#define RT1318_DIV_DAMOD_DIV4 (0x2 << 0)
+#define RT1318_DIV_DAMOD_DIV8 (0x3 << 0)
+/* Clock-3 (0xC004) */
+#define RT1318_AD_STO1_MASK (0x7 << 4)
+#define RT1318_AD_STO1_SFT 4
+#define RT1318_AD_STO1_DIV1 (0x0 << 4)
+#define RT1318_AD_STO1_DIV2 (0x1 << 4)
+#define RT1318_AD_STO1_DIV4 (0x2 << 4)
+#define RT1318_AD_STO1_DIV8 (0x3 << 4)
+#define RT1318_AD_STO1_DIV16 (0x4 << 4)
+#define RT1318_AD_STO2_MASK (0x7 << 0)
+#define RT1318_AD_STO2_SFT 0
+#define RT1318_AD_STO2_DIV1 (0x0 << 0)
+#define RT1318_AD_STO2_DIV2 (0x1 << 0)
+#define RT1318_AD_STO2_DIV4 (0x2 << 0)
+#define RT1318_AD_STO2_DIV8 (0x3 << 0)
+#define RT1318_AD_STO2_DIV16 (0x4 << 0)
+#define RT1318_AD_STO2_SFT 0
+/* Clock-4 (0xC005) */
+#define RT1318_AD_ANA_STO1_MASK (0x7 << 4)
+#define RT1318_AD_ANA_STO1_SFT 4
+#define RT1318_AD_ANA_STO1_DIV1 (0x0 << 4)
+#define RT1318_AD_ANA_STO1_DIV2 (0x1 << 4)
+#define RT1318_AD_ANA_STO1_DIV4 (0x2 << 4)
+#define RT1318_AD_ANA_STO1_DIV8 (0x3 << 4)
+#define RT1318_AD_ANA_STO1_DIV16 (0x4 << 4)
+#define RT1318_AD_ANA_STO2_MASK (0x7 << 0)
+#define RT1318_AD_ANA_STO2_DIV1 (0x0 << 0)
+#define RT1318_AD_ANA_STO2_DIV2 (0x1 << 0)
+#define RT1318_AD_ANA_STO2_DIV4 (0x2 << 0)
+#define RT1318_AD_ANA_STO2_DIV8 (0x3 << 0)
+#define RT1318_AD_ANA_STO2_DIV16 (0x4 << 0)
+#define RT1318_AD_ANA_STO2_SFT 0
+/* Clock-5 (0xC006) */
+#define RT1318_DIV_FIFO_IN_MASK (0x3 << 4)
+#define RT1318_DIV_FIFO_IN_SFT 4
+#define RT1318_DIV_FIFO_IN_DIV1 (0x0 << 4)
+#define RT1318_DIV_FIFO_IN_DIV2 (0x1 << 4)
+#define RT1318_DIV_FIFO_IN_DIV4 (0x2 << 4)
+#define RT1318_DIV_FIFO_IN_DIV8 (0x3 << 4)
+#define RT1318_DIV_FIFO_OUT_MASK (0x3 << 0)
+#define RT1318_DIV_FIFO_OUT_DIV1 (0x0 << 0)
+#define RT1318_DIV_FIFO_OUT_DIV2 (0x1 << 0)
+#define RT1318_DIV_FIFO_OUT_DIV4 (0x2 << 0)
+#define RT1318_DIV_FIFO_OUT_DIV8 (0x3 << 0)
+#define RT1318_DIV_FIFO_OUT_SFT 0
+/* Clock-6 (0xC007) */
+#define RT1318_DIV_NLMS_MASK (0x3 << 6)
+#define RT1318_DIV_NLMS_SFT 6
+#define RT1318_DIV_NLMS_DIV1 (0x0 << 6)
+#define RT1318_DIV_NLMS_DIV2 (0x1 << 6)
+#define RT1318_DIV_NLMS_DIV4 (0x2 << 6)
+#define RT1318_DIV_NLMS_DIV8 (0x3 << 6)
+#define RT1318_DIV_AD_MONO_MASK (0x7 << 3)
+#define RT1318_DIV_AD_MONO_SFT 3
+#define RT1318_DIV_AD_MONO_DIV1 (0x0 << 3)
+#define RT1318_DIV_AD_MONO_DIV2 (0x1 << 3)
+#define RT1318_DIV_AD_MONO_DIV4 (0x2 << 3)
+#define RT1318_DIV_AD_MONO_DIV8 (0x3 << 3)
+#define RT1318_DIV_AD_MONO_DIV16 (0x4 << 3)
+#define RT1318_DIV_POST_G_MASK (0x7 << 0)
+#define RT1318_DIV_POST_G_SFT 0
+#define RT1318_DIV_POST_G_DIV1 (0x0 << 0)
+#define RT1318_DIV_POST_G_DIV2 (0x1 << 0)
+#define RT1318_DIV_POST_G_DIV4 (0x2 << 0)
+#define RT1318_DIV_POST_G_DIV8 (0x3 << 0)
+#define RT1318_DIV_POST_G_DIV16 (0x4 << 0)
+/* Power Status 1 (0xC121) */
+#define RT1318_PDB_CTRL_MASK (0x1)
+#define RT1318_PDB_CTRL_LOW (0x0)
+#define RT1318_PDB_CTRL_HIGH (0x1)
+#define RT1318_PDB_CTRL_SFT 0
+/* SRC Tcon(0xc204) */
+#define RT1318_SRCIN_IN_SEL_MASK (0x3 << 6)
+#define RT1318_SRCIN_IN_48K (0x0 << 6)
+#define RT1318_SRCIN_IN_44P1 (0x1 << 6)
+#define RT1318_SRCIN_IN_32K (0x2 << 6)
+#define RT1318_SRCIN_IN_16K (0x3 << 6)
+#define RT1318_SRCIN_F12288_MASK (0x3 << 4)
+#define RT1318_SRCIN_TCON1 (0x0 << 4)
+#define RT1318_SRCIN_TCON2 (0x1 << 4)
+#define RT1318_SRCIN_TCON4 (0x2 << 4)
+#define RT1318_SRCIN_TCON8 (0x3 << 4)
+#define RT1318_SRCIN_DACLK_MASK (0x3 << 2)
+#define RT1318_DACLK_TCON1 (0x0 << 2)
+#define RT1318_DACLK_TCON2 (0x1 << 2)
+#define RT1318_DACLK_TCON4 (0x2 << 2)
+#define RT1318_DACLK_TCON8 (0x3 << 2)
+/* R0 Compare Flag (0xDB35) */
+#define RT1318_R0_RANGE_MASK (0x1)
+#define RT1318_R0_OUTOFRANGE (0x0)
+#define RT1318_R0_INRANGE (0x1)
+/* PLL internal setting (0xF20D), K value */
+#define RT1318_K_PLL1_MASK (0x1f << 0)
+/* PLL internal setting (0xF20F), M value */
+#define RT1318_M_PLL1_MASK (0x1f << 0)
+/* PLL internal setting (0xF211), N_8 value */
+#define RT1318_N_8_PLL1_MASK (0x1 << 0)
+/* PLL internal setting (0xF212), N_7_0 value */
+#define RT1318_N_7_0_PLL1_MASK (0xff << 0)
+/* TDM CTRL 1 (0xf900) */
+#define RT1318_TDM_BCLK_MASK (0x1 << 7)
+#define RT1318_TDM_BCLK_NORM (0x0 << 7)
+#define RT1318_TDM_BCLK_INV (0x1 << 7)
+#define RT1318_I2S_FMT_MASK (0x7 << 0)
+#define RT1318_FMT_I2S (0x0 << 0)
+#define RT1318_FMT_LEFT_J (0x1 << 0)
+#define RT1318_FMT_PCM_A_R (0x2 << 0)
+#define RT1318_FMT_PCM_B_R (0x3 << 0)
+#define RT1318_FMT_PCM_A_F (0x6 << 0)
+#define RT1318_FMT_PCM_B_F (0x7 << 0)
+#define RT1318_I2S_FMT_SFT 0
+/* TDM CTRL 2 (0xf901) */
+#define RT1318_I2S_CH_TX_MASK (0x3 << 6)
+#define RT1318_I2S_CH_TX_2CH (0x0 << 6)
+#define RT1318_I2S_CH_TX_4CH (0x1 << 6)
+#define RT1318_I2S_CH_TX_6CH (0x2 << 6)
+#define RT1318_I2S_CH_TX_8CH (0x3 << 6)
+#define RT1318_I2S_CH_RX_MASK (0x3 << 4)
+#define RT1318_I2S_CH_RX_2CH (0x0 << 4)
+#define RT1318_I2S_CH_RX_4CH (0x1 << 4)
+#define RT1318_I2S_CH_RX_6CH (0x2 << 4)
+#define RT1318_I2S_CH_RX_8CH (0x3 << 4)
+#define RT1318_I2S_DL_MASK 0x7
+#define RT1318_I2S_DL_SFT 0
+#define RT1318_I2S_DL_16 0x0
+#define RT1318_I2S_DL_20 0x1
+#define RT1318_I2S_DL_24 0x2
+#define RT1318_I2S_DL_32 0x3
+#define RT1318_I2S_DL_8 0x4
+/* TDM CTRL 3 (0xf902) */
+#define RT1318_I2S_TX_CHL_MASK (0x7 << 4)
+#define RT1318_I2S_TX_CHL_SFT 4
+#define RT1318_I2S_TX_CHL_16 (0x0 << 4)
+#define RT1318_I2S_TX_CHL_20 (0x1 << 4)
+#define RT1318_I2S_TX_CHL_24 (0x2 << 4)
+#define RT1318_I2S_TX_CHL_32 (0x3 << 4)
+#define RT1318_I2S_TX_CHL_8 (0x4 << 4)
+#define RT1318_I2S_RX_CHL_MASK (0x7 << 0)
+#define RT1318_I2S_RX_CHL_SFT 0
+#define RT1318_I2S_RX_CHL_16 (0x0 << 0)
+#define RT1318_I2S_RX_CHL_20 (0x1 << 0)
+#define RT1318_I2S_RX_CHL_24 (0x2 << 0)
+#define RT1318_I2S_RX_CHL_32 (0x3 << 0)
+#define RT1318_I2S_RX_CHL_8 (0x4 << 0)
+/* TDM CTRL 9 (0xf908) */
+#define RT1318_TDM_I2S_TX_L_DAC1_1_MASK (0x7 << 4)
+#define RT1318_TDM_I2S_TX_R_DAC1_1_MASK 0x7
+#define RT1318_TDM_I2S_TX_L_DAC1_1_SFT 4
+#define RT1318_TDM_I2S_TX_R_DAC1_1_SFT 0
+
+#define RT1318_REG_DISP_LEN 23
+
+/* System Clock Source */
+enum {
+ RT1318_SCLK_S_BCLK,
+ RT1318_SCLK_S_SDW,
+ RT1318_SCLK_S_PLL2F,
+ RT1318_SCLK_S_PLL2B,
+ RT1318_SCLK_S_MCLK,
+ RT1318_SCLK_S_RC0,
+ RT1318_SCLK_S_RC1,
+ RT1318_SCLK_S_RC2,
+};
+
+/* PLL Source */
+enum {
+ RT1318_PLL_S_BCLK0,
+ RT1318_PLL_S_BCLK1,
+ RT1318_PLL_S_RC,
+ RT1318_PLL_S_MCLK,
+ RT1318_PLL_S_SDW_IN_PLL,
+ RT1318_PLL_S_SDW_0,
+ RT1318_PLL_S_SDW_1,
+ RT1318_PLL_S_SDW_2,
+};
+
+/* TDM channel */
+enum {
+ RT1318_2CH,
+ RT1318_4CH,
+ RT1318_6CH,
+ RT1318_8CH,
+};
+
+/* R0 calibration result */
+enum {
+ RT1318_R0_OUT_OF_RANGE,
+ RT1318_R0_IN_RANGE,
+ RT1318_R0_CALIB_NOT_DONE,
+};
+
+/* PLL pre-defined M/N/K */
+
+struct pll_calc_map {
+ unsigned int pll_in;
+ unsigned int pll_out;
+ int k;
+ int n;
+ int m;
+ bool m_bp;
+ bool k_bp;
+};
+
+struct rt1318_pll_code {
+ bool m_bp; /* Indicates bypass m code or not. */
+ bool k_bp; /* Indicates bypass k code or not. */
+ int m_code;
+ int n_code;
+ int k_code;
+};
+
+#endif /* __RT1318_H__ */
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
new file mode 100644
index 000000000000..2916fa77b791
--- /dev/null
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -0,0 +1,2260 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt1320-sdw.c -- rt1320 SDCA ALSA SoC amplifier audio driver
+//
+// Copyright(c) 2024 Realtek Semiconductor Corp.
+//
+//
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/dmi.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/sdw.h>
+#include "rt1320-sdw.h"
+
+/*
+ * The 'blind writes' is an SDCA term to deal with platform-specific initialization.
+ * It might include vendor-specific or SDCA control registers.
+ */
+static const struct reg_sequence rt1320_blind_write[] = {
+ { 0xc003, 0xe0 },
+ { 0xc01b, 0xfc },
+ { 0xc5c3, 0xf2 },
+ { 0xc5c2, 0x00 },
+ { 0xc5c6, 0x10 },
+ { 0xc5c4, 0x12 },
+ { 0xc5c8, 0x03 },
+ { 0xc5d8, 0x0a },
+ { 0xc5f7, 0x22 },
+ { 0xc5f6, 0x22 },
+ { 0xc5d0, 0x0f },
+ { 0xc5d1, 0x89 },
+ { 0xc057, 0x51 },
+ { 0xc054, 0x35 },
+ { 0xc053, 0x55 },
+ { 0xc052, 0x55 },
+ { 0xc051, 0x13 },
+ { 0xc050, 0x15 },
+ { 0xc060, 0x77 },
+ { 0xc061, 0x55 },
+ { 0xc063, 0x55 },
+ { 0xc065, 0xa5 },
+ { 0xc06b, 0x0a },
+ { 0xca05, 0xd6 },
+ { 0xca25, 0xd6 },
+ { 0xcd00, 0x05 },
+ { 0xc604, 0x40 },
+ { 0xc609, 0x40 },
+ { 0xc046, 0xff },
+ { 0xc045, 0xff },
+ { 0xc044, 0xff },
+ { 0xc043, 0xff },
+ { 0xc042, 0xff },
+ { 0xc041, 0xff },
+ { 0xc040, 0xff },
+ { 0xcc10, 0x01 },
+ { 0xc700, 0xf0 },
+ { 0xc701, 0x13 },
+ { 0xc901, 0x04 },
+ { 0xc900, 0x73 },
+ { 0xde03, 0x05 },
+ { 0xdd0b, 0x0d },
+ { 0xdd0a, 0xff },
+ { 0xdd09, 0x0d },
+ { 0xdd08, 0xff },
+ { 0xc570, 0x08 },
+ { 0xe803, 0xbe },
+ { 0xc003, 0xc0 },
+ { 0xc081, 0xfe },
+ { 0xce31, 0x0d },
+ { 0xce30, 0xae },
+ { 0xce37, 0x0b },
+ { 0xce36, 0xd2 },
+ { 0xce39, 0x04 },
+ { 0xce38, 0x80 },
+ { 0xce3f, 0x00 },
+ { 0xce3e, 0x00 },
+ { 0xd470, 0x8b },
+ { 0xd471, 0x18 },
+ { 0xc019, 0x10 },
+ { 0xd487, 0x3f },
+ { 0xd486, 0xc3 },
+};
+
+/*
+ * The 'patch code' is written to the patch code area.
+ * The patch code area is used for SDCA register expansion flexibility.
+ */
+static const struct reg_sequence rt1320_patch_code_write[] = {
+ { 0x10007000, 0x37 },
+ { 0x10007001, 0x77 },
+ { 0x10007002, 0x00 },
+ { 0x10007003, 0x10 },
+ { 0x10007004, 0xb7 },
+ { 0x10007005, 0xe7 },
+ { 0x10007006, 0x00 },
+ { 0x10007007, 0x10 },
+ { 0x10007008, 0x13 },
+ { 0x10007009, 0x07 },
+ { 0x1000700a, 0x07 },
+ { 0x1000700b, 0x40 },
+ { 0x1000700c, 0x23 },
+ { 0x1000700d, 0xae },
+ { 0x1000700e, 0xe7 },
+ { 0x1000700f, 0xda },
+ { 0x10007010, 0x37 },
+ { 0x10007011, 0x77 },
+ { 0x10007012, 0x00 },
+ { 0x10007013, 0x10 },
+ { 0x10007014, 0x13 },
+ { 0x10007015, 0x07 },
+ { 0x10007016, 0x47 },
+ { 0x10007017, 0x61 },
+ { 0x10007018, 0x23 },
+ { 0x10007019, 0xa4 },
+ { 0x1000701a, 0xe7 },
+ { 0x1000701b, 0xde },
+ { 0x1000701c, 0x37 },
+ { 0x1000701d, 0x77 },
+ { 0x1000701e, 0x00 },
+ { 0x1000701f, 0x10 },
+ { 0x10007020, 0x13 },
+ { 0x10007021, 0x07 },
+ { 0x10007022, 0x07 },
+ { 0x10007023, 0x52 },
+ { 0x10007024, 0x23 },
+ { 0x10007025, 0xae },
+ { 0x10007026, 0xe7 },
+ { 0x10007027, 0xde },
+ { 0x10007028, 0x37 },
+ { 0x10007029, 0x77 },
+ { 0x1000702a, 0x00 },
+ { 0x1000702b, 0x10 },
+ { 0x1000702c, 0x13 },
+ { 0x1000702d, 0x07 },
+ { 0x1000702e, 0x47 },
+ { 0x1000702f, 0x54 },
+ { 0x10007030, 0x23 },
+ { 0x10007031, 0xaa },
+ { 0x10007032, 0xe7 },
+ { 0x10007033, 0xe4 },
+ { 0x10007034, 0x37 },
+ { 0x10007035, 0x87 },
+ { 0x10007036, 0x00 },
+ { 0x10007037, 0x10 },
+ { 0x10007038, 0x13 },
+ { 0x10007039, 0x07 },
+ { 0x1000703a, 0x47 },
+ { 0x1000703b, 0x81 },
+ { 0x1000703c, 0x23 },
+ { 0x1000703d, 0xa2 },
+ { 0x1000703e, 0xe7 },
+ { 0x1000703f, 0xe8 },
+ { 0x10007040, 0x23 },
+ { 0x10007041, 0xa4 },
+ { 0x10007042, 0xe7 },
+ { 0x10007043, 0xe8 },
+ { 0x10007044, 0x37 },
+ { 0x10007045, 0x77 },
+ { 0x10007046, 0x00 },
+ { 0x10007047, 0x10 },
+ { 0x10007048, 0x13 },
+ { 0x10007049, 0x07 },
+ { 0x1000704a, 0x07 },
+ { 0x1000704b, 0x59 },
+ { 0x1000704c, 0x23 },
+ { 0x1000704d, 0xa8 },
+ { 0x1000704e, 0xe7 },
+ { 0x1000704f, 0xea },
+ { 0x10007050, 0x37 },
+ { 0x10007051, 0x77 },
+ { 0x10007052, 0x00 },
+ { 0x10007053, 0x10 },
+ { 0x10007054, 0x13 },
+ { 0x10007055, 0x07 },
+ { 0x10007056, 0x07 },
+ { 0x10007057, 0x78 },
+ { 0x10007058, 0x23 },
+ { 0x10007059, 0xa6 },
+ { 0x1000705a, 0xe7 },
+ { 0x1000705b, 0xec },
+ { 0x1000705c, 0x67 },
+ { 0x1000705d, 0x80 },
+ { 0x1000705e, 0x00 },
+ { 0x1000705f, 0x00 },
+ { 0x10007400, 0x37 },
+ { 0x10007401, 0xd7 },
+ { 0x10007402, 0x00 },
+ { 0x10007403, 0x00 },
+ { 0x10007404, 0x83 },
+ { 0x10007405, 0x27 },
+ { 0x10007406, 0x47 },
+ { 0x10007407, 0x56 },
+ { 0x10007408, 0xb7 },
+ { 0x10007409, 0x06 },
+ { 0x1000740a, 0x00 },
+ { 0x1000740b, 0x02 },
+ { 0x1000740c, 0xb3 },
+ { 0x1000740d, 0xf7 },
+ { 0x1000740e, 0xd7 },
+ { 0x1000740f, 0x00 },
+ { 0x10007410, 0x63 },
+ { 0x10007411, 0x8a },
+ { 0x10007412, 0x07 },
+ { 0x10007413, 0x00 },
+ { 0x10007414, 0x93 },
+ { 0x10007415, 0x06 },
+ { 0x10007416, 0x10 },
+ { 0x10007417, 0x00 },
+ { 0x10007418, 0x23 },
+ { 0x10007419, 0x83 },
+ { 0x1000741a, 0xd1 },
+ { 0x1000741b, 0x44 },
+ { 0x1000741c, 0x93 },
+ { 0x1000741d, 0x07 },
+ { 0x1000741e, 0xf0 },
+ { 0x1000741f, 0xff },
+ { 0x10007420, 0x23 },
+ { 0x10007421, 0x22 },
+ { 0x10007422, 0xf7 },
+ { 0x10007423, 0x56 },
+ { 0x10007424, 0x37 },
+ { 0x10007425, 0xd7 },
+ { 0x10007426, 0x00 },
+ { 0x10007427, 0x00 },
+ { 0x10007428, 0x83 },
+ { 0x10007429, 0x27 },
+ { 0x1000742a, 0x47 },
+ { 0x1000742b, 0x58 },
+ { 0x1000742c, 0x93 },
+ { 0x1000742d, 0xf7 },
+ { 0x1000742e, 0x17 },
+ { 0x1000742f, 0x00 },
+ { 0x10007430, 0x63 },
+ { 0x10007431, 0x86 },
+ { 0x10007432, 0x07 },
+ { 0x10007433, 0x00 },
+ { 0x10007434, 0x93 },
+ { 0x10007435, 0x07 },
+ { 0x10007436, 0x10 },
+ { 0x10007437, 0x00 },
+ { 0x10007438, 0x23 },
+ { 0x10007439, 0x22 },
+ { 0x1000743a, 0xf7 },
+ { 0x1000743b, 0x58 },
+ { 0x1000743c, 0xb7 },
+ { 0x1000743d, 0xd7 },
+ { 0x1000743e, 0x00 },
+ { 0x1000743f, 0x00 },
+ { 0x10007440, 0x03 },
+ { 0x10007441, 0xa7 },
+ { 0x10007442, 0x47 },
+ { 0x10007443, 0x58 },
+ { 0x10007444, 0xb7 },
+ { 0x10007445, 0x07 },
+ { 0x10007446, 0x00 },
+ { 0x10007447, 0x04 },
+ { 0x10007448, 0x33 },
+ { 0x10007449, 0x77 },
+ { 0x1000744a, 0xf7 },
+ { 0x1000744b, 0x00 },
+ { 0x1000744c, 0x93 },
+ { 0x1000744d, 0x07 },
+ { 0x1000744e, 0x00 },
+ { 0x1000744f, 0x00 },
+ { 0x10007450, 0x63 },
+ { 0x10007451, 0x0e },
+ { 0x10007452, 0x07 },
+ { 0x10007453, 0x04 },
+ { 0x10007454, 0x37 },
+ { 0x10007455, 0x07 },
+ { 0x10007456, 0x00 },
+ { 0x10007457, 0x11 },
+ { 0x10007458, 0x03 },
+ { 0x10007459, 0x47 },
+ { 0x1000745a, 0x87 },
+ { 0x1000745b, 0x0e },
+ { 0x1000745c, 0x93 },
+ { 0x1000745d, 0x06 },
+ { 0x1000745e, 0x40 },
+ { 0x1000745f, 0x00 },
+ { 0x10007460, 0x13 },
+ { 0x10007461, 0x77 },
+ { 0x10007462, 0xf7 },
+ { 0x10007463, 0x0f },
+ { 0x10007464, 0x63 },
+ { 0x10007465, 0x02 },
+ { 0x10007466, 0xd7 },
+ { 0x10007467, 0x0a },
+ { 0x10007468, 0x93 },
+ { 0x10007469, 0x06 },
+ { 0x1000746a, 0x70 },
+ { 0x1000746b, 0x00 },
+ { 0x1000746c, 0x63 },
+ { 0x1000746d, 0x10 },
+ { 0x1000746e, 0xd7 },
+ { 0x1000746f, 0x04 },
+ { 0x10007470, 0x93 },
+ { 0x10007471, 0x07 },
+ { 0x10007472, 0x60 },
+ { 0x10007473, 0x06 },
+ { 0x10007474, 0x37 },
+ { 0x10007475, 0xd7 },
+ { 0x10007476, 0x00 },
+ { 0x10007477, 0x00 },
+ { 0x10007478, 0x83 },
+ { 0x10007479, 0x46 },
+ { 0x1000747a, 0x77 },
+ { 0x1000747b, 0xa6 },
+ { 0x1000747c, 0x93 },
+ { 0x1000747d, 0xe6 },
+ { 0x1000747e, 0x06 },
+ { 0x1000747f, 0xf8 },
+ { 0x10007480, 0x93 },
+ { 0x10007481, 0xf6 },
+ { 0x10007482, 0xf6 },
+ { 0x10007483, 0x0f },
+ { 0x10007484, 0xa3 },
+ { 0x10007485, 0x03 },
+ { 0x10007486, 0xd7 },
+ { 0x10007487, 0xa6 },
+ { 0x10007488, 0x83 },
+ { 0x10007489, 0x46 },
+ { 0x1000748a, 0x77 },
+ { 0x1000748b, 0xa8 },
+ { 0x1000748c, 0x93 },
+ { 0x1000748d, 0xe6 },
+ { 0x1000748e, 0x06 },
+ { 0x1000748f, 0xf8 },
+ { 0x10007490, 0x93 },
+ { 0x10007491, 0xf6 },
+ { 0x10007492, 0xf6 },
+ { 0x10007493, 0x0f },
+ { 0x10007494, 0xa3 },
+ { 0x10007495, 0x03 },
+ { 0x10007496, 0xd7 },
+ { 0x10007497, 0xa8 },
+ { 0x10007498, 0xb7 },
+ { 0x10007499, 0xc6 },
+ { 0x1000749a, 0x00 },
+ { 0x1000749b, 0x00 },
+ { 0x1000749c, 0x23 },
+ { 0x1000749d, 0x84 },
+ { 0x1000749e, 0xf6 },
+ { 0x1000749f, 0x06 },
+ { 0x100074a0, 0xa3 },
+ { 0x100074a1, 0x84 },
+ { 0x100074a2, 0xf6 },
+ { 0x100074a3, 0x06 },
+ { 0x100074a4, 0xb7 },
+ { 0x100074a5, 0x06 },
+ { 0x100074a6, 0x00 },
+ { 0x100074a7, 0x04 },
+ { 0x100074a8, 0x23 },
+ { 0x100074a9, 0x22 },
+ { 0x100074aa, 0xd7 },
+ { 0x100074ab, 0x58 },
+ { 0x100074ac, 0x37 },
+ { 0x100074ad, 0xd7 },
+ { 0x100074ae, 0x00 },
+ { 0x100074af, 0x00 },
+ { 0x100074b0, 0x03 },
+ { 0x100074b1, 0x27 },
+ { 0x100074b2, 0x47 },
+ { 0x100074b3, 0x58 },
+ { 0x100074b4, 0xb7 },
+ { 0x100074b5, 0x06 },
+ { 0x100074b6, 0x00 },
+ { 0x100074b7, 0x08 },
+ { 0x100074b8, 0x33 },
+ { 0x100074b9, 0x77 },
+ { 0x100074ba, 0xd7 },
+ { 0x100074bb, 0x00 },
+ { 0x100074bc, 0x63 },
+ { 0x100074bd, 0x04 },
+ { 0x100074be, 0x07 },
+ { 0x100074bf, 0x04 },
+ { 0x100074c0, 0x37 },
+ { 0x100074c1, 0x07 },
+ { 0x100074c2, 0x00 },
+ { 0x100074c3, 0x11 },
+ { 0x100074c4, 0x03 },
+ { 0x100074c5, 0x47 },
+ { 0x100074c6, 0xc7 },
+ { 0x100074c7, 0x0e },
+ { 0x100074c8, 0x93 },
+ { 0x100074c9, 0x06 },
+ { 0x100074ca, 0x40 },
+ { 0x100074cb, 0x00 },
+ { 0x100074cc, 0x13 },
+ { 0x100074cd, 0x77 },
+ { 0x100074ce, 0xf7 },
+ { 0x100074cf, 0x0f },
+ { 0x100074d0, 0x63 },
+ { 0x100074d1, 0x00 },
+ { 0x100074d2, 0xd7 },
+ { 0x100074d3, 0x04 },
+ { 0x100074d4, 0x93 },
+ { 0x100074d5, 0x06 },
+ { 0x100074d6, 0x70 },
+ { 0x100074d7, 0x00 },
+ { 0x100074d8, 0x63 },
+ { 0x100074d9, 0x00 },
+ { 0x100074da, 0xd7 },
+ { 0x100074db, 0x04 },
+ { 0x100074dc, 0x63 },
+ { 0x100074dd, 0x84 },
+ { 0x100074de, 0x07 },
+ { 0x100074df, 0x02 },
+ { 0x100074e0, 0xb7 },
+ { 0x100074e1, 0xd6 },
+ { 0x100074e2, 0x00 },
+ { 0x100074e3, 0x00 },
+ { 0x100074e4, 0x03 },
+ { 0x100074e5, 0xc7 },
+ { 0x100074e6, 0x56 },
+ { 0x100074e7, 0xa4 },
+ { 0x100074e8, 0x13 },
+ { 0x100074e9, 0x67 },
+ { 0x100074ea, 0x07 },
+ { 0x100074eb, 0xf8 },
+ { 0x100074ec, 0x13 },
+ { 0x100074ed, 0x77 },
+ { 0x100074ee, 0xf7 },
+ { 0x100074ef, 0x0f },
+ { 0x100074f0, 0xa3 },
+ { 0x100074f1, 0x82 },
+ { 0x100074f2, 0xe6 },
+ { 0x100074f3, 0xa4 },
+ { 0x100074f4, 0x37 },
+ { 0x100074f5, 0xc7 },
+ { 0x100074f6, 0x00 },
+ { 0x100074f7, 0x00 },
+ { 0x100074f8, 0x23 },
+ { 0x100074f9, 0x02 },
+ { 0x100074fa, 0xf7 },
+ { 0x100074fb, 0x06 },
+ { 0x100074fc, 0xb7 },
+ { 0x100074fd, 0x07 },
+ { 0x100074fe, 0x00 },
+ { 0x100074ff, 0x08 },
+ { 0x10007500, 0x23 },
+ { 0x10007501, 0xa2 },
+ { 0x10007502, 0xf6 },
+ { 0x10007503, 0x58 },
+ { 0x10007504, 0x67 },
+ { 0x10007505, 0x80 },
+ { 0x10007506, 0x00 },
+ { 0x10007507, 0x00 },
+ { 0x10007508, 0x93 },
+ { 0x10007509, 0x07 },
+ { 0x1000750a, 0x80 },
+ { 0x1000750b, 0x08 },
+ { 0x1000750c, 0x6f },
+ { 0x1000750d, 0xf0 },
+ { 0x1000750e, 0x9f },
+ { 0x1000750f, 0xf6 },
+ { 0x10007510, 0x93 },
+ { 0x10007511, 0x07 },
+ { 0x10007512, 0x80 },
+ { 0x10007513, 0x08 },
+ { 0x10007514, 0x6f },
+ { 0x10007515, 0xf0 },
+ { 0x10007516, 0xdf },
+ { 0x10007517, 0xfc },
+ { 0x10007518, 0x93 },
+ { 0x10007519, 0x07 },
+ { 0x1000751a, 0x60 },
+ { 0x1000751b, 0x06 },
+ { 0x1000751c, 0x6f },
+ { 0x1000751d, 0xf0 },
+ { 0x1000751e, 0x5f },
+ { 0x1000751f, 0xfc },
+ { 0x10007520, 0x37 },
+ { 0x10007521, 0xd7 },
+ { 0x10007522, 0x00 },
+ { 0x10007523, 0x00 },
+ { 0x10007524, 0x83 },
+ { 0x10007525, 0x27 },
+ { 0x10007526, 0x07 },
+ { 0x10007527, 0x53 },
+ { 0x10007528, 0xb7 },
+ { 0x10007529, 0x06 },
+ { 0x1000752a, 0x02 },
+ { 0x1000752b, 0x00 },
+ { 0x1000752c, 0xb3 },
+ { 0x1000752d, 0xf7 },
+ { 0x1000752e, 0xd7 },
+ { 0x1000752f, 0x00 },
+ { 0x10007530, 0x63 },
+ { 0x10007531, 0x88 },
+ { 0x10007532, 0x07 },
+ { 0x10007533, 0x00 },
+ { 0x10007534, 0x13 },
+ { 0x10007535, 0x06 },
+ { 0x10007536, 0xa0 },
+ { 0x10007537, 0x05 },
+ { 0x10007538, 0x23 },
+ { 0x10007539, 0xa8 },
+ { 0x1000753a, 0xc1 },
+ { 0x1000753b, 0x56 },
+ { 0x1000753c, 0x23 },
+ { 0x1000753d, 0x28 },
+ { 0x1000753e, 0xd7 },
+ { 0x1000753f, 0x52 },
+ { 0x10007540, 0x67 },
+ { 0x10007541, 0x80 },
+ { 0x10007542, 0x00 },
+ { 0x10007543, 0x00 },
+ { 0x10007544, 0x37 },
+ { 0x10007545, 0xd7 },
+ { 0x10007546, 0x00 },
+ { 0x10007547, 0x10 },
+ { 0x10007548, 0x83 },
+ { 0x10007549, 0x47 },
+ { 0x1000754a, 0x07 },
+ { 0x1000754b, 0xd9 },
+ { 0x1000754c, 0x93 },
+ { 0x1000754d, 0x06 },
+ { 0x1000754e, 0x20 },
+ { 0x1000754f, 0x00 },
+ { 0x10007550, 0x93 },
+ { 0x10007551, 0xf7 },
+ { 0x10007552, 0xf7 },
+ { 0x10007553, 0x0f },
+ { 0x10007554, 0x63 },
+ { 0x10007555, 0x9c },
+ { 0x10007556, 0xd7 },
+ { 0x10007557, 0x02 },
+ { 0x10007558, 0xb7 },
+ { 0x10007559, 0xc6 },
+ { 0x1000755a, 0x00 },
+ { 0x1000755b, 0x00 },
+ { 0x1000755c, 0x83 },
+ { 0x1000755d, 0xc7 },
+ { 0x1000755e, 0x26 },
+ { 0x1000755f, 0x04 },
+ { 0x10007560, 0x93 },
+ { 0x10007561, 0xf7 },
+ { 0x10007562, 0xf7 },
+ { 0x10007563, 0x07 },
+ { 0x10007564, 0x23 },
+ { 0x10007565, 0x81 },
+ { 0x10007566, 0xf6 },
+ { 0x10007567, 0x04 },
+ { 0x10007568, 0xb7 },
+ { 0x10007569, 0xd6 },
+ { 0x1000756a, 0x00 },
+ { 0x1000756b, 0x00 },
+ { 0x1000756c, 0x83 },
+ { 0x1000756d, 0xc7 },
+ { 0x1000756e, 0xa6 },
+ { 0x1000756f, 0xe1 },
+ { 0x10007570, 0x93 },
+ { 0x10007571, 0xf7 },
+ { 0x10007572, 0xf7 },
+ { 0x10007573, 0x07 },
+ { 0x10007574, 0x23 },
+ { 0x10007575, 0x8d },
+ { 0x10007576, 0xf6 },
+ { 0x10007577, 0xe0 },
+ { 0x10007578, 0x23 },
+ { 0x10007579, 0x08 },
+ { 0x1000757a, 0x07 },
+ { 0x1000757b, 0xd8 },
+ { 0x1000757c, 0x83 },
+ { 0x1000757d, 0x47 },
+ { 0x1000757e, 0x47 },
+ { 0x1000757f, 0xd9 },
+ { 0x10007580, 0x93 },
+ { 0x10007581, 0x87 },
+ { 0x10007582, 0x17 },
+ { 0x10007583, 0x00 },
+ { 0x10007584, 0x93 },
+ { 0x10007585, 0xf7 },
+ { 0x10007586, 0xf7 },
+ { 0x10007587, 0x0f },
+ { 0x10007588, 0x23 },
+ { 0x10007589, 0x0a },
+ { 0x1000758a, 0xf7 },
+ { 0x1000758b, 0xd8 },
+ { 0x1000758c, 0x67 },
+ { 0x1000758d, 0x80 },
+ { 0x1000758e, 0x00 },
+ { 0x1000758f, 0x00 },
+ { 0x10007590, 0xb7 },
+ { 0x10007591, 0xd7 },
+ { 0x10007592, 0x00 },
+ { 0x10007593, 0x00 },
+ { 0x10007594, 0x83 },
+ { 0x10007595, 0xc7 },
+ { 0x10007596, 0x07 },
+ { 0x10007597, 0x47 },
+ { 0x10007598, 0x93 },
+ { 0x10007599, 0xf7 },
+ { 0x1000759a, 0x07 },
+ { 0x1000759b, 0x01 },
+ { 0x1000759c, 0x63 },
+ { 0x1000759d, 0x8a },
+ { 0x1000759e, 0x07 },
+ { 0x1000759f, 0x06 },
+ { 0x100075a0, 0x63 },
+ { 0x100075a1, 0x02 },
+ { 0x100075a2, 0x05 },
+ { 0x100075a3, 0x06 },
+ { 0x100075a4, 0x37 },
+ { 0x100075a5, 0xc7 },
+ { 0x100075a6, 0x00 },
+ { 0x100075a7, 0x00 },
+ { 0x100075a8, 0x83 },
+ { 0x100075a9, 0x27 },
+ { 0x100075aa, 0xc7 },
+ { 0x100075ab, 0x5f },
+ { 0x100075ac, 0x23 },
+ { 0x100075ad, 0xae },
+ { 0x100075ae, 0xf1 },
+ { 0x100075af, 0x40 },
+ { 0x100075b0, 0xb7 },
+ { 0x100075b1, 0x06 },
+ { 0x100075b2, 0x00 },
+ { 0x100075b3, 0x10 },
+ { 0x100075b4, 0xb3 },
+ { 0x100075b5, 0xf7 },
+ { 0x100075b6, 0xd7 },
+ { 0x100075b7, 0x00 },
+ { 0x100075b8, 0x63 },
+ { 0x100075b9, 0x8c },
+ { 0x100075ba, 0x07 },
+ { 0x100075bb, 0x04 },
+ { 0x100075bc, 0x83 },
+ { 0x100075bd, 0x47 },
+ { 0x100075be, 0x07 },
+ { 0x100075bf, 0x56 },
+ { 0x100075c0, 0x93 },
+ { 0x100075c1, 0xf7 },
+ { 0x100075c2, 0x87 },
+ { 0x100075c3, 0x01 },
+ { 0x100075c4, 0x63 },
+ { 0x100075c5, 0x86 },
+ { 0x100075c6, 0x07 },
+ { 0x100075c7, 0x04 },
+ { 0x100075c8, 0x83 },
+ { 0x100075c9, 0x47 },
+ { 0x100075ca, 0x17 },
+ { 0x100075cb, 0x08 },
+ { 0x100075cc, 0x93 },
+ { 0x100075cd, 0xf7 },
+ { 0x100075ce, 0x47 },
+ { 0x100075cf, 0x00 },
+ { 0x100075d0, 0x63 },
+ { 0x100075d1, 0x80 },
+ { 0x100075d2, 0x07 },
+ { 0x100075d3, 0x04 },
+ { 0x100075d4, 0xb7 },
+ { 0x100075d5, 0xc7 },
+ { 0x100075d6, 0xc2 },
+ { 0x100075d7, 0x3f },
+ { 0x100075d8, 0x93 },
+ { 0x100075d9, 0x87 },
+ { 0x100075da, 0x07 },
+ { 0x100075db, 0xfc },
+ { 0x100075dc, 0x83 },
+ { 0x100075dd, 0xa7 },
+ { 0x100075de, 0x47 },
+ { 0x100075df, 0x00 },
+ { 0x100075e0, 0x93 },
+ { 0x100075e1, 0xd7 },
+ { 0x100075e2, 0x17 },
+ { 0x100075e3, 0x00 },
+ { 0x100075e4, 0x93 },
+ { 0x100075e5, 0xf7 },
+ { 0x100075e6, 0x17 },
+ { 0x100075e7, 0x00 },
+ { 0x100075e8, 0x63 },
+ { 0x100075e9, 0x84 },
+ { 0x100075ea, 0x07 },
+ { 0x100075eb, 0x02 },
+ { 0x100075ec, 0x23 },
+ { 0x100075ed, 0x8a },
+ { 0x100075ee, 0xf1 },
+ { 0x100075ef, 0x40 },
+ { 0x100075f0, 0xb7 },
+ { 0x100075f1, 0x07 },
+ { 0x100075f2, 0x00 },
+ { 0x100075f3, 0xc0 },
+ { 0x100075f4, 0x37 },
+ { 0x100075f5, 0xf7 },
+ { 0x100075f6, 0x00 },
+ { 0x100075f7, 0x00 },
+ { 0x100075f8, 0x93 },
+ { 0x100075f9, 0x87 },
+ { 0x100075fa, 0xf7 },
+ { 0x100075fb, 0xff },
+ { 0x100075fc, 0x23 },
+ { 0x100075fd, 0x2c },
+ { 0x100075fe, 0xf7 },
+ { 0x100075ff, 0x06 },
+ { 0x10007600, 0x67 },
+ { 0x10007601, 0x80 },
+ { 0x10007602, 0x00 },
+ { 0x10007603, 0x00 },
+ { 0x10007604, 0x23 },
+ { 0x10007605, 0x8a },
+ { 0x10007606, 0x01 },
+ { 0x10007607, 0x40 },
+ { 0x10007608, 0xb7 },
+ { 0x10007609, 0xf7 },
+ { 0x1000760a, 0x00 },
+ { 0x1000760b, 0x00 },
+ { 0x1000760c, 0x23 },
+ { 0x1000760d, 0xac },
+ { 0x1000760e, 0x07 },
+ { 0x1000760f, 0x06 },
+ { 0x10007610, 0x67 },
+ { 0x10007611, 0x80 },
+ { 0x10007612, 0x00 },
+ { 0x10007613, 0x00 },
+ { 0x10007614, 0x13 },
+ { 0x10007615, 0x01 },
+ { 0x10007616, 0x01 },
+ { 0x10007617, 0xff },
+ { 0x10007618, 0x23 },
+ { 0x10007619, 0x26 },
+ { 0x1000761a, 0x11 },
+ { 0x1000761b, 0x00 },
+ { 0x1000761c, 0x23 },
+ { 0x1000761d, 0x24 },
+ { 0x1000761e, 0x81 },
+ { 0x1000761f, 0x00 },
+ { 0x10007620, 0x37 },
+ { 0x10007621, 0xc7 },
+ { 0x10007622, 0x00 },
+ { 0x10007623, 0x00 },
+ { 0x10007624, 0x83 },
+ { 0x10007625, 0x47 },
+ { 0x10007626, 0x07 },
+ { 0x10007627, 0x56 },
+ { 0x10007628, 0x93 },
+ { 0x10007629, 0xf7 },
+ { 0x1000762a, 0x17 },
+ { 0x1000762b, 0x00 },
+ { 0x1000762c, 0x63 },
+ { 0x1000762d, 0x98 },
+ { 0x1000762e, 0x07 },
+ { 0x1000762f, 0x00 },
+ { 0x10007630, 0x83 },
+ { 0x10007631, 0x47 },
+ { 0x10007632, 0x07 },
+ { 0x10007633, 0x56 },
+ { 0x10007634, 0x93 },
+ { 0x10007635, 0xf7 },
+ { 0x10007636, 0x27 },
+ { 0x10007637, 0x00 },
+ { 0x10007638, 0x63 },
+ { 0x10007639, 0x82 },
+ { 0x1000763a, 0x07 },
+ { 0x1000763b, 0x08 },
+ { 0x1000763c, 0x37 },
+ { 0x1000763d, 0xd4 },
+ { 0x1000763e, 0x00 },
+ { 0x1000763f, 0x00 },
+ { 0x10007640, 0x83 },
+ { 0x10007641, 0x47 },
+ { 0x10007642, 0x14 },
+ { 0x10007643, 0x47 },
+ { 0x10007644, 0x93 },
+ { 0x10007645, 0xf7 },
+ { 0x10007646, 0x27 },
+ { 0x10007647, 0x00 },
+ { 0x10007648, 0x63 },
+ { 0x10007649, 0x8a },
+ { 0x1000764a, 0x07 },
+ { 0x1000764b, 0x06 },
+ { 0x1000764c, 0x93 },
+ { 0x1000764d, 0x05 },
+ { 0x1000764e, 0x10 },
+ { 0x1000764f, 0x00 },
+ { 0x10007650, 0x13 },
+ { 0x10007651, 0x05 },
+ { 0x10007652, 0x20 },
+ { 0x10007653, 0x10 },
+ { 0x10007654, 0xef },
+ { 0x10007655, 0xa0 },
+ { 0x10007656, 0x8f },
+ { 0x10007657, 0x9a },
+ { 0x10007658, 0x37 },
+ { 0x10007659, 0x05 },
+ { 0x1000765a, 0x01 },
+ { 0x1000765b, 0x00 },
+ { 0x1000765c, 0x93 },
+ { 0x1000765d, 0x05 },
+ { 0x1000765e, 0x00 },
+ { 0x1000765f, 0x01 },
+ { 0x10007660, 0x13 },
+ { 0x10007661, 0x05 },
+ { 0x10007662, 0xb5 },
+ { 0x10007663, 0xa0 },
+ { 0x10007664, 0xef },
+ { 0x10007665, 0xa0 },
+ { 0x10007666, 0x8f },
+ { 0x10007667, 0x99 },
+ { 0x10007668, 0x83 },
+ { 0x10007669, 0x47 },
+ { 0x1000766a, 0x24 },
+ { 0x1000766b, 0xe0 },
+ { 0x1000766c, 0x13 },
+ { 0x1000766d, 0x05 },
+ { 0x1000766e, 0x80 },
+ { 0x1000766f, 0x3e },
+ { 0x10007670, 0x93 },
+ { 0x10007671, 0x05 },
+ { 0x10007672, 0x00 },
+ { 0x10007673, 0x00 },
+ { 0x10007674, 0x93 },
+ { 0x10007675, 0xe7 },
+ { 0x10007676, 0x07 },
+ { 0x10007677, 0xf8 },
+ { 0x10007678, 0x93 },
+ { 0x10007679, 0xf7 },
+ { 0x1000767a, 0xf7 },
+ { 0x1000767b, 0x0f },
+ { 0x1000767c, 0x23 },
+ { 0x1000767d, 0x01 },
+ { 0x1000767e, 0xf4 },
+ { 0x1000767f, 0xe0 },
+ { 0x10007680, 0x83 },
+ { 0x10007681, 0x47 },
+ { 0x10007682, 0x24 },
+ { 0x10007683, 0xe0 },
+ { 0x10007684, 0x93 },
+ { 0x10007685, 0xf7 },
+ { 0x10007686, 0xf7 },
+ { 0x10007687, 0x0f },
+ { 0x10007688, 0x93 },
+ { 0x10007689, 0xe7 },
+ { 0x1000768a, 0x07 },
+ { 0x1000768b, 0x04 },
+ { 0x1000768c, 0x23 },
+ { 0x1000768d, 0x01 },
+ { 0x1000768e, 0xf4 },
+ { 0x1000768f, 0xe0 },
+ { 0x10007690, 0xef },
+ { 0x10007691, 0xe0 },
+ { 0x10007692, 0x8f },
+ { 0x10007693, 0xb9 },
+ { 0x10007694, 0x83 },
+ { 0x10007695, 0x47 },
+ { 0x10007696, 0x34 },
+ { 0x10007697, 0xe0 },
+ { 0x10007698, 0x93 },
+ { 0x10007699, 0xf7 },
+ { 0x1000769a, 0x07 },
+ { 0x1000769b, 0x02 },
+ { 0x1000769c, 0xe3 },
+ { 0x1000769d, 0x9c },
+ { 0x1000769e, 0x07 },
+ { 0x1000769f, 0xfe },
+ { 0x100076a0, 0x37 },
+ { 0x100076a1, 0x05 },
+ { 0x100076a2, 0x01 },
+ { 0x100076a3, 0x00 },
+ { 0x100076a4, 0x93 },
+ { 0x100076a5, 0x05 },
+ { 0x100076a6, 0x00 },
+ { 0x100076a7, 0x00 },
+ { 0x100076a8, 0x13 },
+ { 0x100076a9, 0x05 },
+ { 0x100076aa, 0xb5 },
+ { 0x100076ab, 0xa0 },
+ { 0x100076ac, 0xef },
+ { 0x100076ad, 0xa0 },
+ { 0x100076ae, 0x0f },
+ { 0x100076af, 0x95 },
+ { 0x100076b0, 0x83 },
+ { 0x100076b1, 0x47 },
+ { 0x100076b2, 0x14 },
+ { 0x100076b3, 0x47 },
+ { 0x100076b4, 0x93 },
+ { 0x100076b5, 0xf7 },
+ { 0x100076b6, 0xd7 },
+ { 0x100076b7, 0x0f },
+ { 0x100076b8, 0xa3 },
+ { 0x100076b9, 0x08 },
+ { 0x100076ba, 0xf4 },
+ { 0x100076bb, 0x46 },
+ { 0x100076bc, 0x03 },
+ { 0x100076bd, 0xa7 },
+ { 0x100076be, 0x01 },
+ { 0x100076bf, 0x57 },
+ { 0x100076c0, 0x93 },
+ { 0x100076c1, 0x07 },
+ { 0x100076c2, 0xa0 },
+ { 0x100076c3, 0x05 },
+ { 0x100076c4, 0x63 },
+ { 0x100076c5, 0x14 },
+ { 0x100076c6, 0xf7 },
+ { 0x100076c7, 0x04 },
+ { 0x100076c8, 0x37 },
+ { 0x100076c9, 0x07 },
+ { 0x100076ca, 0x00 },
+ { 0x100076cb, 0x11 },
+ { 0x100076cc, 0x83 },
+ { 0x100076cd, 0x47 },
+ { 0x100076ce, 0x07 },
+ { 0x100076cf, 0x01 },
+ { 0x100076d0, 0x13 },
+ { 0x100076d1, 0x06 },
+ { 0x100076d2, 0x30 },
+ { 0x100076d3, 0x00 },
+ { 0x100076d4, 0x93 },
+ { 0x100076d5, 0xf7 },
+ { 0x100076d6, 0xf7 },
+ { 0x100076d7, 0x0f },
+ { 0x100076d8, 0x63 },
+ { 0x100076d9, 0x9a },
+ { 0x100076da, 0xc7 },
+ { 0x100076db, 0x02 },
+ { 0x100076dc, 0x03 },
+ { 0x100076dd, 0x47 },
+ { 0x100076de, 0x87 },
+ { 0x100076df, 0x01 },
+ { 0x100076e0, 0x13 },
+ { 0x100076e1, 0x77 },
+ { 0x100076e2, 0xf7 },
+ { 0x100076e3, 0x0f },
+ { 0x100076e4, 0x63 },
+ { 0x100076e5, 0x14 },
+ { 0x100076e6, 0xf7 },
+ { 0x100076e7, 0x02 },
+ { 0x100076e8, 0x37 },
+ { 0x100076e9, 0xd7 },
+ { 0x100076ea, 0x00 },
+ { 0x100076eb, 0x00 },
+ { 0x100076ec, 0x83 },
+ { 0x100076ed, 0x47 },
+ { 0x100076ee, 0x37 },
+ { 0x100076ef, 0x54 },
+ { 0x100076f0, 0x93 },
+ { 0x100076f1, 0xf7 },
+ { 0x100076f2, 0xf7 },
+ { 0x100076f3, 0x0f },
+ { 0x100076f4, 0x93 },
+ { 0x100076f5, 0xe7 },
+ { 0x100076f6, 0x07 },
+ { 0x100076f7, 0x02 },
+ { 0x100076f8, 0xa3 },
+ { 0x100076f9, 0x01 },
+ { 0x100076fa, 0xf7 },
+ { 0x100076fb, 0x54 },
+ { 0x100076fc, 0x83 },
+ { 0x100076fd, 0x47 },
+ { 0x100076fe, 0x37 },
+ { 0x100076ff, 0x54 },
+ { 0x10007700, 0x93 },
+ { 0x10007701, 0xf7 },
+ { 0x10007702, 0xf7 },
+ { 0x10007703, 0x0d },
+ { 0x10007704, 0xa3 },
+ { 0x10007705, 0x01 },
+ { 0x10007706, 0xf7 },
+ { 0x10007707, 0x54 },
+ { 0x10007708, 0x23 },
+ { 0x10007709, 0xa8 },
+ { 0x1000770a, 0x01 },
+ { 0x1000770b, 0x56 },
+ { 0x1000770c, 0xb7 },
+ { 0x1000770d, 0xd7 },
+ { 0x1000770e, 0x00 },
+ { 0x1000770f, 0x10 },
+ { 0x10007710, 0x03 },
+ { 0x10007711, 0xc7 },
+ { 0x10007712, 0x07 },
+ { 0x10007713, 0xd9 },
+ { 0x10007714, 0x93 },
+ { 0x10007715, 0x06 },
+ { 0x10007716, 0x10 },
+ { 0x10007717, 0x00 },
+ { 0x10007718, 0x13 },
+ { 0x10007719, 0x77 },
+ { 0x1000771a, 0xf7 },
+ { 0x1000771b, 0x0f },
+ { 0x1000771c, 0x63 },
+ { 0x1000771d, 0x1a },
+ { 0x1000771e, 0xd7 },
+ { 0x1000771f, 0x04 },
+ { 0x10007720, 0x03 },
+ { 0x10007721, 0xc7 },
+ { 0x10007722, 0x27 },
+ { 0x10007723, 0xd9 },
+ { 0x10007724, 0x13 },
+ { 0x10007725, 0x07 },
+ { 0x10007726, 0x17 },
+ { 0x10007727, 0x00 },
+ { 0x10007728, 0x13 },
+ { 0x10007729, 0x77 },
+ { 0x1000772a, 0xf7 },
+ { 0x1000772b, 0x0f },
+ { 0x1000772c, 0x23 },
+ { 0x1000772d, 0x89 },
+ { 0x1000772e, 0xe7 },
+ { 0x1000772f, 0xd8 },
+ { 0x10007730, 0x83 },
+ { 0x10007731, 0xc6 },
+ { 0x10007732, 0x27 },
+ { 0x10007733, 0xd9 },
+ { 0x10007734, 0x03 },
+ { 0x10007735, 0xc7 },
+ { 0x10007736, 0x17 },
+ { 0x10007737, 0xd9 },
+ { 0x10007738, 0x93 },
+ { 0x10007739, 0xf6 },
+ { 0x1000773a, 0xf6 },
+ { 0x1000773b, 0x0f },
+ { 0x1000773c, 0x13 },
+ { 0x1000773d, 0x77 },
+ { 0x1000773e, 0xf7 },
+ { 0x1000773f, 0x0f },
+ { 0x10007740, 0x63 },
+ { 0x10007741, 0xe8 },
+ { 0x10007742, 0xe6 },
+ { 0x10007743, 0x02 },
+ { 0x10007744, 0xb7 },
+ { 0x10007745, 0xd6 },
+ { 0x10007746, 0x00 },
+ { 0x10007747, 0x00 },
+ { 0x10007748, 0x03 },
+ { 0x10007749, 0xc7 },
+ { 0x1000774a, 0xa6 },
+ { 0x1000774b, 0xe1 },
+ { 0x1000774c, 0x13 },
+ { 0x1000774d, 0x67 },
+ { 0x1000774e, 0x07 },
+ { 0x1000774f, 0xf8 },
+ { 0x10007750, 0x13 },
+ { 0x10007751, 0x77 },
+ { 0x10007752, 0xf7 },
+ { 0x10007753, 0x0f },
+ { 0x10007754, 0x23 },
+ { 0x10007755, 0x8d },
+ { 0x10007756, 0xe6 },
+ { 0x10007757, 0xe0 },
+ { 0x10007758, 0x03 },
+ { 0x10007759, 0xc7 },
+ { 0x1000775a, 0x37 },
+ { 0x1000775b, 0xd9 },
+ { 0x1000775c, 0x13 },
+ { 0x1000775d, 0x07 },
+ { 0x1000775e, 0x17 },
+ { 0x1000775f, 0x00 },
+ { 0x10007760, 0x13 },
+ { 0x10007761, 0x77 },
+ { 0x10007762, 0xf7 },
+ { 0x10007763, 0x0f },
+ { 0x10007764, 0xa3 },
+ { 0x10007765, 0x89 },
+ { 0x10007766, 0xe7 },
+ { 0x10007767, 0xd8 },
+ { 0x10007768, 0x13 },
+ { 0x10007769, 0x07 },
+ { 0x1000776a, 0x20 },
+ { 0x1000776b, 0x00 },
+ { 0x1000776c, 0x23 },
+ { 0x1000776d, 0x88 },
+ { 0x1000776e, 0xe7 },
+ { 0x1000776f, 0xd8 },
+ { 0x10007770, 0x83 },
+ { 0x10007771, 0x20 },
+ { 0x10007772, 0xc1 },
+ { 0x10007773, 0x00 },
+ { 0x10007774, 0x03 },
+ { 0x10007775, 0x24 },
+ { 0x10007776, 0x81 },
+ { 0x10007777, 0x00 },
+ { 0x10007778, 0x13 },
+ { 0x10007779, 0x01 },
+ { 0x1000777a, 0x01 },
+ { 0x1000777b, 0x01 },
+ { 0x1000777c, 0x67 },
+ { 0x1000777d, 0x80 },
+ { 0x1000777e, 0x00 },
+ { 0x1000777f, 0x00 },
+ { 0x10007780, 0x03 },
+ { 0x10007781, 0xc7 },
+ { 0x10007782, 0xa1 },
+ { 0x10007783, 0x40 },
+ { 0x10007784, 0x93 },
+ { 0x10007785, 0x06 },
+ { 0x10007786, 0x10 },
+ { 0x10007787, 0x00 },
+ { 0x10007788, 0x63 },
+ { 0x10007789, 0x16 },
+ { 0x1000778a, 0xd7 },
+ { 0x1000778b, 0x00 },
+ { 0x1000778c, 0xb7 },
+ { 0x1000778d, 0xd6 },
+ { 0x1000778e, 0x00 },
+ { 0x1000778f, 0x10 },
+ { 0x10007790, 0xa3 },
+ { 0x10007791, 0x8a },
+ { 0x10007792, 0xe6 },
+ { 0x10007793, 0xd8 },
+ { 0x10007794, 0x83 },
+ { 0x10007795, 0xc7 },
+ { 0x10007796, 0xa1 },
+ { 0x10007797, 0x40 },
+ { 0x10007798, 0x63 },
+ { 0x10007799, 0x9c },
+ { 0x1000779a, 0x07 },
+ { 0x1000779b, 0x06 },
+ { 0x1000779c, 0x13 },
+ { 0x1000779d, 0x01 },
+ { 0x1000779e, 0x01 },
+ { 0x1000779f, 0xff },
+ { 0x100077a0, 0x23 },
+ { 0x100077a1, 0x22 },
+ { 0x100077a2, 0x91 },
+ { 0x100077a3, 0x00 },
+ { 0x100077a4, 0x23 },
+ { 0x100077a5, 0x26 },
+ { 0x100077a6, 0x11 },
+ { 0x100077a7, 0x00 },
+ { 0x100077a8, 0x23 },
+ { 0x100077a9, 0x24 },
+ { 0x100077aa, 0x81 },
+ { 0x100077ab, 0x00 },
+ { 0x100077ac, 0xb7 },
+ { 0x100077ad, 0xc4 },
+ { 0x100077ae, 0x00 },
+ { 0x100077af, 0x00 },
+ { 0x100077b0, 0x83 },
+ { 0x100077b1, 0xc7 },
+ { 0x100077b2, 0x04 },
+ { 0x100077b3, 0x56 },
+ { 0x100077b4, 0x13 },
+ { 0x100077b5, 0x07 },
+ { 0x100077b6, 0x80 },
+ { 0x100077b7, 0x01 },
+ { 0x100077b8, 0x93 },
+ { 0x100077b9, 0xf7 },
+ { 0x100077ba, 0xf7 },
+ { 0x100077bb, 0x0f },
+ { 0x100077bc, 0x63 },
+ { 0x100077bd, 0x70 },
+ { 0x100077be, 0xf7 },
+ { 0x100077bf, 0x04 },
+ { 0x100077c0, 0x37 },
+ { 0x100077c1, 0xd4 },
+ { 0x100077c2, 0x00 },
+ { 0x100077c3, 0x10 },
+ { 0x100077c4, 0x83 },
+ { 0x100077c5, 0x47 },
+ { 0x100077c6, 0x54 },
+ { 0x100077c7, 0xd9 },
+ { 0x100077c8, 0x93 },
+ { 0x100077c9, 0xf7 },
+ { 0x100077ca, 0xf7 },
+ { 0x100077cb, 0x0f },
+ { 0x100077cc, 0x63 },
+ { 0x100077cd, 0x88 },
+ { 0x100077ce, 0x07 },
+ { 0x100077cf, 0x02 },
+ { 0x100077d0, 0x93 },
+ { 0x100077d1, 0x07 },
+ { 0x100077d2, 0x10 },
+ { 0x100077d3, 0x00 },
+ { 0x100077d4, 0x23 },
+ { 0x100077d5, 0x82 },
+ { 0x100077d6, 0xf4 },
+ { 0x100077d7, 0x58 },
+ { 0x100077d8, 0x03 },
+ { 0x100077d9, 0x45 },
+ { 0x100077da, 0x64 },
+ { 0x100077db, 0xd9 },
+ { 0x100077dc, 0xb7 },
+ { 0x100077dd, 0x15 },
+ { 0x100077de, 0x00 },
+ { 0x100077df, 0x00 },
+ { 0x100077e0, 0x93 },
+ { 0x100077e1, 0x85 },
+ { 0x100077e2, 0x85 },
+ { 0x100077e3, 0x38 },
+ { 0x100077e4, 0x13 },
+ { 0x100077e5, 0x75 },
+ { 0x100077e6, 0xf5 },
+ { 0x100077e7, 0x0f },
+ { 0x100077e8, 0xef },
+ { 0x100077e9, 0xe0 },
+ { 0x100077ea, 0x9f },
+ { 0x100077eb, 0xd0 },
+ { 0x100077ec, 0x93 },
+ { 0x100077ed, 0x55 },
+ { 0x100077ee, 0xf5 },
+ { 0x100077ef, 0x41 },
+ { 0x100077f0, 0xef },
+ { 0x100077f1, 0xe0 },
+ { 0x100077f2, 0x8f },
+ { 0x100077f3, 0xa3 },
+ { 0x100077f4, 0x23 },
+ { 0x100077f5, 0x82 },
+ { 0x100077f6, 0x04 },
+ { 0x100077f7, 0x58 },
+ { 0x100077f8, 0xa3 },
+ { 0x100077f9, 0x0a },
+ { 0x100077fa, 0x04 },
+ { 0x100077fb, 0xd8 },
+ { 0x100077fc, 0x83 },
+ { 0x100077fd, 0x20 },
+ { 0x100077fe, 0xc1 },
+ { 0x100077ff, 0x00 },
+ { 0x10007800, 0x03 },
+ { 0x10007801, 0x24 },
+ { 0x10007802, 0x81 },
+ { 0x10007803, 0x00 },
+ { 0x10007804, 0x83 },
+ { 0x10007805, 0x24 },
+ { 0x10007806, 0x41 },
+ { 0x10007807, 0x00 },
+ { 0x10007808, 0x13 },
+ { 0x10007809, 0x01 },
+ { 0x1000780a, 0x01 },
+ { 0x1000780b, 0x01 },
+ { 0x1000780c, 0x67 },
+ { 0x1000780d, 0x80 },
+ { 0x1000780e, 0x00 },
+ { 0x1000780f, 0x00 },
+ { 0x10007810, 0x67 },
+ { 0x10007811, 0x80 },
+ { 0x10007812, 0x00 },
+ { 0x10007813, 0x00 },
+ { 0x10007814, 0x13 },
+ { 0x10007815, 0x01 },
+ { 0x10007816, 0x01 },
+ { 0x10007817, 0xff },
+ { 0x10007818, 0x23 },
+ { 0x10007819, 0x26 },
+ { 0x1000781a, 0x11 },
+ { 0x1000781b, 0x00 },
+ { 0x1000781c, 0xef },
+ { 0x1000781d, 0xd0 },
+ { 0x1000781e, 0x8f },
+ { 0x1000781f, 0x86 },
+ { 0x10007820, 0x83 },
+ { 0x10007821, 0xc7 },
+ { 0x10007822, 0x11 },
+ { 0x10007823, 0x42 },
+ { 0x10007824, 0x63 },
+ { 0x10007825, 0x86 },
+ { 0x10007826, 0x07 },
+ { 0x10007827, 0x00 },
+ { 0x10007828, 0x03 },
+ { 0x10007829, 0xc7 },
+ { 0x1000782a, 0x01 },
+ { 0x1000782b, 0x42 },
+ { 0x1000782c, 0x63 },
+ { 0x1000782d, 0x10 },
+ { 0x1000782e, 0x07 },
+ { 0x1000782f, 0x02 },
+ { 0x10007830, 0x83 },
+ { 0x10007831, 0xc6 },
+ { 0x10007832, 0x21 },
+ { 0x10007833, 0x41 },
+ { 0x10007834, 0x13 },
+ { 0x10007835, 0x07 },
+ { 0x10007836, 0xf0 },
+ { 0x10007837, 0x01 },
+ { 0x10007838, 0x13 },
+ { 0x10007839, 0x05 },
+ { 0x1000783a, 0xf0 },
+ { 0x1000783b, 0x01 },
+ { 0x1000783c, 0x63 },
+ { 0x1000783d, 0x98 },
+ { 0x1000783e, 0xe6 },
+ { 0x1000783f, 0x02 },
+ { 0x10007840, 0x63 },
+ { 0x10007841, 0x8a },
+ { 0x10007842, 0x07 },
+ { 0x10007843, 0x02 },
+ { 0x10007844, 0x83 },
+ { 0x10007845, 0xc7 },
+ { 0x10007846, 0x01 },
+ { 0x10007847, 0x42 },
+ { 0x10007848, 0x63 },
+ { 0x10007849, 0x86 },
+ { 0x1000784a, 0x07 },
+ { 0x1000784b, 0x02 },
+ { 0x1000784c, 0x83 },
+ { 0x1000784d, 0xc7 },
+ { 0x1000784e, 0x31 },
+ { 0x1000784f, 0x42 },
+ { 0x10007850, 0x63 },
+ { 0x10007851, 0x86 },
+ { 0x10007852, 0x07 },
+ { 0x10007853, 0x00 },
+ { 0x10007854, 0x83 },
+ { 0x10007855, 0xc7 },
+ { 0x10007856, 0x21 },
+ { 0x10007857, 0x42 },
+ { 0x10007858, 0x63 },
+ { 0x10007859, 0x9e },
+ { 0x1000785a, 0x07 },
+ { 0x1000785b, 0x00 },
+ { 0x1000785c, 0x03 },
+ { 0x1000785d, 0xc7 },
+ { 0x1000785e, 0x21 },
+ { 0x1000785f, 0x41 },
+ { 0x10007860, 0x93 },
+ { 0x10007861, 0x07 },
+ { 0x10007862, 0xb0 },
+ { 0x10007863, 0x01 },
+ { 0x10007864, 0x63 },
+ { 0x10007865, 0x08 },
+ { 0x10007866, 0xf7 },
+ { 0x10007867, 0x00 },
+ { 0x10007868, 0x13 },
+ { 0x10007869, 0x05 },
+ { 0x1000786a, 0xb0 },
+ { 0x1000786b, 0x01 },
+ { 0x1000786c, 0xef },
+ { 0x1000786d, 0xd0 },
+ { 0x1000786e, 0x0f },
+ { 0x1000786f, 0xcf },
+ { 0x10007870, 0xef },
+ { 0x10007871, 0xd0 },
+ { 0x10007872, 0x8f },
+ { 0x10007873, 0xa4 },
+ { 0x10007874, 0x93 },
+ { 0x10007875, 0x06 },
+ { 0x10007876, 0x10 },
+ { 0x10007877, 0x00 },
+ { 0x10007878, 0xa3 },
+ { 0x10007879, 0x89 },
+ { 0x1000787a, 0xd1 },
+ { 0x1000787b, 0x40 },
+ { 0x1000787c, 0x37 },
+ { 0x1000787d, 0xd7 },
+ { 0x1000787e, 0x00 },
+ { 0x1000787f, 0x10 },
+ { 0x10007880, 0x83 },
+ { 0x10007881, 0x47 },
+ { 0x10007882, 0x07 },
+ { 0x10007883, 0xd9 },
+ { 0x10007884, 0x93 },
+ { 0x10007885, 0xf7 },
+ { 0x10007886, 0xf7 },
+ { 0x10007887, 0x0f },
+ { 0x10007888, 0x63 },
+ { 0x10007889, 0x90 },
+ { 0x1000788a, 0x07 },
+ { 0x1000788b, 0x02 },
+ { 0x1000788c, 0x37 },
+ { 0x1000788d, 0xc6 },
+ { 0x1000788e, 0x00 },
+ { 0x1000788f, 0x00 },
+ { 0x10007890, 0x83 },
+ { 0x10007891, 0x47 },
+ { 0x10007892, 0x26 },
+ { 0x10007893, 0x04 },
+ { 0x10007894, 0x93 },
+ { 0x10007895, 0xe7 },
+ { 0x10007896, 0x07 },
+ { 0x10007897, 0xf8 },
+ { 0x10007898, 0x93 },
+ { 0x10007899, 0xf7 },
+ { 0x1000789a, 0xf7 },
+ { 0x1000789b, 0x0f },
+ { 0x1000789c, 0x23 },
+ { 0x1000789d, 0x01 },
+ { 0x1000789e, 0xf6 },
+ { 0x1000789f, 0x04 },
+ { 0x100078a0, 0x23 },
+ { 0x100078a1, 0x08 },
+ { 0x100078a2, 0xd7 },
+ { 0x100078a3, 0xd8 },
+ { 0x100078a4, 0x23 },
+ { 0x100078a5, 0x09 },
+ { 0x100078a6, 0x07 },
+ { 0x100078a7, 0xd8 },
+ { 0x100078a8, 0x83 },
+ { 0x100078a9, 0x20 },
+ { 0x100078aa, 0xc1 },
+ { 0x100078ab, 0x00 },
+ { 0x100078ac, 0x13 },
+ { 0x100078ad, 0x01 },
+ { 0x100078ae, 0x01 },
+ { 0x100078af, 0x01 },
+ { 0x100078b0, 0x67 },
+ { 0x100078b1, 0x80 },
+ { 0x100078b2, 0x00 },
+ { 0x100078b3, 0x00 },
+ { 0x3fc2bfc7, 0x00 },
+ { 0x3fc2bfc6, 0x00 },
+ { 0x3fc2bfc5, 0x00 },
+ { 0x3fc2bfc4, 0x01 },
+ { 0x0000d486, 0x43 },
+ { 0x1000db00, 0x02 },
+ { 0x1000db01, 0x00 },
+ { 0x1000db02, 0x11 },
+ { 0x1000db03, 0x00 },
+ { 0x1000db04, 0x00 },
+ { 0x1000db05, 0x82 },
+ { 0x1000db06, 0x04 },
+ { 0x1000db07, 0xf1 },
+ { 0x1000db08, 0x00 },
+ { 0x1000db09, 0x00 },
+ { 0x1000db0a, 0x40 },
+ { 0x0000d540, 0x01 },
+};
+
+static const struct reg_default rt1320_reg_defaults[] = {
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x0b },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE27, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+};
+
+static const struct reg_default rt1320_mbq_defaults[] = {
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+};
+
+static bool rt1320_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0xc000 ... 0xc086:
+ case 0xc400 ... 0xc409:
+ case 0xc480 ... 0xc48f:
+ case 0xc4c0 ... 0xc4c4:
+ case 0xc4e0 ... 0xc4e7:
+ case 0xc500:
+ case 0xc560 ... 0xc56b:
+ case 0xc570:
+ case 0xc580 ... 0xc59a:
+ case 0xc5b0 ... 0xc60f:
+ case 0xc640 ... 0xc64f:
+ case 0xc670:
+ case 0xc680 ... 0xc683:
+ case 0xc700 ... 0xc76f:
+ case 0xc800 ... 0xc801:
+ case 0xc820:
+ case 0xc900 ... 0xc901:
+ case 0xc920 ... 0xc921:
+ case 0xca00 ... 0xca07:
+ case 0xca20 ... 0xca27:
+ case 0xca40 ... 0xca4b:
+ case 0xca60 ... 0xca68:
+ case 0xca80 ... 0xca88:
+ case 0xcb00 ... 0xcb0c:
+ case 0xcc00 ... 0xcc12:
+ case 0xcc80 ... 0xcc81:
+ case 0xcd00:
+ case 0xcd80 ... 0xcd82:
+ case 0xce00 ... 0xce4d:
+ case 0xcf00 ... 0xcf25:
+ case 0xd000 ... 0xd0ff:
+ case 0xd100 ... 0xd1ff:
+ case 0xd200 ... 0xd2ff:
+ case 0xd300 ... 0xd3ff:
+ case 0xd400 ... 0xd403:
+ case 0xd410 ... 0xd417:
+ case 0xd470 ... 0xd497:
+ case 0xd4dc ... 0xd50f:
+ case 0xd520 ... 0xd543:
+ case 0xd560 ... 0xd5ef:
+ case 0xd600 ... 0xd663:
+ case 0xda00 ... 0xda6e:
+ case 0xda80 ... 0xda9e:
+ case 0xdb00 ... 0xdb7f:
+ case 0xdc00:
+ case 0xdc20 ... 0xdc21:
+ case 0xdd00 ... 0xdd17:
+ case 0xde00 ... 0xde09:
+ case 0xdf00 ... 0xdf1b:
+ case 0xe000 ... 0xe847:
+ case 0xf717 ... 0xf719:
+ case 0xf720 ... 0xf723:
+ case 0x1000f008:
+ case 0x3fe2e000 ... 0x3fe2e003:
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE27, RT1320_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt1320_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0xc402 ... 0xc406:
+ case 0xc48c ... 0xc48f:
+ case 0xc560:
+ case 0xc5b5 ... 0xc5b7:
+ case 0xc5fc ... 0xc5ff:
+ case 0xc820:
+ case 0xc900:
+ case 0xc920:
+ case 0xca42:
+ case 0xca62:
+ case 0xca82:
+ case 0xcd00:
+ case 0xce03:
+ case 0xce10:
+ case 0xce14 ... 0xce17:
+ case 0xce44 ... 0xce49:
+ case 0xce4c ... 0xce4d:
+ case 0xcf0c:
+ case 0xcf10 ... 0xcf25:
+ case 0xd486 ... 0xd487:
+ case 0xd4e5 ... 0xd4e6:
+ case 0xd4e8 ... 0xd4ff:
+ case 0xd530:
+ case 0xd540:
+ case 0xd543:
+ case 0xdb58 ... 0xdb5f:
+ case 0xdb60 ... 0xdb63:
+ case 0xdb68 ... 0xdb69:
+ case 0xdb6d:
+ case 0xdb70 ... 0xdb71:
+ case 0xdb76:
+ case 0xdb7a:
+ case 0xdb7c ... 0xdb7f:
+ case 0xdd0c ... 0xdd13:
+ case 0xde02:
+ case 0xdf14 ... 0xdf1b:
+ case 0xe83c ... 0xe847:
+ case 0xf717 ... 0xf719:
+ case 0xf720 ... 0xf723:
+ case 0x10000000 ... 0x10007fff:
+ case 0x1000c000 ... 0x1000dfff:
+ case 0x1000f008:
+ case 0x3fc2bfc4 ... 0x3fc2bfc7:
+ case 0x3fe2e000 ... 0x3fe2e003:
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt1320_mbq_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rt1320_sdw_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt1320_readable_register,
+ .volatile_reg = rt1320_volatile_register,
+ .max_register = 0x41081488,
+ .reg_defaults = rt1320_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt1320_reg_defaults),
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static const struct regmap_config rt1320_mbq_regmap = {
+ .name = "sdw-mbq",
+ .reg_bits = 32,
+ .val_bits = 16,
+ .readable_reg = rt1320_mbq_readable_register,
+ .max_register = 0x41000192,
+ .reg_defaults = rt1320_mbq_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt1320_mbq_defaults),
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt1320_read_prop(struct sdw_slave *slave)
+{
+ struct sdw_slave_prop *prop = &slave->prop;
+ int nval;
+ int i, j;
+ u32 bit;
+ unsigned long addr;
+ struct sdw_dpn_prop *dpn;
+
+ /*
+ * Due to support the multi-lane, we call 'sdw_slave_read_prop' to get the lane mapping
+ */
+ sdw_slave_read_prop(slave);
+
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+
+ prop->paging_support = true;
+ prop->lane_control_support = true;
+
+ /* first we need to allocate memory for set bits in port lists */
+ prop->source_ports = BIT(4);
+ prop->sink_ports = BIT(1);
+
+ nval = hweight32(prop->source_ports);
+ prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->src_dpn_prop), GFP_KERNEL);
+ if (!prop->src_dpn_prop)
+ return -ENOMEM;
+
+ i = 0;
+ dpn = prop->src_dpn_prop;
+ addr = prop->source_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[i].num = bit;
+ dpn[i].type = SDW_DPN_FULL;
+ dpn[i].simple_ch_prep_sm = true;
+ dpn[i].ch_prep_timeout = 10;
+ i++;
+ }
+
+ /* do this again for sink now */
+ nval = hweight32(prop->sink_ports);
+ prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+ if (!prop->sink_dpn_prop)
+ return -ENOMEM;
+
+ j = 0;
+ dpn = prop->sink_dpn_prop;
+ addr = prop->sink_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[j].num = bit;
+ dpn[j].type = SDW_DPN_FULL;
+ dpn[j].simple_ch_prep_sm = true;
+ dpn[j].ch_prep_timeout = 10;
+ j++;
+ }
+
+ /* set the timeout values */
+ prop->clk_stop_timeout = 64;
+
+ return 0;
+}
+
+static int rt1320_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev);
+ unsigned int amp_func_status, val, tmp;
+
+ if (rt1320->hw_init)
+ return 0;
+
+ regcache_cache_only(rt1320->regmap, false);
+ regcache_cache_only(rt1320->mbq_regmap, false);
+ if (rt1320->first_hw_init) {
+ regcache_cache_bypass(rt1320->regmap, true);
+ regcache_cache_bypass(rt1320->mbq_regmap, true);
+ } else {
+ /*
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
+ */
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+
+ if (rt1320->version_id < 0) {
+ regmap_read(rt1320->regmap, RT1320_DEV_VERSION_ID_1, &val);
+ rt1320->version_id = val;
+ }
+
+ regmap_read(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0), &amp_func_status);
+ dev_dbg(dev, "%s amp func_status=0x%x\n", __func__, amp_func_status);
+
+ /* initialization write */
+ if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt1320->first_hw_init)) {
+ regmap_multi_reg_write(rt1320->regmap, rt1320_blind_write, ARRAY_SIZE(rt1320_blind_write));
+ regmap_multi_reg_write(rt1320->regmap, rt1320_patch_code_write,
+ ARRAY_SIZE(rt1320_patch_code_write));
+
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0),
+ FUNCTION_NEEDS_INITIALIZATION);
+ }
+ if (!rt1320->first_hw_init) {
+ regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
+ RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0);
+ regmap_read(rt1320->regmap, RT1320_HIFI_VER_0, &val);
+ regmap_read(rt1320->regmap, RT1320_HIFI_VER_1, &tmp);
+ val = (tmp << 8) | val;
+ regmap_read(rt1320->regmap, RT1320_HIFI_VER_2, &tmp);
+ val = (tmp << 16) | val;
+ regmap_read(rt1320->regmap, RT1320_HIFI_VER_3, &tmp);
+ val = (tmp << 24) | val;
+ dev_dbg(dev, "%s ROM version=0x%x\n", __func__, val);
+ /*
+ * We call the version b which has the new DSP ROM code against version a.
+ * Therefore, we read the DSP address to check the ID.
+ */
+ if (val == RT1320_VER_B_ID)
+ rt1320->version_id = RT1320_VB;
+ regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
+ RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 3);
+ }
+ dev_dbg(dev, "%s version_id=%d\n", __func__, rt1320->version_id);
+
+ if (rt1320->first_hw_init) {
+ regcache_cache_bypass(rt1320->regmap, false);
+ regcache_cache_bypass(rt1320->mbq_regmap, false);
+ regcache_mark_dirty(rt1320->regmap);
+ regcache_mark_dirty(rt1320->mbq_regmap);
+ }
+
+ /* Mark Slave initialization complete */
+ rt1320->first_hw_init = true;
+ rt1320->hw_init = true;
+
+ pm_runtime_mark_last_busy(&slave->dev);
+ pm_runtime_put_autosuspend(&slave->dev);
+
+ dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
+ return 0;
+}
+
+static int rt1320_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(&slave->dev);
+
+ if (status == SDW_SLAVE_UNATTACHED)
+ rt1320->hw_init = false;
+
+ /*
+ * Perform initialization only if slave status is present and
+ * hw_init flag is false
+ */
+ if (rt1320->hw_init || status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt1320_io_init(&slave->dev, slave);
+}
+
+static int rt1320_pde23_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 rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
+ RT1320_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
+ RT1320_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int rt1320_set_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ unsigned int read_l, read_r, gain_l_val, gain_r_val;
+ unsigned int lvalue, rvalue;
+ const unsigned int interval_offset = 0xc0;
+
+ regmap_read(rt1320->mbq_regmap, mc->reg, &lvalue);
+ regmap_read(rt1320->mbq_regmap, mc->rreg, &rvalue);
+
+ /* L Channel */
+ gain_l_val = ucontrol->value.integer.value[0];
+ if (gain_l_val > mc->max)
+ gain_l_val = mc->max;
+ gain_l_val = 0 - ((mc->max - gain_l_val) * interval_offset);
+ gain_l_val &= 0xffff;
+
+ /* R Channel */
+ gain_r_val = ucontrol->value.integer.value[1];
+ if (gain_r_val > mc->max)
+ gain_r_val = mc->max;
+ gain_r_val = 0 - ((mc->max - gain_r_val) * interval_offset);
+ gain_r_val &= 0xffff;
+
+ if (lvalue == gain_l_val && rvalue == gain_r_val)
+ return 0;
+
+ /* Lch*/
+ regmap_write(rt1320->mbq_regmap, mc->reg, gain_l_val);
+ /* Rch */
+ regmap_write(rt1320->mbq_regmap, mc->rreg, gain_r_val);
+
+ regmap_read(rt1320->mbq_regmap, mc->reg, &read_l);
+ regmap_read(rt1320->mbq_regmap, mc->rreg, &read_r);
+ if (read_r == gain_r_val && read_l == gain_l_val)
+ return 1;
+
+ return -EIO;
+}
+
+static int rt1320_set_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0;
+ const unsigned int interval_offset = 0xc0;
+
+ regmap_read(rt1320->mbq_regmap, mc->reg, &read_l);
+ regmap_read(rt1320->mbq_regmap, mc->rreg, &read_r);
+
+ ctl_l = mc->max - (((0 - read_l) & 0xffff) / interval_offset);
+
+ if (read_l != read_r)
+ ctl_r = mc->max - (((0 - read_r) & 0xffff) / interval_offset);
+ else
+ ctl_r = ctl_l;
+
+ ucontrol->value.integer.value[0] = ctl_l;
+ ucontrol->value.integer.value[1] = ctl_r;
+ return 0;
+}
+
+static const char * const rt1320_rx_data_ch_select[] = {
+ "L,R",
+ "R,L",
+ "L,L",
+ "R,R",
+ "L,L+R",
+ "R,L+R",
+ "L+R,L",
+ "L+R,R",
+ "L+R,L+R",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1320_rx_data_ch_enum,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0), 0,
+ rt1320_rx_data_ch_select);
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0);
+
+static const struct snd_kcontrol_new rt1320_snd_controls[] = {
+ SOC_DOUBLE_R_EXT_TLV("FU21 Playback Volume",
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01),
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02),
+ 0, 0x57, 0, rt1320_set_gain_get, rt1320_set_gain_put, out_vol_tlv),
+ SOC_ENUM("RX Channel Select", rt1320_rx_data_ch_enum),
+};
+
+static const struct snd_kcontrol_new rt1320_spk_l_dac =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01),
+ 0, 1, 1);
+static const struct snd_kcontrol_new rt1320_spk_r_dac =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02),
+ 0, 1, 1);
+
+static const struct snd_soc_dapm_widget rt1320_dapm_widgets[] = {
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Digital Interface */
+ SND_SOC_DAPM_PGA("FU21", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0,
+ rt1320_pde23_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ /* Output */
+ SND_SOC_DAPM_SWITCH("OT23 L", SND_SOC_NOPM, 0, 0, &rt1320_spk_l_dac),
+ SND_SOC_DAPM_SWITCH("OT23 R", SND_SOC_NOPM, 0, 0, &rt1320_spk_r_dac),
+ SND_SOC_DAPM_OUTPUT("SPOL"),
+ SND_SOC_DAPM_OUTPUT("SPOR"),
+
+ /* Input */
+ SND_SOC_DAPM_PGA("AEC Data", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SIGGEN("AEC Gen"),
+};
+
+static const struct snd_soc_dapm_route rt1320_dapm_routes[] = {
+ { "FU21", NULL, "DP1RX" },
+ { "FU21", NULL, "PDE 23" },
+ { "OT23 L", "Switch", "FU21" },
+ { "OT23 R", "Switch", "FU21" },
+ { "SPOL", NULL, "OT23 L" },
+ { "SPOR", NULL, "OT23 R" },
+
+ { "AEC Data", NULL, "AEC Gen" },
+ { "DP4TX", NULL, "AEC Data" },
+};
+
+static int rt1320_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+ int direction)
+{
+ snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+ return 0;
+}
+
+static void rt1320_sdw_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1320_sdw_priv *rt1320 =
+ snd_soc_component_get_drvdata(component);
+ struct sdw_stream_config stream_config;
+ struct sdw_port_config port_config;
+ struct sdw_stream_runtime *sdw_stream;
+ int retval;
+ unsigned int sampling_rate;
+
+ dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+ sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ if (!rt1320->sdw_slave)
+ return -EINVAL;
+
+ /* SoundWire specific configuration */
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (dai->id == RT1320_AIF1)
+ port_config.num = 1;
+ else
+ return -EINVAL;
+ } else {
+ if (dai->id == RT1320_AIF1)
+ port_config.num = 4;
+ else
+ return -EINVAL;
+ }
+
+ retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config,
+ &port_config, 1, sdw_stream);
+ if (retval) {
+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
+ return retval;
+ }
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 16000:
+ sampling_rate = RT1320_SDCA_RATE_16000HZ;
+ break;
+ case 32000:
+ sampling_rate = RT1320_SDCA_RATE_32000HZ;
+ break;
+ case 44100:
+ sampling_rate = RT1320_SDCA_RATE_44100HZ;
+ break;
+ case 48000:
+ sampling_rate = RT1320_SDCA_RATE_48000HZ;
+ break;
+ case 96000:
+ sampling_rate = RT1320_SDCA_RATE_96000HZ;
+ break;
+ case 192000:
+ sampling_rate = RT1320_SDCA_RATE_192000HZ;
+ break;
+ default:
+ dev_err(component->dev, "%s: Rate %d is not supported\n",
+ __func__, params_rate(params));
+ return -EINVAL;
+ }
+
+ /* set sampling frequency */
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+
+ return 0;
+}
+
+static int rt1320_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1320_sdw_priv *rt1320 =
+ snd_soc_component_get_drvdata(component);
+ struct sdw_stream_runtime *sdw_stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt1320->sdw_slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt1320->sdw_slave, sdw_stream);
+ return 0;
+}
+
+/*
+ * slave_ops: callbacks for get_clock_stop_mode, clock_stop and
+ * port_prep are not defined for now
+ */
+static const struct sdw_slave_ops rt1320_slave_ops = {
+ .read_prop = rt1320_read_prop,
+ .update_status = rt1320_update_status,
+};
+
+static int rt1320_sdw_component_probe(struct snd_soc_component *component)
+{
+ int ret;
+ struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+
+ rt1320->component = component;
+
+ if (!rt1320->first_hw_init)
+ return 0;
+
+ ret = pm_runtime_resume(component->dev);
+ dev_dbg(&rt1320->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_sdw_rt1320 = {
+ .probe = rt1320_sdw_component_probe,
+ .controls = rt1320_snd_controls,
+ .num_controls = ARRAY_SIZE(rt1320_snd_controls),
+ .dapm_widgets = rt1320_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt1320_dapm_widgets),
+ .dapm_routes = rt1320_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt1320_dapm_routes),
+ .endianness = 1,
+};
+
+static const struct snd_soc_dai_ops rt1320_aif_dai_ops = {
+ .hw_params = rt1320_sdw_hw_params,
+ .hw_free = rt1320_sdw_pcm_hw_free,
+ .set_stream = rt1320_set_sdw_stream,
+ .shutdown = rt1320_sdw_shutdown,
+};
+
+#define RT1320_STEREO_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define RT1320_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver rt1320_sdw_dai[] = {
+ {
+ .name = "rt1320-aif1",
+ .id = RT1320_AIF1,
+ .playback = {
+ .stream_name = "DP1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT1320_STEREO_RATES,
+ .formats = RT1320_FORMATS,
+ },
+ .capture = {
+ .stream_name = "DP4 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT1320_STEREO_RATES,
+ .formats = RT1320_FORMATS,
+ },
+ .ops = &rt1320_aif_dai_ops,
+ },
+};
+
+static int rt1320_sdw_init(struct device *dev, struct regmap *regmap,
+ struct regmap *mbq_regmap, struct sdw_slave *slave)
+{
+ struct rt1320_sdw_priv *rt1320;
+ int ret;
+
+ rt1320 = devm_kzalloc(dev, sizeof(*rt1320), GFP_KERNEL);
+ if (!rt1320)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt1320);
+ rt1320->sdw_slave = slave;
+ rt1320->mbq_regmap = mbq_regmap;
+ rt1320->regmap = regmap;
+
+ regcache_cache_only(rt1320->regmap, true);
+ regcache_cache_only(rt1320->mbq_regmap, true);
+
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt1320->hw_init = false;
+ rt1320->first_hw_init = false;
+ rt1320->version_id = -1;
+
+ ret = devm_snd_soc_register_component(dev,
+ &soc_component_sdw_rt1320,
+ rt1320_sdw_dai,
+ ARRAY_SIZE(rt1320_sdw_dai));
+ if (ret < 0)
+ return ret;
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ return ret;
+}
+
+static int rt1320_sdw_probe(struct sdw_slave *slave,
+ const struct sdw_device_id *id)
+{
+ struct regmap *regmap, *mbq_regmap;
+
+ /* Regmap Initialization */
+ mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt1320_mbq_regmap);
+ if (IS_ERR(mbq_regmap))
+ return PTR_ERR(mbq_regmap);
+
+ regmap = devm_regmap_init_sdw(slave, &rt1320_sdw_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt1320_sdw_init(&slave->dev, regmap, mbq_regmap, slave);
+}
+
+static int rt1320_sdw_remove(struct sdw_slave *slave)
+{
+ pm_runtime_disable(&slave->dev);
+
+ return 0;
+}
+
+/*
+ * Version A/B will use the class id 0
+ * The newer version than A/B will use the class id 1, so add it in advance
+ */
+static const struct sdw_device_id rt1320_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x1320, 0x3, 0x0, 0),
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x1320, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt1320_id);
+
+static int __maybe_unused rt1320_dev_suspend(struct device *dev)
+{
+ struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev);
+
+ if (!rt1320->hw_init)
+ return 0;
+
+ regcache_cache_only(rt1320->regmap, true);
+ regcache_cache_only(rt1320->mbq_regmap, true);
+ return 0;
+}
+
+#define RT1320_PROBE_TIMEOUT 5000
+
+static int __maybe_unused rt1320_dev_resume(struct device *dev)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev);
+ unsigned long time;
+
+ if (!rt1320->first_hw_init)
+ return 0;
+
+ if (!slave->unattach_request)
+ goto regmap_sync;
+
+ time = wait_for_completion_timeout(&slave->initialization_complete,
+ msecs_to_jiffies(RT1320_PROBE_TIMEOUT));
+ if (!time) {
+ dev_err(&slave->dev, "%s: Initialization not complete, timed out\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+regmap_sync:
+ slave->unattach_request = 0;
+ regcache_cache_only(rt1320->regmap, false);
+ regcache_sync(rt1320->regmap);
+ regcache_cache_only(rt1320->mbq_regmap, false);
+ regcache_sync(rt1320->mbq_regmap);
+ return 0;
+}
+
+static const struct dev_pm_ops rt1320_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rt1320_dev_suspend, rt1320_dev_resume)
+ SET_RUNTIME_PM_OPS(rt1320_dev_suspend, rt1320_dev_resume, NULL)
+};
+
+static struct sdw_driver rt1320_sdw_driver = {
+ .driver = {
+ .name = "rt1320-sdca",
+ .pm = &rt1320_pm,
+ },
+ .probe = rt1320_sdw_probe,
+ .remove = rt1320_sdw_remove,
+ .ops = &rt1320_slave_ops,
+ .id_table = rt1320_id,
+};
+module_sdw_driver(rt1320_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT1320 driver SDCA SDW");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h
new file mode 100644
index 000000000000..b23228e74568
--- /dev/null
+++ b/sound/soc/codecs/rt1320-sdw.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt1320-sdw.h -- RT1320 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2024 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT1320_SDW_H__
+#define __RT1320_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/soc.h>
+
+/* imp-defined registers */
+#define RT1320_DEV_VERSION_ID_1 0xc404
+
+#define RT1320_KR0_STATUS_CNT 0x1000f008
+#define RT1320_HIFI_VER_0 0x3fe2e000
+#define RT1320_HIFI_VER_1 0x3fe2e001
+#define RT1320_HIFI_VER_2 0x3fe2e002
+#define RT1320_HIFI_VER_3 0x3fe2e003
+
+/* RT1320 SDCA Control - function number */
+#define FUNC_NUM_AMP 0x04
+
+/* RT1320 SDCA entity */
+#define RT1320_SDCA_ENT0 0x00
+#define RT1320_SDCA_ENT_PDE11 0x2a
+#define RT1320_SDCA_ENT_PDE23 0x33
+#define RT1320_SDCA_ENT_PDE27 0x27
+#define RT1320_SDCA_ENT_FU14 0x32
+#define RT1320_SDCA_ENT_FU21 0x03
+#define RT1320_SDCA_ENT_FU113 0x30
+#define RT1320_SDCA_ENT_CS14 0x13
+#define RT1320_SDCA_ENT_CS21 0x21
+#define RT1320_SDCA_ENT_CS113 0x12
+#define RT1320_SDCA_ENT_SAPU 0x29
+#define RT1320_SDCA_ENT_PPU21 0x04
+
+/* RT1320 SDCA control */
+#define RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10
+#define RT1320_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT1320_SDCA_CTL_FU_MUTE 0x01
+#define RT1320_SDCA_CTL_FU_VOLUME 0x02
+#define RT1320_SDCA_CTL_SAPU_PROTECTION_MODE 0x10
+#define RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS 0x11
+#define RT1320_SDCA_CTL_POSTURE_NUMBER 0x10
+#define RT1320_SDCA_CTL_FUNC_STATUS 0x10
+
+/* RT1320 SDCA channel */
+#define CH_01 0x01
+#define CH_02 0x02
+
+/* Function_Status */
+#define FUNCTION_NEEDS_INITIALIZATION BIT(5)
+
+/* Sample Frequency Index */
+#define RT1320_SDCA_RATE_16000HZ 0x04
+#define RT1320_SDCA_RATE_32000HZ 0x07
+#define RT1320_SDCA_RATE_44100HZ 0x08
+#define RT1320_SDCA_RATE_48000HZ 0x09
+#define RT1320_SDCA_RATE_96000HZ 0x0b
+#define RT1320_SDCA_RATE_192000HZ 0x0d
+
+enum {
+ RT1320_AIF1,
+};
+
+/*
+ * The version id will be useful to distinguish the capability between the different IC versions.
+ * Currently, VA and VB have different DSP FW versions.
+ */
+enum rt1320_version_id {
+ RT1320_VA,
+ RT1320_VB,
+};
+
+#define RT1320_VER_B_ID 0x07392238
+
+struct rt1320_sdw_priv {
+ struct snd_soc_component *component;
+ struct regmap *regmap;
+ struct regmap *mbq_regmap;
+ struct sdw_slave *sdw_slave;
+ struct sdw_bus_params params;
+ bool hw_init;
+ bool first_hw_init;
+ int version_id;
+};
+
+#endif /* __RT1320_SDW_H__ */
diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c
index 1e8dbfc3ecd9..dd6ccf17afd4 100644
--- a/sound/soc/codecs/rt711-sdca.c
+++ b/sound/soc/codecs/rt711-sdca.c
@@ -81,6 +81,24 @@ static void rt711_sdca_reset(struct rt711_sdca_priv *rt711)
RT711_HDA_LEGACY_RESET_CTL, 0x1, 0x1);
}
+static void rt711_sdca_ge_force_jack_type(struct rt711_sdca_priv *rt711, unsigned int det_mode)
+{
+ switch (det_mode) {
+ case 0x00:
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, RT711_COMBO_JACK_AUTO_CTL1, 0x8400, 0x0000);
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, RT711_PUSH_BTN_INT_CTL0, 0x10, 0x00);
+ break;
+ case 0x03:
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, RT711_COMBO_JACK_AUTO_CTL1, 0x8400, 0x8000);
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, RT711_PUSH_BTN_INT_CTL0, 0x17, 0x13);
+ break;
+ case 0x05:
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, RT711_COMBO_JACK_AUTO_CTL1, 0x8400, 0x8400);
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, RT711_PUSH_BTN_INT_CTL0, 0x17, 0x15);
+ break;
+ }
+}
+
static int rt711_sdca_calibration(struct rt711_sdca_priv *rt711)
{
unsigned int val, loop_rc = 0, loop_dc = 0;
@@ -248,6 +266,8 @@ static int rt711_sdca_headset_detect(struct rt711_sdca_priv *rt711)
unsigned int det_mode;
int ret;
+ rt711_sdca_ge_force_jack_type(rt711, rt711->ge_mode_override);
+
/* get detected_mode */
ret = regmap_read(rt711->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_DETECTED_MODE, 0),
@@ -790,6 +810,56 @@ static int rt711_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol,
return changed;
}
+static int rt711_sdca_ge_select_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ unsigned int val, item;
+
+ val = (rt711->ge_mode_override >> e->shift_l) & e->mask;
+ item = snd_soc_enum_val_to_item(e, val);
+ ucontrol->value.enumerated.item[0] = item;
+ return 0;
+}
+
+static int rt711_sdca_ge_select_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ unsigned int val, change = 0;
+
+ if (item[0] >= e->items)
+ return -EINVAL;
+
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+ if (rt711->ge_mode_override != val) {
+ rt711->ge_mode_override = val;
+ change = 1;
+ }
+
+ return change;
+}
+
+static const char * const rt711_sdca_ge_select[] = {
+ "Auto",
+ "Headphone",
+ "Headset",
+};
+
+static int rt711_sdca_ge_select_values[] = {
+ 0,
+ 3,
+ 5,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt711_sdca_ge_mode_enum, SND_SOC_NOPM,
+ 0, 0x7, rt711_sdca_ge_select, rt711_sdca_ge_select_values);
+
static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0);
static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
@@ -824,6 +894,8 @@ static const struct snd_kcontrol_new rt711_sdca_snd_controls[] = {
SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_R),
8, 3, 0,
rt711_sdca_set_gain_get, rt711_sdca_set_gain_put, mic_vol_tlv),
+ SOC_ENUM_EXT("GE49 Selected Mode", rt711_sdca_ge_mode_enum,
+ rt711_sdca_ge_select_get, rt711_sdca_ge_select_put),
};
static int rt711_sdca_mux_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/codecs/rt711-sdca.h b/sound/soc/codecs/rt711-sdca.h
index 11d421e8ab2b..15263dcb0314 100644
--- a/sound/soc/codecs/rt711-sdca.h
+++ b/sound/soc/codecs/rt711-sdca.h
@@ -33,6 +33,7 @@ struct rt711_sdca_priv {
int hw_ver;
bool fu0f_dapm_mute, fu0f_mixer_l_mute, fu0f_mixer_r_mute;
bool fu1e_dapm_mute, fu1e_mixer_l_mute, fu1e_mixer_r_mute;
+ unsigned int ge_mode_override;
};
/* NID */
diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c
index ce337db86d1a..90d5aaddbd5b 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -34,6 +34,10 @@ static bool rt712_sdca_readable_register(struct device *dev, unsigned int reg)
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_GE49, RT712_SDCA_CTL_DETECTED_MODE, 0):
case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ...
SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
case RT712_BUF_ADDR_HID1 ... RT712_BUF_ADDR_HID2:
return true;
default:
@@ -56,6 +60,10 @@ static bool rt712_sdca_volatile_register(struct device *dev, unsigned int reg)
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_GE49, RT712_SDCA_CTL_DETECTED_MODE, 0):
case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ...
SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
case RT712_BUF_ADDR_HID1 ... RT712_BUF_ADDR_HID2:
return true;
default:
@@ -78,13 +86,21 @@ static bool rt712_sdca_mbq_readable_register(struct device *dev, unsigned int re
case 0x5c00000 ... 0x5c0009a:
case 0x5d00000 ... 0x5d00009:
case 0x5f00000 ... 0x5f00030:
- case 0x6100000 ... 0x6100068:
- case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L):
- case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R):
- case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L):
- case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R):
- case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L):
- case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R):
+ case 0x6100000 ... 0x61000f1:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_03):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_04):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_03):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_04):
return true;
default:
return false;
@@ -96,7 +112,9 @@ static bool rt712_sdca_mbq_volatile_register(struct device *dev, unsigned int re
switch (reg) {
case 0x2000000:
case 0x200001a:
+ case 0x2000020:
case 0x2000024:
+ case 0x2000030:
case 0x2000046:
case 0x200008a:
case 0x5800000:
@@ -178,13 +196,15 @@ static int rt712_sdca_read_prop(struct sdw_slave *slave)
unsigned long addr;
struct sdw_dpn_prop *dpn;
+ sdw_slave_read_prop(slave);
+
prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
prop->paging_support = true;
/* first we need to allocate memory for set bits in port lists */
- prop->source_ports = BIT(4); /* BITMAP: 00010000 */
+ prop->source_ports = BIT(8) | BIT(4); /* BITMAP: 100010000 */
prop->sink_ports = BIT(3) | BIT(1); /* BITMAP: 00001010 */
nval = hweight32(prop->source_ports);
diff --git a/sound/soc/codecs/rt712-sdca-sdw.h b/sound/soc/codecs/rt712-sdca-sdw.h
index 4be22ccd8561..99fd2d67f04d 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.h
+++ b/sound/soc/codecs/rt712-sdca-sdw.h
@@ -12,68 +12,31 @@
#include <linux/soundwire/sdw_registers.h>
static const struct reg_default rt712_sdca_reg_defaults[] = {
- { 0x201a, 0x00 },
- { 0x201b, 0x00 },
- { 0x201c, 0x00 },
- { 0x201d, 0x00 },
- { 0x201e, 0x00 },
- { 0x201f, 0x00 },
- { 0x2029, 0x00 },
- { 0x202a, 0x00 },
- { 0x202d, 0x00 },
- { 0x202e, 0x00 },
- { 0x202f, 0x00 },
- { 0x2030, 0x00 },
- { 0x2031, 0x00 },
- { 0x2032, 0x00 },
- { 0x2033, 0x00 },
- { 0x2034, 0x00 },
- { 0x2230, 0x00 },
- { 0x2231, 0x2f },
- { 0x2232, 0x80 },
- { 0x2f01, 0x00 },
- { 0x2f02, 0x09 },
- { 0x2f03, 0x00 },
- { 0x2f04, 0x00 },
- { 0x2f05, 0x0b },
- { 0x2f06, 0x01 },
- { 0x2f08, 0x00 },
- { 0x2f09, 0x00 },
- { 0x2f0a, 0x01 },
- { 0x2f35, 0x01 },
- { 0x2f36, 0xcf },
- { 0x2f50, 0x0f },
- { 0x2f54, 0x01 },
- { 0x2f58, 0x07 },
- { 0x2f59, 0x09 },
- { 0x2f5a, 0x01 },
- { 0x2f5b, 0x07 },
- { 0x2f5c, 0x05 },
- { 0x2f5d, 0x05 },
- { 0x3201, 0x01 },
- { 0x320c, 0x00 },
- { 0x3301, 0x01 },
- { 0x3302, 0x00 },
- { 0x3303, 0x1f },
+
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE12, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_03), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_04), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_PDE23, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
};
static const struct reg_default rt712_sdca_mbq_defaults[] = {
{ 0x2000004, 0xaa01 },
{ 0x200000e, 0x21e0 },
- { 0x2000024, 0x01ba },
{ 0x200004a, 0x8830 },
{ 0x2000067, 0xf100 },
{ 0x5800000, 0x1893 },
@@ -81,12 +44,8 @@ static const struct reg_default rt712_sdca_mbq_defaults[] = {
{ 0x5b00005, 0x0000 },
{ 0x5b00029, 0x3fff },
{ 0x5b0002a, 0xf000 },
- { 0x5f00008, 0x7000 },
+ { 0x6100000, 0x04e4 },
{ 0x610000e, 0x0007 },
- { 0x6100022, 0x2828 },
- { 0x6100023, 0x2929 },
- { 0x6100026, 0x2c29 },
- { 0x610002c, 0x4150 },
{ 0x6100045, 0x0860 },
{ 0x6100046, 0x0029 },
{ 0x6100053, 0x3fff },
@@ -95,14 +54,22 @@ static const struct reg_default rt712_sdca_mbq_defaults[] = {
{ 0x6100064, 0x8000 },
{ 0x6100065, 0x0000 },
{ 0x6100067, 0xff12 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_L), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_R), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_03), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_04), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_03), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_04), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
};
#endif /* __RT712_SDW_H__ */
diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c
index b503de9fda80..e210c574bb74 100644
--- a/sound/soc/codecs/rt712-sdca.c
+++ b/sound/soc/codecs/rt712-sdca.c
@@ -82,7 +82,8 @@ static int rt712_sdca_calibration(struct rt712_sdca_priv *rt712)
dev = regmap_get_device(regmap);
/* Set HP-JD source from JD1 */
- rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
+ if (rt712->version_id == RT712_VA)
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
/* FSM switch to calibration manual mode */
rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_FSM_CTL, 0x4100);
@@ -198,11 +199,17 @@ static unsigned int rt712_sdca_button_detect(struct rt712_sdca_priv *rt712)
_end_btn_det_:
/* Host is owner, so set back to device */
- if (owner == 0)
+ if (owner == 0) {
/* set owner to device */
- regmap_write(rt712->regmap,
- SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01,
- RT712_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE, 0), 0x01);
+ if (rt712->version_id == RT712_VA)
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01,
+ RT712_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE, 0), 0x01);
+ else
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01,
+ RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01);
+ }
return btn_type;
}
@@ -415,8 +422,9 @@ static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712)
switch (rt712->jd_src) {
case RT712_JD1:
- /* Set HP-JD source from JD1 */
- rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
+ /* Set HP-JD source from JD1, VB uses JD1 in default */
+ if (rt712->version_id == RT712_VA)
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
break;
default:
dev_warn(rt712->component->dev, "Wrong JD source\n");
@@ -592,20 +600,20 @@ static int rt712_sdca_set_gain_get(struct snd_kcontrol *kcontrol,
static int rt712_sdca_set_fu0f_capture_ctl(struct rt712_sdca_priv *rt712)
{
int err;
- unsigned int ch_l, ch_r;
+ unsigned int ch_01, ch_02;
- ch_l = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_l_mute) ? 0x01 : 0x00;
- ch_r = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_r_mute) ? 0x01 : 0x00;
+ ch_01 = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_l_mute) ? 0x01 : 0x00;
+ ch_02 = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_r_mute) ? 0x01 : 0x00;
err = regmap_write(rt712->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F,
- RT712_SDCA_CTL_FU_MUTE, CH_L), ch_l);
+ RT712_SDCA_CTL_FU_MUTE, CH_01), ch_01);
if (err < 0)
return err;
err = regmap_write(rt712->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F,
- RT712_SDCA_CTL_FU_MUTE, CH_R), ch_r);
+ RT712_SDCA_CTL_FU_MUTE, CH_02), ch_02);
if (err < 0)
return err;
@@ -649,28 +657,28 @@ static const DECLARE_TLV_DB_SCALE(boost_vol_tlv, 0, 1000, 0);
static const struct snd_kcontrol_new rt712_sdca_controls[] = {
SOC_DOUBLE_R_EXT_TLV("FU05 Playback Volume",
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L),
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02),
0, 0x57, 0,
rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, out_vol_tlv),
SOC_DOUBLE_EXT("FU0F Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0,
rt712_sdca_fu0f_capture_get, rt712_sdca_fu0f_capture_put),
SOC_DOUBLE_R_EXT_TLV("FU0F Capture Volume",
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L),
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02),
0, 0x3f, 0,
rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, mic_vol_tlv),
SOC_DOUBLE_R_EXT_TLV("FU44 Boost Volume",
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_L),
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_R),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_01),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_02),
8, 3, 0,
rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, boost_vol_tlv),
};
static const struct snd_kcontrol_new rt712_sdca_spk_controls[] = {
SOC_DOUBLE_R_EXT_TLV("FU06 Playback Volume",
- SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L),
- SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R),
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01),
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02),
0, 0x57, 0,
rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, out_vol_tlv),
};
@@ -763,21 +771,21 @@ static int rt712_sdca_fu05_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
regmap_write(rt712->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
- RT712_SDCA_CTL_FU_MUTE, CH_L),
+ RT712_SDCA_CTL_FU_MUTE, CH_01),
unmute);
regmap_write(rt712->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
- RT712_SDCA_CTL_FU_MUTE, CH_R),
+ RT712_SDCA_CTL_FU_MUTE, CH_02),
unmute);
break;
case SND_SOC_DAPM_PRE_PMD:
regmap_write(rt712->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
- RT712_SDCA_CTL_FU_MUTE, CH_L),
+ RT712_SDCA_CTL_FU_MUTE, CH_01),
mute);
regmap_write(rt712->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
- RT712_SDCA_CTL_FU_MUTE, CH_R),
+ RT712_SDCA_CTL_FU_MUTE, CH_02),
mute);
break;
}
@@ -854,7 +862,7 @@ static int rt712_sdca_pde12_event(struct snd_soc_dapm_widget *w,
return 0;
}
-static int rt712_sdca_classd_event(struct snd_soc_dapm_widget *w,
+static int rt712_sdca_pde23_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component =
@@ -883,10 +891,13 @@ static int rt712_sdca_classd_event(struct snd_soc_dapm_widget *w,
return 0;
}
-static const struct snd_kcontrol_new rt712_spk_sto_dac =
- SOC_DAPM_DOUBLE_R("Switch",
- SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_L),
- SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_R),
+static const struct snd_kcontrol_new rt712_spk_l_dac =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01),
+ 0, 1, 1);
+static const struct snd_kcontrol_new rt712_spk_r_dac =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02),
0, 1, 1);
static const struct snd_soc_dapm_widget rt712_sdca_dapm_widgets[] = {
@@ -931,20 +942,26 @@ static const struct snd_soc_dapm_widget rt712_sdca_spk_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0),
/* Digital Interface */
- SND_SOC_DAPM_SWITCH("FU06", SND_SOC_NOPM, 0, 0, &rt712_spk_sto_dac),
+ SND_SOC_DAPM_PGA("FU06", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0,
+ rt712_sdca_pde23_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
/* Output */
- SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0,
- rt712_sdca_classd_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SWITCH("OT23 L", SND_SOC_NOPM, 0, 0, &rt712_spk_l_dac),
+ SND_SOC_DAPM_SWITCH("OT23 R", SND_SOC_NOPM, 0, 0, &rt712_spk_r_dac),
SND_SOC_DAPM_OUTPUT("SPOL"),
SND_SOC_DAPM_OUTPUT("SPOR"),
};
static const struct snd_soc_dapm_route rt712_sdca_spk_dapm_routes[] = {
- { "FU06", "Switch", "DP3RX" },
- { "CLASS D", NULL, "FU06" },
- { "SPOL", NULL, "CLASS D" },
- { "SPOR", NULL, "CLASS D" },
+ { "FU06", NULL, "DP3RX" },
+ { "FU06", NULL, "PDE 23" },
+ { "OT23 L", "Switch", "FU06" },
+ { "OT23 R", "Switch", "FU06" },
+ { "SPOL", NULL, "OT23 L" },
+ { "SPOR", NULL, "OT23 R" },
};
static int rt712_sdca_parse_dt(struct rt712_sdca_priv *rt712, struct device *dev)
@@ -983,6 +1000,376 @@ static int rt712_sdca_probe(struct snd_soc_component *component)
return 0;
}
+static int rt712_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+ struct rt712_dmic_kctrl_priv *p =
+ (struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+ unsigned int regvalue, ctl, i;
+ unsigned int adc_vol_flag = 0;
+ const unsigned int interval_offset = 0xc0;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume"))
+ adc_vol_flag = 1;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ regmap_read(rt712->mbq_regmap, p->reg_base + i, &regvalue);
+
+ if (!adc_vol_flag) /* boost gain */
+ ctl = regvalue / 0x0a00;
+ else { /* ADC gain */
+ if (adc_vol_flag)
+ ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset);
+ else
+ ctl = p->max - (((0 - regvalue) & 0xffff) / interval_offset);
+ }
+
+ ucontrol->value.integer.value[i] = ctl;
+ }
+
+ return 0;
+}
+
+static int rt712_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt712_dmic_kctrl_priv *p =
+ (struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+ struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+ unsigned int gain_val[4];
+ unsigned int i, adc_vol_flag = 0, changed = 0;
+ unsigned int regvalue[4];
+ const unsigned int interval_offset = 0xc0;
+ int err;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume"))
+ adc_vol_flag = 1;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ regmap_read(rt712->mbq_regmap, p->reg_base + i, &regvalue[i]);
+
+ gain_val[i] = ucontrol->value.integer.value[i];
+ if (gain_val[i] > p->max)
+ gain_val[i] = p->max;
+
+ if (!adc_vol_flag) /* boost gain */
+ gain_val[i] = gain_val[i] * 0x0a00;
+ else { /* ADC gain */
+ gain_val[i] = 0x1e00 - ((p->max - gain_val[i]) * interval_offset);
+ gain_val[i] &= 0xffff;
+ }
+
+ if (regvalue[i] != gain_val[i])
+ changed = 1;
+ }
+
+ if (!changed)
+ return 0;
+
+ for (i = 0; i < p->count; i++) {
+ err = regmap_write(rt712->mbq_regmap, p->reg_base + i, gain_val[i]);
+ if (err < 0)
+ dev_err(&rt712->slave->dev, "0x%08x can't be set\n", p->reg_base + i);
+ }
+
+ return changed;
+}
+
+static int rt712_sdca_set_fu1e_capture_ctl(struct rt712_sdca_priv *rt712)
+{
+ int err, i;
+ unsigned int ch_mute;
+
+ for (i = 0; i < ARRAY_SIZE(rt712->fu1e_mixer_mute); i++) {
+ ch_mute = (rt712->fu1e_dapm_mute || rt712->fu1e_mixer_mute[i]) ? 0x01 : 0x00;
+ err = regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E,
+ RT712_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int rt712_sdca_dmic_fu1e_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+ struct rt712_dmic_kctrl_priv *p =
+ (struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+ unsigned int i;
+
+ for (i = 0; i < p->count; i++)
+ ucontrol->value.integer.value[i] = !rt712->fu1e_mixer_mute[i];
+
+ return 0;
+}
+
+static int rt712_sdca_dmic_fu1e_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+ struct rt712_dmic_kctrl_priv *p =
+ (struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+ int err, changed = 0, i;
+
+ for (i = 0; i < p->count; i++) {
+ if (rt712->fu1e_mixer_mute[i] != !ucontrol->value.integer.value[i])
+ changed = 1;
+ rt712->fu1e_mixer_mute[i] = !ucontrol->value.integer.value[i];
+ }
+
+ err = rt712_sdca_set_fu1e_capture_ctl(rt712);
+ if (err < 0)
+ return err;
+
+ return changed;
+}
+
+static int rt712_sdca_fu_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct rt712_dmic_kctrl_priv *p =
+ (struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+
+ if (p->max == 1)
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = p->count;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = p->max;
+ return 0;
+}
+
+#define RT712_SDCA_PR_VALUE(xreg_base, xcount, xmax, xinvert) \
+ ((unsigned long)&(struct rt712_dmic_kctrl_priv) \
+ {.reg_base = xreg_base, .count = xcount, .max = xmax, \
+ .invert = xinvert})
+
+#define RT712_SDCA_FU_CTRL(xname, reg_base, xmax, xinvert, xcount) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .info = rt712_sdca_fu_info, \
+ .get = rt712_sdca_dmic_fu1e_capture_get, \
+ .put = rt712_sdca_dmic_fu1e_capture_put, \
+ .private_value = RT712_SDCA_PR_VALUE(reg_base, xcount, xmax, xinvert)}
+
+#define RT712_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\
+ xhandler_put, xcount, xmax, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .tlv.p = (tlv_array), \
+ .info = rt712_sdca_fu_info, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = RT712_SDCA_PR_VALUE(reg_base, xcount, xmax, 0) }
+
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(dmic_vol_tlv, 0, 1000, 0);
+
+static const struct snd_kcontrol_new rt712_sdca_dmic_snd_controls[] = {
+ RT712_SDCA_FU_CTRL("FU1E Capture Switch",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01),
+ 1, 1, 4),
+ RT712_SDCA_EXT_TLV("FU1E Capture Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01),
+ rt712_sdca_dmic_set_gain_get, rt712_sdca_dmic_set_gain_put, 4, 0x3f, in_vol_tlv),
+ RT712_SDCA_EXT_TLV("FU15 Boost Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01),
+ rt712_sdca_dmic_set_gain_get, rt712_sdca_dmic_set_gain_put, 4, 3, dmic_vol_tlv),
+};
+
+static int rt712_sdca_dmic_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_kcontrol_component(kcontrol);
+ struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+ unsigned int val = 0, mask_sft;
+
+ if (strstr(ucontrol->id.name, "ADC 0A Mux"))
+ mask_sft = 0;
+ else if (strstr(ucontrol->id.name, "ADC 0B Mux"))
+ mask_sft = 4;
+ else
+ return -EINVAL;
+
+ rt712_sdca_index_read(rt712, RT712_VENDOR_HDA_CTL,
+ RT712_HDA_LEGACY_MUX_CTL0, &val);
+
+ ucontrol->value.enumerated.item[0] = (((val >> mask_sft) & 0xf) == 0x4) ? 0 : 1;
+
+ return 0;
+}
+
+static int rt712_sdca_dmic_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
+ unsigned int val, val2 = 0, change, mask_sft;
+
+ if (item[0] >= e->items)
+ return -EINVAL;
+
+ if (strstr(ucontrol->id.name, "ADC 0A Mux"))
+ mask_sft = 0;
+ else if (strstr(ucontrol->id.name, "ADC 0B Mux"))
+ mask_sft = 4;
+ else
+ return -EINVAL;
+
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+
+ rt712_sdca_index_read(rt712, RT712_VENDOR_HDA_CTL,
+ RT712_HDA_LEGACY_MUX_CTL0, &val2);
+ val2 = ((0xf << mask_sft) & val2) >> mask_sft;
+
+ if (val == 0)
+ val = 0x4;
+ else if (val >= 1)
+ val = 0xe;
+
+ if (val == val2)
+ change = 0;
+ else
+ change = 1;
+
+ if (change)
+ rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL,
+ RT712_HDA_LEGACY_MUX_CTL0, 0xf << mask_sft,
+ val << mask_sft);
+
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL);
+
+ return change;
+}
+
+static const char * const adc_dmic_mux_text[] = {
+ "DMIC1",
+ "DMIC2",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt712_adc0a_enum, SND_SOC_NOPM, 0, adc_dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt712_adc0b_enum, SND_SOC_NOPM, 0, adc_dmic_mux_text);
+
+static const struct snd_kcontrol_new rt712_sdca_dmic_adc0a_mux =
+ SOC_DAPM_ENUM_EXT("ADC 0A Mux", rt712_adc0a_enum,
+ rt712_sdca_dmic_mux_get, rt712_sdca_dmic_mux_put);
+
+static const struct snd_kcontrol_new rt712_sdca_dmic_adc0b_mux =
+ SOC_DAPM_ENUM_EXT("ADC 0B Mux", rt712_adc0b_enum,
+ rt712_sdca_dmic_mux_get, rt712_sdca_dmic_mux_put);
+
+static int rt712_sdca_dmic_fu1e_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 rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt712->fu1e_dapm_mute = false;
+ rt712_sdca_set_fu1e_capture_ctl(rt712);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt712->fu1e_dapm_mute = true;
+ rt712_sdca_set_fu1e_capture_ctl(rt712);
+ break;
+ }
+ return 0;
+}
+
+static int rt712_sdca_dmic_pde11_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 rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PDE11,
+ RT712_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PDE11,
+ RT712_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt712_sdca_dmic_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("DMIC1"),
+ SND_SOC_DAPM_INPUT("DMIC2"),
+
+ SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0,
+ rt712_sdca_dmic_pde11_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_ADC_E("FU 1E", NULL, SND_SOC_NOPM, 0, 0,
+ rt712_sdca_dmic_fu1e_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_MUX("ADC 0A Mux", SND_SOC_NOPM, 0, 0,
+ &rt712_sdca_dmic_adc0a_mux),
+ SND_SOC_DAPM_MUX("ADC 0B Mux", SND_SOC_NOPM, 0, 0,
+ &rt712_sdca_dmic_adc0b_mux),
+
+ SND_SOC_DAPM_AIF_OUT("DP8TX", "DP8 Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt712_sdca_dmic_audio_map[] = {
+ {"DP8TX", NULL, "FU 1E"},
+
+ {"FU 1E", NULL, "PDE 11"},
+ {"FU 1E", NULL, "ADC 0A Mux"},
+ {"FU 1E", NULL, "ADC 0B Mux"},
+ {"ADC 0A Mux", "DMIC1", "DMIC1"},
+ {"ADC 0A Mux", "DMIC2", "DMIC2"},
+ {"ADC 0B Mux", "DMIC1", "DMIC1"},
+ {"ADC 0B Mux", "DMIC2", "DMIC2"},
+};
+
+static int rt712_sdca_dmic_probe(struct snd_soc_component *component)
+{
+ struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ rt712->dmic_component = component;
+
+ if (!rt712->first_hw_init)
+ return 0;
+
+ ret = pm_runtime_resume(component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ return 0;
+}
+
static const struct snd_soc_component_driver soc_sdca_dev_rt712 = {
.probe = rt712_sdca_probe,
.controls = rt712_sdca_controls,
@@ -995,6 +1382,20 @@ static const struct snd_soc_component_driver soc_sdca_dev_rt712 = {
.endianness = 1,
};
+static const struct snd_soc_component_driver soc_sdca_dev_rt712_dmic = {
+ .probe = rt712_sdca_dmic_probe,
+ .controls = rt712_sdca_dmic_snd_controls,
+ .num_controls = ARRAY_SIZE(rt712_sdca_dmic_snd_controls),
+ .dapm_widgets = rt712_sdca_dmic_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt712_sdca_dmic_dapm_widgets),
+ .dapm_routes = rt712_sdca_dmic_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rt712_sdca_dmic_audio_map),
+ .endianness = 1,
+#ifdef CONFIG_DEBUG_FS
+ .debugfs_prefix = "dmic",
+#endif
+};
+
static int rt712_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
int direction)
{
@@ -1022,7 +1423,7 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
int retval, port, num_channels;
unsigned int sampling_rate;
- dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+ dev_dbg(dai->dev, "%s %s id %d", __func__, dai->name, dai->id);
sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
if (!sdw_stream)
@@ -1031,6 +1432,10 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
if (!rt712->slave)
return -EINVAL;
+ /* VA doesn't support AIF3 */
+ if (dai->id == RT712_AIF3 && rt712->version_id == RT712_VA)
+ return -EINVAL;
+
/* SoundWire specific configuration */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
direction = SDW_DATA_DIR_RX;
@@ -1044,6 +1449,8 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
direction = SDW_DATA_DIR_TX;
if (dai->id == RT712_AIF1)
port = 4;
+ else if (dai->id == RT712_AIF3)
+ port = 8;
else
return -EINVAL;
}
@@ -1105,6 +1512,14 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
sampling_rate);
break;
+ case RT712_AIF3:
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+ break;
default:
dev_err(component->dev, "%s: Wrong DAI id\n", __func__);
return -EINVAL;
@@ -1174,6 +1589,21 @@ static struct snd_soc_dai_driver rt712_sdca_dai[] = {
}
};
+static struct snd_soc_dai_driver rt712_sdca_dmic_dai[] = {
+ {
+ .name = "rt712-sdca-aif3",
+ .id = RT712_AIF3,
+ .capture = {
+ .stream_name = "DP8 Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = RT712_STEREO_RATES,
+ .formats = RT712_FORMATS,
+ },
+ .ops = &rt712_sdca_ops,
+ }
+};
+
int rt712_sdca_init(struct device *dev, struct regmap *regmap,
struct regmap *mbq_regmap, struct sdw_slave *slave)
{
@@ -1206,6 +1636,9 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
rt712->first_hw_init = false;
rt712->fu0f_dapm_mute = true;
rt712->fu0f_mixer_l_mute = rt712->fu0f_mixer_r_mute = true;
+ rt712->fu1e_dapm_mute = true;
+ rt712->fu1e_mixer_mute[0] = rt712->fu1e_mixer_mute[1] =
+ rt712->fu1e_mixer_mute[2] = rt712->fu1e_mixer_mute[3] = true;
/* JD source uses JD1 in default */
rt712->jd_src = RT712_JD1;
@@ -1239,35 +1672,11 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
return 0;
}
-int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+static void rt712_sdca_va_io_init(struct rt712_sdca_priv *rt712)
{
- struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev);
int ret = 0;
- unsigned int val, hibernation_flag;
-
- rt712->disable_irq = false;
-
- if (rt712->hw_init)
- return 0;
-
- regcache_cache_only(rt712->regmap, false);
- regcache_cache_only(rt712->mbq_regmap, false);
- if (rt712->first_hw_init) {
- regcache_cache_bypass(rt712->regmap, true);
- regcache_cache_bypass(rt712->mbq_regmap, true);
- } else {
- /*
- * PM runtime status is marked as 'active' only when a Slave reports as Attached
- */
-
- /* update count of parent 'active' children */
- pm_runtime_set_active(&slave->dev);
- }
-
- pm_runtime_get_noresume(&slave->dev);
-
- rt712_sdca_index_read(rt712, RT712_VENDOR_REG, RT712_JD_PRODUCT_NUM, &val);
- rt712->hw_id = (val & 0xf000) >> 12;
+ unsigned int hibernation_flag;
+ struct device *dev = &rt712->slave->dev;
rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_ANALOG_BIAS_CTL3, 0xaa81);
rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_LDO2_3_CTL1, 0xa1e0);
@@ -1307,6 +1716,131 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
regmap_write(rt712->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x04);
}
+}
+
+static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712)
+{
+ int ret = 0;
+ unsigned int jack_func_status, mic_func_status, amp_func_status;
+ struct device *dev = &rt712->slave->dev;
+
+ regmap_read(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &jack_func_status);
+ regmap_read(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &mic_func_status);
+ regmap_read(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &amp_func_status);
+ dev_dbg(dev, "%s jack/mic/amp func_status=0x%x, 0x%x, 0x%x\n",
+ __func__, jack_func_status, mic_func_status, amp_func_status);
+
+ /* DMIC */
+ if ((mic_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) {
+ rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_IT_FLOAT_CTL, 0x1526);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_CH12_FLOAT_CTL, 0x0304);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_ADC0A_CS_ADC0B_FU_FLOAT_CTL, 0x1f1e);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_ADC0B_FU_CH12_FLOAT_CTL, 0x0304);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_HDA_LEGACY_CONFIG_CTL0, 0x8010);
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_IT11, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x01);
+ rt712_sdca_index_write(rt712, RT712_ULTRA_SOUND_DET, RT712_ULTRA_SOUND_DETECTOR6, 0x3200);
+ regmap_write(rt712->regmap, RT712_RC_CAL, 0x23);
+
+ /* clear flag */
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0),
+ FUNCTION_NEEDS_INITIALIZATION);
+ }
+
+ /* Jack */
+ if ((jack_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) {
+ rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_SEL_VEE2_HP_CTL1, 0x042a);
+ rt712_sdca_index_write(rt712, RT712_CHARGE_PUMP, RT712_HP_DET_CTL3, 0x1fff);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_IO_CTL, 0xec67);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_ANALOG_BIAS_CTL3, 0xaa81);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_LDO2_3_CTL1, 0xa1e0);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_HP_DETECT_RLDET_CTL1, 0x0000);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_HP_DETECT_RLDET_CTL2, 0x0000);
+ regmap_write(rt712->regmap, RT712_RC_CAL, 0x23);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_JD_CTL1, 0x2802);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CLASSD_AMP_CTL6, 0xf215);
+
+ /* calibration */
+ ret = rt712_sdca_calibration(rt712);
+ if (ret < 0)
+ dev_err(dev, "%s, calibration failed!\n", __func__);
+
+ rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL, RT712_MIXER_CTL1, 0x3000, 0x0000);
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_IT09, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x01);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_MISC_CTL_FOR_UAJ, 0x0003);
+
+ /* clear flag */
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0),
+ FUNCTION_NEEDS_INITIALIZATION);
+ }
+
+ /* SPK */
+ if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) {
+ if (rt712->hw_id != RT712_DEV_ID_713) {
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_IO_CTL, 0xec63);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CLASSD_AMP_CTL1, 0xfff5);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_EAPD_CTL, 0x0002);
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x04);
+ }
+ /* clear flag */
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0),
+ FUNCTION_NEEDS_INITIALIZATION);
+ }
+}
+
+int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev);
+ int ret = 0;
+ unsigned int val;
+ struct sdw_slave_prop *prop = &slave->prop;
+
+ rt712->disable_irq = false;
+
+ if (rt712->hw_init)
+ return 0;
+
+ regcache_cache_only(rt712->regmap, false);
+ regcache_cache_only(rt712->mbq_regmap, false);
+ if (rt712->first_hw_init) {
+ regcache_cache_bypass(rt712->regmap, true);
+ regcache_cache_bypass(rt712->mbq_regmap, true);
+ } else {
+ /*
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
+ */
+
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+
+ rt712_sdca_index_read(rt712, RT712_VENDOR_REG, RT712_JD_PRODUCT_NUM, &val);
+ rt712->hw_id = (val & 0xf000) >> 12;
+ rt712->version_id = (val & 0x0f00) >> 8;
+ dev_dbg(&slave->dev, "%s hw_id=0x%x, version_id=0x%x\n", __func__, rt712->hw_id, rt712->version_id);
+
+ if (rt712->version_id == RT712_VA)
+ rt712_sdca_va_io_init(rt712);
+ else {
+ /* multilanes and DMIC are supported by rt712vb */
+ ret = devm_snd_soc_register_component(dev,
+ &soc_sdca_dev_rt712_dmic, rt712_sdca_dmic_dai, ARRAY_SIZE(rt712_sdca_dmic_dai));
+ if (ret < 0)
+ return ret;
+
+ prop->lane_control_support = true;
+ rt712_sdca_vb_io_init(rt712);
+ }
/*
* if set_jack callback occurred early than io_init,
@@ -1315,8 +1849,7 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
if (rt712->hs_jack)
rt712_sdca_jack_init(rt712);
- if (!hibernation_flag)
- rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_SW_CONFIG1, 0x0001);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_SW_CONFIG1, 0x0001);
if (rt712->first_hw_init) {
regcache_cache_bypass(rt712->regmap, false);
diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h
index ff79e03118ce..2169f2f726b9 100644
--- a/sound/soc/codecs/rt712-sdca.h
+++ b/sound/soc/codecs/rt712-sdca.h
@@ -19,6 +19,7 @@ struct rt712_sdca_priv {
struct regmap *regmap;
struct regmap *mbq_regmap;
struct snd_soc_component *component;
+ struct snd_soc_component *dmic_component;
struct sdw_slave *slave;
struct sdw_bus_params params;
bool hw_init;
@@ -34,13 +35,31 @@ struct rt712_sdca_priv {
unsigned int scp_sdca_stat1;
unsigned int scp_sdca_stat2;
unsigned int hw_id;
+ unsigned int version_id;
bool fu0f_dapm_mute;
bool fu0f_mixer_l_mute;
bool fu0f_mixer_r_mute;
+ bool fu1e_dapm_mute;
+ bool fu1e_mixer_mute[4];
};
+struct rt712_dmic_kctrl_priv {
+ unsigned int reg_base;
+ unsigned int count;
+ unsigned int max;
+ unsigned int invert;
+};
+
+/* SDCA (Channel) */
+#define CH_01 0x01
+#define CH_02 0x02
+#define CH_03 0x03
+#define CH_04 0x04
+
/* NID */
#define RT712_VENDOR_REG 0x20
+#define RT712_EQ_CTRL 0x53
+#define RT712_CHARGE_PUMP 0x57
#define RT712_VENDOR_CALI 0x58
#define RT712_ULTRA_SOUND_DET 0x59
#define RT712_VENDOR_IMS_DRE 0x5b
@@ -50,9 +69,13 @@ struct rt712_sdca_priv {
/* Index (NID:20h) */
#define RT712_JD_PRODUCT_NUM 0x00
#define RT712_ANALOG_BIAS_CTL3 0x04
+#define RT712_JD_CTL1 0x09
+#define RT712_IO_CTL 0x0c
#define RT712_LDO2_3_CTL1 0x0e
#define RT712_PARA_VERB_CTL 0x1a
#define RT712_CC_DET1 0x24
+#define RT712_CLASSD_AMP_CTL1 0x37
+#define RT712_CLASSD_AMP_CTL6 0x3c
#define RT712_COMBO_JACK_AUTO_CTL1 0x45
#define RT712_COMBO_JACK_AUTO_CTL2 0x46
#define RT712_COMBO_JACK_AUTO_CTL3 0x47
@@ -61,6 +84,9 @@ struct rt712_sdca_priv {
#define RT712_SW_CONFIG1 0x8a
#define RT712_SW_CONFIG2 0x8b
+/* Index (NID:57h) */
+#define RT712_HP_DET_CTL3 0x0c
+
/* Index (NID:58h) */
#define RT712_DAC_DC_CALI_CTL1 0x00
#define RT712_DAC_DC_CALI_CTL2 0x01
@@ -71,6 +97,7 @@ struct rt712_sdca_priv {
/* Index (NID:5bh) */
#define RT712_IMS_DIGITAL_CTL1 0x00
#define RT712_IMS_DIGITAL_CTL5 0x05
+#define RT712_SEL_VEE2_HP_CTL1 0x23
#define RT712_HP_DETECT_RLDET_CTL1 0x29
#define RT712_HP_DETECT_RLDET_CTL2 0x2a
@@ -109,6 +136,11 @@ struct rt712_sdca_priv {
#define RT712_UMP_HID_CTL6 0x66
#define RT712_UMP_HID_CTL7 0x67
#define RT712_UMP_HID_CTL8 0x68
+#define RT712_MISC_CTL_FOR_UAJ 0x72
+#define RT712_ADC0A_CS_ADC0B_FU_FLOAT_CTL 0xa2
+#define RT712_DMIC2_FU_IT_FLOAT_CTL 0xa6
+#define RT712_ADC0B_FU_CH12_FLOAT_CTL 0xb0
+#define RT712_DMIC2_FU_CH12_FLOAT_CTL 0xb1
/* Parameter & Verb control 01 (0x1a)(NID:20h) */
#define RT712_HIDDEN_REG_SW_RESET (0x1 << 14)
@@ -139,6 +171,7 @@ struct rt712_sdca_priv {
#define FUNC_NUM_AMP 0x04
/* RT712 SDCA entity */
+#define RT712_SDCA_ENT0 0x00
#define RT712_SDCA_ENT_HID01 0x01
#define RT712_SDCA_ENT_GE49 0x49
#define RT712_SDCA_ENT_USER_FU05 0x05
@@ -157,6 +190,7 @@ struct rt712_sdca_priv {
#define RT712_SDCA_ENT_CS1C 0x1c
#define RT712_SDCA_ENT_CS31 0x31
#define RT712_SDCA_ENT_OT23 0x42
+#define RT712_SDCA_ENT_IT11 0x26
#define RT712_SDCA_ENT_IT26 0x26
#define RT712_SDCA_ENT_IT09 0x09
#define RT712_SDCA_ENT_PLATFORM_FU15 0x15
@@ -175,10 +209,12 @@ struct rt712_sdca_priv {
#define RT712_SDCA_CTL_REQ_POWER_STATE 0x01
#define RT712_SDCA_CTL_VENDOR_DEF 0x30
#define RT712_SDCA_CTL_FU_CH_GAIN 0x0b
+#define RT712_SDCA_CTL_FUNC_STATUS 0x10
-/* RT712 SDCA channel */
-#define CH_L 0x01
-#define CH_R 0x02
+/* Function_Status */
+#define FUNCTION_NEEDS_INITIALIZATION BIT(5)
+#define FUNCTION_HAS_BEEN_RESET BIT(6)
+#define FUNCTION_BUSY BIT(7)
/* sample frequency index */
#define RT712_SDCA_RATE_16000HZ 0x04
@@ -191,6 +227,7 @@ struct rt712_sdca_priv {
enum {
RT712_AIF1,
RT712_AIF2,
+ RT712_AIF3,
};
enum rt712_sdca_jd_src {
@@ -207,6 +244,11 @@ enum rt712_sdca_hw_id {
#define RT712_PART_ID_713 0x713
+enum rt712_sdca_version {
+ RT712_VA,
+ RT712_VB,
+};
+
int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave);
int rt712_sdca_init(struct device *dev, struct regmap *regmap,
struct regmap *mbq_regmap, struct sdw_slave *slave);
diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c
index bf67de12d20b..240af0563283 100644
--- a/sound/soc/codecs/simple-mux.c
+++ b/sound/soc/codecs/simple-mux.c
@@ -9,12 +9,21 @@
#include <linux/regulator/consumer.h>
#include <sound/soc.h>
+#define MUX_TEXT_SIZE 2
+#define MUX_WIDGET_SIZE 4
+#define MUX_ROUTE_SIZE 3
struct simple_mux {
struct gpio_desc *gpiod_mux;
unsigned int mux;
+ const char *mux_texts[MUX_TEXT_SIZE];
+ struct soc_enum mux_enum;
+ struct snd_kcontrol_new mux_mux;
+ struct snd_soc_dapm_widget mux_widgets[MUX_WIDGET_SIZE];
+ struct snd_soc_dapm_route mux_routes[MUX_ROUTE_SIZE];
+ struct snd_soc_component_driver mux_driver;
};
-static const char * const simple_mux_texts[] = {
+static const char * const simple_mux_texts[MUX_TEXT_SIZE] = {
"Input 1", "Input 2"
};
@@ -66,30 +75,23 @@ static unsigned int simple_mux_read(struct snd_soc_component *component,
static const struct snd_kcontrol_new simple_mux_mux =
SOC_DAPM_ENUM_EXT("Muxer", simple_mux_enum, simple_mux_control_get, simple_mux_control_put);
-static const struct snd_soc_dapm_widget simple_mux_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget simple_mux_dapm_widgets[MUX_WIDGET_SIZE] = {
SND_SOC_DAPM_INPUT("IN1"),
SND_SOC_DAPM_INPUT("IN2"),
- SND_SOC_DAPM_MUX("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux),
+ SND_SOC_DAPM_MUX("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux), // see simple_mux_probe()
SND_SOC_DAPM_OUTPUT("OUT"),
};
-static const struct snd_soc_dapm_route simple_mux_dapm_routes[] = {
+static const struct snd_soc_dapm_route simple_mux_dapm_routes[MUX_ROUTE_SIZE] = {
{ "OUT", NULL, "MUX" },
- { "MUX", "Input 1", "IN1" },
- { "MUX", "Input 2", "IN2" },
-};
-
-static const struct snd_soc_component_driver simple_mux_component_driver = {
- .dapm_widgets = simple_mux_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(simple_mux_dapm_widgets),
- .dapm_routes = simple_mux_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(simple_mux_dapm_routes),
- .read = simple_mux_read,
+ { "MUX", "Input 1", "IN1" }, // see simple_mux_probe()
+ { "MUX", "Input 2", "IN2" }, // see simple_mux_probe()
};
static int simple_mux_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct simple_mux *priv;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -103,7 +105,30 @@ static int simple_mux_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(priv->gpiod_mux),
"Failed to get 'mux' gpio");
- return devm_snd_soc_register_component(dev, &simple_mux_component_driver, NULL, 0);
+ /* Copy default settings */
+ memcpy(&priv->mux_texts, &simple_mux_texts, sizeof(priv->mux_texts));
+ memcpy(&priv->mux_enum, &simple_mux_enum, sizeof(priv->mux_enum));
+ memcpy(&priv->mux_mux, &simple_mux_mux, sizeof(priv->mux_mux));
+ memcpy(&priv->mux_widgets, &simple_mux_dapm_widgets, sizeof(priv->mux_widgets));
+ memcpy(&priv->mux_routes, &simple_mux_dapm_routes, sizeof(priv->mux_routes));
+
+ priv->mux_driver.dapm_widgets = priv->mux_widgets;
+ priv->mux_driver.num_dapm_widgets = MUX_WIDGET_SIZE;
+ priv->mux_driver.dapm_routes = priv->mux_routes;
+ priv->mux_driver.num_dapm_routes = MUX_ROUTE_SIZE;
+ priv->mux_driver.read = simple_mux_read;
+
+ /* Overwrite text ("Input 1", "Input 2") if property exists */
+ of_property_read_string_array(np, "state-labels", priv->mux_texts, MUX_TEXT_SIZE);
+
+ /* switch to use priv data instead of default */
+ priv->mux_enum.texts = priv->mux_texts;
+ priv->mux_mux.private_value = (unsigned long)&priv->mux_enum;
+ priv->mux_widgets[2].kcontrol_news = &priv->mux_mux;
+ priv->mux_routes[1].control = priv->mux_texts[0]; // "Input 1"
+ priv->mux_routes[2].control = priv->mux_texts[1]; // "Input 2"
+
+ return devm_snd_soc_register_component(dev, &priv->mux_driver, NULL, 0);
}
#ifdef CONFIG_OF
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index a7ed59ec49a6..9e68afc09897 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -13,7 +13,6 @@
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
-#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 1dc719d726ab..5eaddf07aadc 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -15,7 +15,6 @@
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/pcm.h>
diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index 67bc1c8b0131..5601fba17c96 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -20,7 +20,6 @@
#include <linux/firmware.h>
#include <linux/regmap.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/pcm.h>
diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c
index a18ccf5fb7ad..6902bfef185b 100644
--- a/sound/soc/codecs/tas2780.c
+++ b/sound/soc/codecs/tas2780.c
@@ -11,7 +11,6 @@
#include <linux/gpio/consumer.h>
#include <linux/regmap.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <sound/soc.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c
index 3aa81514dad7..1fbf4560f5cc 100644
--- a/sound/soc/codecs/tas2781-comlib.c
+++ b/sound/soc/codecs/tas2781-comlib.c
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
//
-// tas2781-lib.c -- TAS2781 Common functions for HDA and ASoC Audio drivers
+// TAS2781 Common functions for HDA and ASoC Audio drivers
//
-// Copyright 2023 Texas Instruments, Inc.
+// Copyright 2023 - 2024 Texas Instruments, Inc.
//
// Author: Shenghao Ding <shenghao-ding@ti.com>
@@ -243,7 +243,7 @@ struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c)
}
EXPORT_SYMBOL_GPL(tasdevice_kzalloc);
-void tas2781_reset(struct tasdevice_priv *tas_dev)
+void tasdevice_reset(struct tasdevice_priv *tas_dev)
{
int ret, i;
@@ -254,8 +254,8 @@ void tas2781_reset(struct tasdevice_priv *tas_dev)
} else {
for (i = 0; i < tas_dev->ndev; i++) {
ret = tasdevice_dev_write(tas_dev, i,
- TAS2781_REG_SWRESET,
- TAS2781_REG_SWRESET_RESET);
+ TASDEVICE_REG_SWRESET,
+ TASDEVICE_REG_SWRESET_RESET);
if (ret < 0)
dev_err(tas_dev->dev,
"dev %d swreset fail, %d\n",
@@ -264,7 +264,7 @@ void tas2781_reset(struct tasdevice_priv *tas_dev)
}
usleep_range(1000, 1050);
}
-EXPORT_SYMBOL_GPL(tas2781_reset);
+EXPORT_SYMBOL_GPL(tasdevice_reset);
int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
struct module *module,
@@ -277,8 +277,13 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
*/
mutex_lock(&tas_priv->codec_lock);
- scnprintf(tas_priv->rca_binaryname, 64, "%sRCA%d.bin",
- tas_priv->dev_name, tas_priv->ndev);
+ if (tas_priv->name_prefix)
+ scnprintf(tas_priv->rca_binaryname, 64, "%s-%sRCA%d.bin",
+ tas_priv->name_prefix, tas_priv->dev_name,
+ tas_priv->ndev);
+ else
+ scnprintf(tas_priv->rca_binaryname, 64, "%sRCA%d.bin",
+ tas_priv->dev_name, tas_priv->ndev);
crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL);
tas_priv->codec = codec;
ret = request_firmware_nowait(module, FW_ACTION_UEVENT,
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
index 265a8ca25cbb..63626b982d04 100644
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -21,7 +21,7 @@
#include <sound/soc.h>
#include <sound/tlv.h>
#include <sound/tas2781.h>
-
+#include <asm/unaligned.h>
#define ERROR_PRAM_CRCCHK 0x0000000
#define ERROR_YRAM_CRCCHK 0x0000001
@@ -187,8 +187,7 @@ static struct tasdevice_config_info *tasdevice_add_config(
/* convert data[offset], data[offset + 1], data[offset + 2] and
* data[offset + 3] into host
*/
- cfg_info->nblocks =
- be32_to_cpup((__be32 *)&config_data[config_offset]);
+ cfg_info->nblocks = get_unaligned_be32(&config_data[config_offset]);
config_offset += 4;
/* Several kinds of dsp/algorithm firmwares can run on tas2781,
@@ -232,14 +231,14 @@ static struct tasdevice_config_info *tasdevice_add_config(
}
bk_da[i]->yram_checksum =
- be16_to_cpup((__be16 *)&config_data[config_offset]);
+ get_unaligned_be16(&config_data[config_offset]);
config_offset += 2;
bk_da[i]->block_size =
- be32_to_cpup((__be32 *)&config_data[config_offset]);
+ get_unaligned_be32(&config_data[config_offset]);
config_offset += 4;
bk_da[i]->n_subblks =
- be32_to_cpup((__be32 *)&config_data[config_offset]);
+ get_unaligned_be32(&config_data[config_offset]);
config_offset += 4;
@@ -289,7 +288,7 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw)
}
buf = (unsigned char *)fmw->data;
- fw_hdr->img_sz = be32_to_cpup((__be32 *)&buf[offset]);
+ fw_hdr->img_sz = get_unaligned_be32(&buf[offset]);
offset += 4;
if (fw_hdr->img_sz != fmw->size) {
dev_err(tas_priv->dev,
@@ -300,9 +299,9 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw)
goto out;
}
- fw_hdr->checksum = be32_to_cpup((__be32 *)&buf[offset]);
+ fw_hdr->checksum = get_unaligned_be32(&buf[offset]);
offset += 4;
- fw_hdr->binary_version_num = be32_to_cpup((__be32 *)&buf[offset]);
+ fw_hdr->binary_version_num = get_unaligned_be32(&buf[offset]);
if (fw_hdr->binary_version_num < 0x103) {
dev_err(tas_priv->dev, "File version 0x%04x is too low",
fw_hdr->binary_version_num);
@@ -311,7 +310,7 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw)
goto out;
}
offset += 4;
- fw_hdr->drv_fw_version = be32_to_cpup((__be32 *)&buf[offset]);
+ fw_hdr->drv_fw_version = get_unaligned_be32(&buf[offset]);
offset += 8;
fw_hdr->plat_type = buf[offset];
offset += 1;
@@ -339,11 +338,11 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw)
for (i = 0; i < TASDEVICE_DEVICE_SUM; i++, offset++)
fw_hdr->devs[i] = buf[offset];
- fw_hdr->nconfig = be32_to_cpup((__be32 *)&buf[offset]);
+ fw_hdr->nconfig = get_unaligned_be32(&buf[offset]);
offset += 4;
for (i = 0; i < TASDEVICE_CONFIG_SUM; i++) {
- fw_hdr->config_size[i] = be32_to_cpup((__be32 *)&buf[offset]);
+ fw_hdr->config_size[i] = get_unaligned_be32(&buf[offset]);
offset += 4;
total_config_sz += fw_hdr->config_size[i];
}
@@ -423,7 +422,7 @@ static int fw_parse_block_data_kernel(struct tasdevice_fw *tas_fmw,
/* convert data[offset], data[offset + 1], data[offset + 2] and
* data[offset + 3] into host
*/
- block->type = be32_to_cpup((__be32 *)&data[offset]);
+ block->type = get_unaligned_be32(&data[offset]);
offset += 4;
block->is_pchksum_present = data[offset];
@@ -438,10 +437,10 @@ static int fw_parse_block_data_kernel(struct tasdevice_fw *tas_fmw,
block->ychksum = data[offset];
offset++;
- block->blk_size = be32_to_cpup((__be32 *)&data[offset]);
+ block->blk_size = get_unaligned_be32(&data[offset]);
offset += 4;
- block->nr_subblocks = be32_to_cpup((__be32 *)&data[offset]);
+ block->nr_subblocks = get_unaligned_be32(&data[offset]);
offset += 4;
/* fixed m68k compiling issue:
@@ -482,7 +481,7 @@ static int fw_parse_data_kernel(struct tasdevice_fw *tas_fmw,
offset = -EINVAL;
goto out;
}
- img_data->nr_blk = be32_to_cpup((__be32 *)&data[offset]);
+ img_data->nr_blk = get_unaligned_be32(&data[offset]);
offset += 4;
img_data->dev_blks = kcalloc(img_data->nr_blk,
@@ -578,14 +577,14 @@ static int fw_parse_variable_header_kernel(
offset = -EINVAL;
goto out;
}
- fw_hdr->device_family = be16_to_cpup((__be16 *)&buf[offset]);
+ fw_hdr->device_family = get_unaligned_be16(&buf[offset]);
if (fw_hdr->device_family != 0) {
dev_err(tas_priv->dev, "%s:not TAS device\n", __func__);
offset = -EINVAL;
goto out;
}
offset += 2;
- fw_hdr->device = be16_to_cpup((__be16 *)&buf[offset]);
+ fw_hdr->device = get_unaligned_be16(&buf[offset]);
if (fw_hdr->device >= TASDEVICE_DSP_TAS_MAX_DEVICE ||
fw_hdr->device == 6) {
dev_err(tas_priv->dev, "Unsupported dev %d\n", fw_hdr->device);
@@ -603,7 +602,7 @@ static int fw_parse_variable_header_kernel(
goto out;
}
- tas_fmw->nr_programs = be32_to_cpup((__be32 *)&buf[offset]);
+ tas_fmw->nr_programs = get_unaligned_be32(&buf[offset]);
offset += 4;
if (tas_fmw->nr_programs == 0 || tas_fmw->nr_programs >
@@ -622,14 +621,14 @@ static int fw_parse_variable_header_kernel(
for (i = 0; i < tas_fmw->nr_programs; i++) {
program = &(tas_fmw->programs[i]);
- program->prog_size = be32_to_cpup((__be32 *)&buf[offset]);
+ program->prog_size = get_unaligned_be32(&buf[offset]);
offset += 4;
}
/* Skip the unused prog_size */
offset += 4 * (TASDEVICE_MAXPROGRAM_NUM_KERNEL - tas_fmw->nr_programs);
- tas_fmw->nr_configurations = be32_to_cpup((__be32 *)&buf[offset]);
+ tas_fmw->nr_configurations = get_unaligned_be32(&buf[offset]);
offset += 4;
/* The max number of config in firmware greater than 4 pieces of
@@ -661,7 +660,7 @@ static int fw_parse_variable_header_kernel(
for (i = 0; i < tas_fmw->nr_programs; i++) {
config = &(tas_fmw->configs[i]);
- config->cfg_size = be32_to_cpup((__be32 *)&buf[offset]);
+ config->cfg_size = get_unaligned_be32(&buf[offset]);
offset += 4;
}
@@ -699,7 +698,7 @@ static int tasdevice_process_block(void *context, unsigned char *data,
switch (subblk_typ) {
case TASDEVICE_CMD_SING_W: {
int i;
- unsigned short len = be16_to_cpup((__be16 *)&data[2]);
+ unsigned short len = get_unaligned_be16(&data[2]);
subblk_offset += 2;
if (subblk_offset + 4 * len > sublocksize) {
@@ -725,7 +724,7 @@ static int tasdevice_process_block(void *context, unsigned char *data,
}
break;
case TASDEVICE_CMD_BURST: {
- unsigned short len = be16_to_cpup((__be16 *)&data[2]);
+ unsigned short len = get_unaligned_be16(&data[2]);
subblk_offset += 2;
if (subblk_offset + 4 + len > sublocksize) {
@@ -766,7 +765,7 @@ static int tasdevice_process_block(void *context, unsigned char *data,
is_err = true;
break;
}
- sleep_time = be16_to_cpup((__be16 *)&data[2]) * 1000;
+ sleep_time = get_unaligned_be16(&data[2]) * 1000;
usleep_range(sleep_time, sleep_time + 50);
subblk_offset += 2;
}
@@ -910,7 +909,7 @@ static int fw_parse_variable_hdr(struct tasdevice_priv
offset += len;
- fw_hdr->device_family = be32_to_cpup((__be32 *)&buf[offset]);
+ fw_hdr->device_family = get_unaligned_be32(&buf[offset]);
if (fw_hdr->device_family != 0) {
dev_err(tas_priv->dev, "%s: not TAS device\n", __func__);
offset = -EINVAL;
@@ -918,7 +917,7 @@ static int fw_parse_variable_hdr(struct tasdevice_priv
}
offset += 4;
- fw_hdr->device = be32_to_cpup((__be32 *)&buf[offset]);
+ fw_hdr->device = get_unaligned_be32(&buf[offset]);
if (fw_hdr->device >= TASDEVICE_DSP_TAS_MAX_DEVICE ||
fw_hdr->device == 6) {
dev_err(tas_priv->dev, "Unsupported dev %d\n", fw_hdr->device);
@@ -963,7 +962,7 @@ static int fw_parse_block_data(struct tasdevice_fw *tas_fmw,
offset = -EINVAL;
goto out;
}
- block->type = be32_to_cpup((__be32 *)&data[offset]);
+ block->type = get_unaligned_be32(&data[offset]);
offset += 4;
if (tas_fmw->fw_hdr.fixed_hdr.drv_ver >= PPC_DRIVER_CRCCHK) {
@@ -988,7 +987,7 @@ static int fw_parse_block_data(struct tasdevice_fw *tas_fmw,
block->is_ychksum_present = 0;
}
- block->nr_cmds = be32_to_cpup((__be32 *)&data[offset]);
+ block->nr_cmds = get_unaligned_be32(&data[offset]);
offset += 4;
n = block->nr_cmds * 4;
@@ -1039,7 +1038,7 @@ static int fw_parse_data(struct tasdevice_fw *tas_fmw,
goto out;
}
offset += n;
- img_data->nr_blk = be16_to_cpup((__be16 *)&data[offset]);
+ img_data->nr_blk = get_unaligned_be16(&data[offset]);
offset += 2;
img_data->dev_blks = kcalloc(img_data->nr_blk,
@@ -1076,7 +1075,7 @@ static int fw_parse_program_data(struct tasdevice_priv *tas_priv,
offset = -EINVAL;
goto out;
}
- tas_fmw->nr_programs = be16_to_cpup((__be16 *)&buf[offset]);
+ tas_fmw->nr_programs = get_unaligned_be16(&buf[offset]);
offset += 2;
if (tas_fmw->nr_programs == 0) {
@@ -1143,7 +1142,7 @@ static int fw_parse_configuration_data(
offset = -EINVAL;
goto out;
}
- tas_fmw->nr_configurations = be16_to_cpup((__be16 *)&data[offset]);
+ tas_fmw->nr_configurations = get_unaligned_be16(&data[offset]);
offset += 2;
if (tas_fmw->nr_configurations == 0) {
@@ -1775,7 +1774,7 @@ static int fw_parse_header(struct tasdevice_priv *tas_priv,
/* Convert data[offset], data[offset + 1], data[offset + 2] and
* data[offset + 3] into host
*/
- fw_fixed_hdr->fwsize = be32_to_cpup((__be32 *)&buf[offset]);
+ fw_fixed_hdr->fwsize = get_unaligned_be32(&buf[offset]);
offset += 4;
if (fw_fixed_hdr->fwsize != fmw->size) {
dev_err(tas_priv->dev, "File size not match, %lu %u",
@@ -1784,9 +1783,9 @@ static int fw_parse_header(struct tasdevice_priv *tas_priv,
goto out;
}
offset += 4;
- fw_fixed_hdr->ppcver = be32_to_cpup((__be32 *)&buf[offset]);
+ fw_fixed_hdr->ppcver = get_unaligned_be32(&buf[offset]);
offset += 8;
- fw_fixed_hdr->drv_ver = be32_to_cpup((__be32 *)&buf[offset]);
+ fw_fixed_hdr->drv_ver = get_unaligned_be32(&buf[offset]);
offset += 72;
out:
@@ -1828,7 +1827,7 @@ static int fw_parse_calibration_data(struct tasdevice_priv *tas_priv,
offset = -EINVAL;
goto out;
}
- tas_fmw->nr_calibrations = be16_to_cpup((__be16 *)&data[offset]);
+ tas_fmw->nr_calibrations = get_unaligned_be16(&data[offset]);
offset += 2;
if (tas_fmw->nr_calibrations != 1) {
@@ -2324,14 +2323,21 @@ void tasdevice_tuning_switch(void *context, int state)
struct tasdevice_fw *tas_fmw = tas_priv->fmw;
int profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
- if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) {
- dev_err(tas_priv->dev, "DSP bin file not loaded\n");
+ /*
+ * Only RCA-based Playback can still work with no dsp program running
+ * inside the chip.
+ */
+ switch (tas_priv->fw_state) {
+ case TASDEVICE_RCA_FW_OK:
+ case TASDEVICE_DSP_FW_ALL_OK:
+ break;
+ default:
return;
}
if (state == 0) {
- if (tas_priv->cur_prog < tas_fmw->nr_programs) {
- /*dsp mode or tuning mode*/
+ if (tas_fmw && tas_priv->cur_prog < tas_fmw->nr_programs) {
+ /* dsp mode or tuning mode */
profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
tasdevice_select_tuningprm_cfg(tas_priv,
tas_priv->cur_prog, tas_priv->cur_conf,
@@ -2340,9 +2346,10 @@ void tasdevice_tuning_switch(void *context, int state)
tasdevice_select_cfg_blk(tas_priv, profile_cfg_id,
TASDEVICE_BIN_BLK_PRE_POWER_UP);
- } else
+ } else {
tasdevice_select_cfg_blk(tas_priv, profile_cfg_id,
TASDEVICE_BIN_BLK_PRE_SHUTDOWN);
+ }
}
EXPORT_SYMBOL_NS_GPL(tasdevice_tuning_switch,
SND_SOC_TAS2781_FMWLIB);
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 9350972dfefe..e79d613745b4 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -21,6 +21,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/regmap.h>
@@ -30,6 +31,7 @@
#include <sound/tas2781.h>
#include <sound/tlv.h>
#include <sound/tas2781-tlv.h>
+#include <asm/unaligned.h>
static const struct i2c_device_id tasdevice_id[] = {
{ "tas2563", TAS2563 },
@@ -103,7 +105,7 @@ static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
return tasdevice_amp_putvol(tas_priv, ucontrol, mc);
}
-static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
+static int tasdev_force_fwload_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component =
@@ -118,7 +120,7 @@ static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
+static int tasdev_force_fwload_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component =
@@ -139,6 +141,106 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
return change;
}
+static int tas2563_digital_gain_get(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec);
+ unsigned int l = 0, r = mc->max;
+ unsigned int target, ar_mid, mid, ar_l, ar_r;
+ unsigned int reg = mc->reg;
+ unsigned char data[4];
+ int ret;
+
+ mutex_lock(&tas_dev->codec_lock);
+ /* Read the primary device */
+ ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
+ if (ret) {
+ dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
+ goto out;
+ }
+
+ target = get_unaligned_be32(&data[0]);
+
+ while (r > 1 + l) {
+ mid = (l + r) / 2;
+ ar_mid = get_unaligned_be32(tas2563_dvc_table[mid]);
+ if (target < ar_mid)
+ r = mid;
+ else
+ l = mid;
+ }
+
+ ar_l = get_unaligned_be32(tas2563_dvc_table[l]);
+ ar_r = get_unaligned_be32(tas2563_dvc_table[r]);
+
+ /* find out the member same as or closer to the current volume */
+ ucontrol->value.integer.value[0] =
+ abs(target - ar_l) <= abs(target - ar_r) ? l : r;
+out:
+ mutex_unlock(&tas_dev->codec_lock);
+ return 0;
+}
+
+static int tas2563_digital_gain_put(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec);
+ int vol = ucontrol->value.integer.value[0];
+ int status = 0, max = mc->max, rc = 1;
+ int i, ret;
+ unsigned int reg = mc->reg;
+ unsigned int volrd, volwr;
+ unsigned char data[4];
+
+ vol = clamp(vol, 0, max);
+ mutex_lock(&tas_dev->codec_lock);
+ /* Read the primary device */
+ ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
+ if (ret) {
+ dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
+ rc = -1;
+ goto out;
+ }
+
+ volrd = get_unaligned_be32(&data[0]);
+ volwr = get_unaligned_be32(tas2563_dvc_table[vol]);
+
+ if (volrd == volwr) {
+ rc = 0;
+ goto out;
+ }
+
+ for (i = 0; i < tas_dev->ndev; i++) {
+ ret = tasdevice_dev_bulk_write(tas_dev, i, reg,
+ (unsigned char *)tas2563_dvc_table[vol], 4);
+ if (ret) {
+ dev_err(tas_dev->dev,
+ "%s, set digital vol error in dev %d\n",
+ __func__, i);
+ status |= BIT(i);
+ }
+ }
+
+ if (status)
+ rc = -1;
+out:
+ mutex_unlock(&tas_dev->codec_lock);
+ return rc;
+}
+
+static const struct snd_kcontrol_new tasdevice_snd_controls[] = {
+ SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
+ tasdev_force_fwload_get, tasdev_force_fwload_put),
+};
+
static const struct snd_kcontrol_new tas2781_snd_controls[] = {
SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL,
1, 0, 20, 0, tas2781_amp_getvol,
@@ -146,8 +248,13 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = {
SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain", TAS2781_DVC_LVL,
0, 0, 200, 1, tas2781_digital_getvol,
tas2781_digital_putvol, dvc_tlv),
- SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
- tas2781_force_fwload_get, tas2781_force_fwload_put),
+};
+
+static const struct snd_kcontrol_new tas2563_snd_controls[] = {
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2563_DVC_LVL, 0,
+ 0, ARRAY_SIZE(tas2563_dvc_table) - 1, 0,
+ tas2563_digital_gain_get, tas2563_digital_gain_put,
+ tas2563_dvc_tlv),
};
static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
@@ -380,23 +487,41 @@ static void tasdevice_fw_ready(const struct firmware *fmw,
mutex_lock(&tas_priv->codec_lock);
ret = tasdevice_rca_parser(tas_priv, fmw);
- if (ret)
+ if (ret) {
+ tasdevice_config_info_remove(tas_priv);
goto out;
+ }
tasdevice_create_control(tas_priv);
tasdevice_dsp_remove(tas_priv);
tasdevice_calbin_remove(tas_priv);
- tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
- scnprintf(tas_priv->coef_binaryname, 64, "%s_coef.bin",
- tas_priv->dev_name);
+ /*
+ * The baseline is the RCA-only case, and then the code attempts to
+ * load DSP firmware but in case of failures just keep going, i.e.
+ * failing to load DSP firmware is NOT an error.
+ */
+ tas_priv->fw_state = TASDEVICE_RCA_FW_OK;
+ if (tas_priv->name_prefix)
+ scnprintf(tas_priv->rca_binaryname, 64, "%s-%s_coef.bin",
+ tas_priv->name_prefix, tas_priv->dev_name);
+ else
+ scnprintf(tas_priv->coef_binaryname, 64, "%s_coef.bin",
+ tas_priv->dev_name);
ret = tasdevice_dsp_parser(tas_priv);
if (ret) {
dev_err(tas_priv->dev, "dspfw load %s error\n",
tas_priv->coef_binaryname);
- tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
goto out;
}
- tasdevice_dsp_create_ctrls(tas_priv);
+
+ /*
+ * If no dsp-related kcontrol created, the dsp resource will be freed.
+ */
+ ret = tasdevice_dsp_create_ctrls(tas_priv);
+ if (ret) {
+ dev_err(tas_priv->dev, "dsp controls error\n");
+ goto out;
+ }
tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
@@ -404,8 +529,15 @@ static void tasdevice_fw_ready(const struct firmware *fmw,
* calibrated data inside algo.
*/
for (i = 0; i < tas_priv->ndev; i++) {
- scnprintf(tas_priv->cal_binaryname[i], 64, "%s_cal_0x%02x.bin",
- tas_priv->dev_name, tas_priv->tasdevice[i].dev_addr);
+ if (tas_priv->name_prefix)
+ scnprintf(tas_priv->cal_binaryname[i], 64,
+ "%s-%s_cal_0x%02x.bin", tas_priv->name_prefix,
+ tas_priv->dev_name,
+ tas_priv->tasdevice[i].dev_addr);
+ else
+ scnprintf(tas_priv->cal_binaryname[i], 64,
+ "%s_cal_0x%02x.bin", tas_priv->dev_name,
+ tas_priv->tasdevice[i].dev_addr);
ret = tas2781_load_calibration(tas_priv,
tas_priv->cal_binaryname[i], i);
if (ret != 0)
@@ -417,9 +549,8 @@ static void tasdevice_fw_ready(const struct firmware *fmw,
tasdevice_prmg_load(tas_priv, 0);
tas_priv->cur_prog = 0;
out:
- if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) {
- /*If DSP FW fail, kcontrol won't be created */
- tasdevice_config_info_remove(tas_priv);
+ if (tas_priv->fw_state == TASDEVICE_RCA_FW_OK) {
+ /* If DSP FW fail, DSP kcontrol won't be created. */
tasdevice_dsp_remove(tas_priv);
}
mutex_unlock(&tas_priv->codec_lock);
@@ -466,14 +597,14 @@ static int tasdevice_startup(struct snd_pcm_substream *substream,
{
struct snd_soc_component *codec = dai->component;
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
- int ret = 0;
- if (tas_priv->fw_state != TASDEVICE_DSP_FW_ALL_OK) {
- dev_err(tas_priv->dev, "DSP bin file not loaded\n");
- ret = -EINVAL;
+ switch (tas_priv->fw_state) {
+ case TASDEVICE_RCA_FW_OK:
+ case TASDEVICE_DSP_FW_ALL_OK:
+ return 0;
+ default:
+ return -EINVAL;
}
-
- return ret;
}
static int tasdevice_hw_params(struct snd_pcm_substream *substream,
@@ -565,7 +696,28 @@ static struct snd_soc_dai_driver tasdevice_dai_driver[] = {
static int tasdevice_codec_probe(struct snd_soc_component *codec)
{
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ struct snd_kcontrol_new *p;
+ unsigned int size;
+ int rc;
+
+ switch (tas_priv->chip_id) {
+ case TAS2781:
+ p = (struct snd_kcontrol_new *)tas2781_snd_controls;
+ size = ARRAY_SIZE(tas2781_snd_controls);
+ break;
+ default:
+ p = (struct snd_kcontrol_new *)tas2563_snd_controls;
+ size = ARRAY_SIZE(tas2563_snd_controls);
+ }
+
+ rc = snd_soc_add_component_controls(codec, p, size);
+ if (rc < 0) {
+ dev_err(tas_priv->dev, "%s: Add control err rc = %d",
+ __func__, rc);
+ return rc;
+ }
+ tas_priv->name_prefix = codec->name_prefix;
return tascodec_init(tas_priv, codec, THIS_MODULE, tasdevice_fw_ready);
}
@@ -591,8 +743,8 @@ static const struct snd_soc_component_driver
soc_codec_driver_tasdevice = {
.probe = tasdevice_codec_probe,
.remove = tasdevice_codec_remove,
- .controls = tas2781_snd_controls,
- .num_controls = ARRAY_SIZE(tas2781_snd_controls),
+ .controls = tasdevice_snd_controls,
+ .num_controls = ARRAY_SIZE(tasdevice_snd_controls),
.dapm_widgets = tasdevice_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(tasdevice_dapm_widgets),
.dapm_routes = tasdevice_audio_map,
@@ -622,33 +774,20 @@ static void tasdevice_parse_dt(struct tasdevice_priv *tas_priv)
tas_priv->irq_info.irq_gpio =
acpi_dev_gpio_irq_get(ACPI_COMPANION(&client->dev), 0);
- } else {
+ } else if (IS_ENABLED(CONFIG_OF)) {
struct device_node *np = tas_priv->dev->of_node;
-#ifdef CONFIG_OF
- const __be32 *reg, *reg_end;
- int len, sw, aw;
-
- aw = of_n_addr_cells(np);
- sw = of_n_size_cells(np);
- if (sw == 0) {
- reg = (const __be32 *)of_get_property(np,
- "reg", &len);
- reg_end = reg + len/sizeof(*reg);
- ndev = 0;
- do {
- dev_addrs[ndev] = of_read_number(reg, aw);
- reg += aw;
- ndev++;
- } while (reg < reg_end);
- } else {
- ndev = 1;
- dev_addrs[0] = client->addr;
+ u64 addr;
+
+ for (i = 0; i < TASDEVICE_MAX_CHANNELS; i++) {
+ if (of_property_read_reg(np, i, &addr, NULL))
+ break;
+ dev_addrs[ndev++] = addr;
}
-#else
+
+ tas_priv->irq_info.irq_gpio = of_irq_get(np, 0);
+ } else {
ndev = 1;
dev_addrs[0] = client->addr;
-#endif
- tas_priv->irq_info.irq_gpio = of_irq_get(np, 0);
}
tas_priv->ndev = ndev;
for (i = 0; i < ndev; i++)
@@ -714,6 +853,8 @@ static int tasdevice_i2c_probe(struct i2c_client *i2c)
if (ret)
goto err;
+ tasdevice_reset(tas_priv);
+
ret = devm_snd_soc_register_component(tas_priv->dev,
&soc_codec_driver_tasdevice,
tasdevice_dai_driver, ARRAY_SIZE(tasdevice_dai_driver));
@@ -746,7 +887,7 @@ MODULE_DEVICE_TABLE(acpi, tasdevice_acpi_match);
static struct i2c_driver tasdevice_i2c_driver = {
.driver = {
- .name = "tas2781-codec",
+ .name = "tasdev-codec",
.of_match_table = of_match_ptr(tasdevice_of_match),
#ifdef CONFIG_ACPI
.acpi_match_table = ACPI_PTR(tasdevice_acpi_match),
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
index 6d45df3b9ba4..4bc1fdd232bb 100644
--- a/sound/soc/codecs/tas5086.c
+++ b/sound/soc/codecs/tas5086.c
@@ -24,14 +24,13 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -246,7 +245,7 @@ struct tas5086_private {
/* Current sample rate for de-emphasis control */
int rate;
/* GPIO driving Reset pin, if any */
- int gpio_nreset;
+ struct gpio_desc *reset;
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
};
@@ -462,11 +461,11 @@ static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
static void tas5086_reset(struct tas5086_private *priv)
{
- if (gpio_is_valid(priv->gpio_nreset)) {
+ if (priv->reset) {
/* Reset codec - minimum assertion time is 400ns */
- gpio_direction_output(priv->gpio_nreset, 0);
+ gpiod_direction_output(priv->reset, 1);
udelay(1);
- gpio_set_value(priv->gpio_nreset, 1);
+ gpiod_set_value(priv->reset, 0);
/* Codec needs ~15ms to wake up */
msleep(15);
@@ -867,9 +866,9 @@ static void tas5086_remove(struct snd_soc_component *component)
{
struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
- if (gpio_is_valid(priv->gpio_nreset))
+ if (priv->reset)
/* Set codec to the reset state */
- gpio_set_value(priv->gpio_nreset, 0);
+ gpiod_set_value(priv->reset, 1);
regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
};
@@ -914,7 +913,6 @@ static int tas5086_i2c_probe(struct i2c_client *i2c)
{
struct tas5086_private *priv;
struct device *dev = &i2c->dev;
- int gpio_nreset = -EINVAL;
int i, ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -940,12 +938,11 @@ static int tas5086_i2c_probe(struct i2c_client *i2c)
i2c_set_clientdata(i2c, priv);
- gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0);
- if (gpio_is_valid(gpio_nreset))
- if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset"))
- gpio_nreset = -EINVAL;
-
- priv->gpio_nreset = gpio_nreset;
+ /* Request line asserted */
+ priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset))
+ return PTR_ERR(priv->reset);
+ gpiod_set_consumer_name(priv->reset, "TAS5086 Reset");
ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
if (ret < 0) {
diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c
index e100cc9f5c19..7073b9d1cda8 100644
--- a/sound/soc/codecs/tlv320adc3xxx.c
+++ b/sound/soc/codecs/tlv320adc3xxx.c
@@ -25,7 +25,6 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -40,9 +39,10 @@
*/
#define ADC3XXX_MICBIAS_PINS 2
+#define ADC3XXX_GPIO_PINS 2
/* Number of GPIO pins exposed via the gpiolib interface */
-#define ADC3XXX_GPIOS_MAX 2
+#define ADC3XXX_GPIOS_MAX (ADC3XXX_MICBIAS_PINS + ADC3XXX_GPIO_PINS)
#define ADC3XXX_RATES SNDRV_PCM_RATE_8000_96000
#define ADC3XXX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -321,7 +321,8 @@ struct adc3xxx {
struct gpio_desc *rst_pin;
unsigned int pll_mode;
unsigned int sysclk;
- unsigned int gpio_cfg[ADC3XXX_GPIOS_MAX]; /* value+1 (0 => not set) */
+ unsigned int gpio_cfg[ADC3XXX_GPIO_PINS]; /* value+1 (0 => not set) */
+ unsigned int micbias_gpo[ADC3XXX_MICBIAS_PINS]; /* 1 => pin is GPO */
unsigned int micbias_vg[ADC3XXX_MICBIAS_PINS];
int master;
u8 page_no;
@@ -329,7 +330,7 @@ struct adc3xxx {
struct gpio_chip gpio_chip;
};
-static const unsigned int adc3xxx_gpio_ctrl_reg[ADC3XXX_GPIOS_MAX] = {
+static const unsigned int adc3xxx_gpio_ctrl_reg[ADC3XXX_GPIO_PINS] = {
ADC3XXX_GPIO1_CTRL,
ADC3XXX_GPIO2_CTRL
};
@@ -960,14 +961,23 @@ static int adc3xxx_gpio_request(struct gpio_chip *chip, unsigned int offset)
if (offset >= ADC3XXX_GPIOS_MAX)
return -EINVAL;
- /* GPIO1 is offset 0, GPIO2 is offset 1 */
- /* We check here that the GPIO pins are either not configured in the
- * DT, or that they purposely are set as outputs.
- * (Input mode not yet implemented).
- */
- if (adc3xxx->gpio_cfg[offset] != 0 &&
- adc3xxx->gpio_cfg[offset] != ADC3XXX_GPIO_GPO + 1)
- return -EINVAL;
+ if (offset >= 0 && offset < ADC3XXX_GPIO_PINS) {
+ /* GPIO1 is offset 0, GPIO2 is offset 1 */
+ /* We check here that the GPIO pins are either not configured
+ * in the DT, or that they purposely are set as outputs.
+ * (Input mode not yet implemented).
+ */
+ if (adc3xxx->gpio_cfg[offset] != 0 &&
+ adc3xxx->gpio_cfg[offset] != ADC3XXX_GPIO_GPO + 1)
+ return -EINVAL;
+ } else if (offset >= ADC3XXX_GPIO_PINS && offset < ADC3XXX_GPIOS_MAX) {
+ /* MICBIAS1 is offset 2, MICBIAS2 is offset 3 */
+ /* We check here if the MICBIAS pins are in fact configured
+ * as GPOs.
+ */
+ if (!adc3xxx->micbias_gpo[offset - ADC3XXX_GPIO_PINS])
+ return -EINVAL;
+ }
return 0;
}
@@ -977,6 +987,21 @@ static int adc3xxx_gpio_direction_out(struct gpio_chip *chip,
{
struct adc3xxx *adc3xxx = gpiochip_get_data(chip);
+ /* For the MICBIAS pins, they are by definition outputs. */
+ if (offset >= ADC3XXX_GPIO_PINS) {
+ unsigned int vg;
+ unsigned int micbias = offset - ADC3XXX_GPIO_PINS;
+
+ if (value)
+ vg = adc3xxx->micbias_vg[micbias];
+ else
+ vg = ADC3XXX_MICBIAS_OFF;
+ return regmap_update_bits(adc3xxx->regmap,
+ ADC3XXX_MICBIAS_CTRL,
+ ADC3XXX_MICBIAS_MASK << adc3xxx_micbias_shift[micbias],
+ vg << adc3xxx_micbias_shift[micbias]);
+ }
+
/* Set GPIO output function. */
return regmap_update_bits(adc3xxx->regmap,
adc3xxx_gpio_ctrl_reg[offset],
@@ -1005,9 +1030,17 @@ static int adc3xxx_gpio_get(struct gpio_chip *chip, unsigned int offset)
unsigned int regval;
int ret;
- /* We only allow output pins, so just read the value set in the output
- * pin register field.
- */
+ /* We only allow output pins, so just read the value prevously set. */
+ if (offset >= ADC3XXX_GPIO_PINS) {
+ /* MICBIAS pins */
+ unsigned int micbias = offset - ADC3XXX_GPIO_PINS;
+
+ ret = regmap_read(adc3xxx->regmap, ADC3XXX_MICBIAS_CTRL, &regval);
+ if (ret)
+ return ret;
+ return ((regval >> adc3xxx_micbias_shift[micbias]) & ADC3XXX_MICBIAS_MASK) !=
+ ADC3XXX_MICBIAS_OFF;
+ }
ret = regmap_read(adc3xxx->regmap, adc3xxx_gpio_ctrl_reg[offset], &regval);
if (ret)
return ret;
@@ -1049,7 +1082,7 @@ static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx)
* This allows us to set up things which are not software
* controllable GPIOs, such as PDM microphone I/O,
*/
- for (gpio = 0; gpio < ADC3XXX_GPIOS_MAX; gpio++) {
+ for (gpio = 0; gpio < ADC3XXX_GPIO_PINS; gpio++) {
unsigned int cfg = adc3xxx->gpio_cfg[gpio];
if (cfg) {
@@ -1061,9 +1094,15 @@ static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx)
}
}
- /* Set up micbias voltage */
+ /* Set up micbias voltage. */
+ /* If pin is configured as GPO, set off initially. */
for (micbias = 0; micbias < ADC3XXX_MICBIAS_PINS; micbias++) {
- unsigned int vg = adc3xxx->micbias_vg[micbias];
+ unsigned int vg;
+
+ if (adc3xxx->micbias_gpo[micbias])
+ vg = ADC3XXX_MICBIAS_OFF;
+ else
+ vg = adc3xxx->micbias_vg[micbias];
regmap_update_bits(adc3xxx->regmap,
ADC3XXX_MICBIAS_CTRL,
@@ -1091,8 +1130,19 @@ static int adc3xxx_parse_dt_gpio(struct adc3xxx *adc3xxx,
return 0;
}
-static int adc3xxx_parse_dt_micbias(struct adc3xxx *adc3xxx,
- const char *propname, unsigned int *vg)
+static int adc3xxx_parse_dt_micbias_gpo(struct adc3xxx *adc3xxx,
+ const char *propname,
+ unsigned int *cfg)
+{
+ struct device *dev = adc3xxx->dev;
+ struct device_node *np = dev->of_node;
+
+ *cfg = of_property_read_bool(np, propname);
+ return 0;
+}
+
+static int adc3xxx_parse_dt_micbias_vg(struct adc3xxx *adc3xxx,
+ const char *propname, unsigned int *vg)
{
struct device *dev = adc3xxx->dev;
struct device_node *np = dev->of_node;
@@ -1383,16 +1433,28 @@ static int adc3xxx_i2c_probe(struct i2c_client *i2c)
dev_dbg(dev, "Enabled MCLK, freq %lu Hz\n", clk_get_rate(adc3xxx->mclk));
}
+ /* Configure mode for DMDIN/GPIO1 pin */
ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmdin-gpio1", &adc3xxx->gpio_cfg[0]);
if (ret < 0)
goto err_unprepare_mclk;
+ /* Configure mode for DMCLK/GPIO2 pin */
ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmclk-gpio2", &adc3xxx->gpio_cfg[1]);
if (ret < 0)
goto err_unprepare_mclk;
- ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]);
+ /* Configure mode for MICBIAS1: as Mic Bias output or GPO */
+ ret = adc3xxx_parse_dt_micbias_gpo(adc3xxx, "ti,micbias1-gpo", &adc3xxx->micbias_gpo[0]);
+ if (ret < 0)
+ goto err_unprepare_mclk;
+ /* Configure mode for MICBIAS2: as Mic Bias output or GPO */
+ ret = adc3xxx_parse_dt_micbias_gpo(adc3xxx, "ti,micbias2-gpo", &adc3xxx->micbias_gpo[1]);
+ if (ret < 0)
+ goto err_unprepare_mclk;
+ /* Configure voltage for MICBIAS1 pin (ON voltage when used as GPO) */
+ ret = adc3xxx_parse_dt_micbias_vg(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]);
if (ret < 0)
goto err_unprepare_mclk;
- ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]);
+ /* Configure voltage for MICBIAS2 pin (ON voltage when used as GPO) */
+ ret = adc3xxx_parse_dt_micbias_vg(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]);
if (ret < 0)
goto err_unprepare_mclk;
diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c
index 41342b340680..d594bf166c0e 100644
--- a/sound/soc/codecs/tlv320adcx140.c
+++ b/sound/soc/codecs/tlv320adcx140.c
@@ -12,7 +12,6 @@
#include <linux/regulator/consumer.h>
#include <linux/acpi.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 4d7c5a80c6ed..2f94cfda0e33 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -23,7 +23,6 @@
#include <linux/regulator/consumer.h>
#include <linux/acpi.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/jack.h>
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
index dbf448dd8864..b9eb59e3bfa0 100644
--- a/sound/soc/codecs/ts3a227e.c
+++ b/sound/soc/codecs/ts3a227e.c
@@ -10,7 +10,6 @@
#include <linux/init.h>
#include <linux/input.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/acpi.h>
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index 0e6218ed0e5e..d589a212b768 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -50,7 +50,7 @@ struct wcd_mbhc {
struct wcd_mbhc_config *cfg;
const struct wcd_mbhc_cb *mbhc_cb;
const struct wcd_mbhc_intr *intr_ids;
- struct wcd_mbhc_field *fields;
+ const struct wcd_mbhc_field *fields;
/* Delayed work to report long button press */
struct delayed_work mbhc_btn_dwork;
/* Work to handle plug report */
@@ -1505,7 +1505,7 @@ EXPORT_SYMBOL(wcd_dt_parse_mbhc_data);
struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
const struct wcd_mbhc_cb *mbhc_cb,
const struct wcd_mbhc_intr *intr_ids,
- struct wcd_mbhc_field *fields,
+ const struct wcd_mbhc_field *fields,
bool impedance_det_en)
{
struct device *dev = component->dev;
diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h
index df68e99c81a3..b977e8f87d7c 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.h
+++ b/sound/soc/codecs/wcd-mbhc-v2.h
@@ -279,7 +279,7 @@ int wcd_mbhc_typec_report_unplug(struct wcd_mbhc *mbhc);
struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
const struct wcd_mbhc_cb *mbhc_cb,
const struct wcd_mbhc_intr *mbhc_cdc_intr_ids,
- struct wcd_mbhc_field *fields,
+ const struct wcd_mbhc_field *fields,
bool impedance_det_en);
int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
uint32_t *zr);
@@ -300,7 +300,7 @@ static inline void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
static inline struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
const struct wcd_mbhc_cb *mbhc_cb,
const struct wcd_mbhc_intr *mbhc_cdc_intr_ids,
- struct wcd_mbhc_field *fields,
+ const struct wcd_mbhc_field *fields,
bool impedance_det_en)
{
return ERR_PTR(-ENOTSUPP);
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index deb15b95992d..373a31ddccb2 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -5,6 +5,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/bitops.h>
@@ -297,7 +298,6 @@ struct wcd9335_codec {
struct clk *mclk;
struct clk *native_clk;
u32 mclk_rate;
- u8 version;
struct slim_device *slim;
struct slim_device *slim_ifc_dev;
@@ -345,10 +345,6 @@ struct wcd9335_codec {
int dmic_0_1_clk_cnt;
int dmic_2_3_clk_cnt;
int dmic_4_5_clk_cnt;
- int dmic_sample_rate;
- int mad_dmic_sample_rate;
-
- int native_clk_users;
};
struct wcd9335_irq {
@@ -397,13 +393,13 @@ struct interp_sample_rate {
int rate_val;
};
-static struct interp_sample_rate int_mix_rate_val[] = {
+static const struct interp_sample_rate int_mix_rate_val[] = {
{48000, 0x4}, /* 48K */
{96000, 0x5}, /* 96K */
{192000, 0x6}, /* 192K */
};
-static struct interp_sample_rate int_prim_rate_val[] = {
+static const struct interp_sample_rate int_prim_rate_val[] = {
{8000, 0x0}, /* 8K */
{16000, 0x1}, /* 16K */
{24000, -EINVAL},/* 24K */
@@ -1983,8 +1979,10 @@ static int wcd9335_trigger(struct snd_pcm_substream *substream, int cmd,
}
static int wcd9335_set_channel_map(struct snd_soc_dai *dai,
- unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
+ unsigned int tx_num,
+ const unsigned int *tx_slot,
+ unsigned int rx_num,
+ const unsigned int *rx_slot)
{
struct wcd9335_codec *wcd;
int i;
@@ -2012,7 +2010,7 @@ static int wcd9335_set_channel_map(struct snd_soc_dai *dai,
return 0;
}
-static int wcd9335_get_channel_map(struct snd_soc_dai *dai,
+static int wcd9335_get_channel_map(const struct snd_soc_dai *dai,
unsigned int *tx_num, unsigned int *tx_slot,
unsigned int *rx_num, unsigned int *rx_slot)
{
@@ -2717,25 +2715,23 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
unsigned int decimator;
char *dec_adc_mux_name = NULL;
- char *widget_name = NULL;
- char *wname;
+ char *widget_name;
int ret = 0, amic_n;
u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg;
u16 tx_gain_ctl_reg;
char *dec;
u8 hpf_coff_freq;
- widget_name = kmemdup_nul(w->name, 15, GFP_KERNEL);
- if (!widget_name)
+ char *wname __free(kfree) = kmemdup_nul(w->name, 15, GFP_KERNEL);
+ if (!wname)
return -ENOMEM;
- wname = widget_name;
+ widget_name = wname;
dec_adc_mux_name = strsep(&widget_name, " ");
if (!dec_adc_mux_name) {
dev_err(comp->dev, "%s: Invalid decimator = %s\n",
__func__, w->name);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
dec_adc_mux_name = widget_name;
@@ -2743,16 +2739,14 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
if (!dec) {
dev_err(comp->dev, "%s: decimator index not found\n",
__func__);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
ret = kstrtouint(dec, 10, &decimator);
if (ret < 0) {
dev_err(comp->dev, "%s: Invalid decimator = %s\n",
__func__, wname);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
tx_vol_ctl_reg = WCD9335_CDC_TX0_TX_PATH_CTL + 16 * decimator;
@@ -2839,62 +2833,20 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x00);
break;
}
-out:
- kfree(wname);
+
return ret;
}
static u8 wcd9335_get_dmic_clk_val(struct snd_soc_component *component,
- u32 mclk_rate, u32 dmic_clk_rate)
+ u32 mclk_rate)
{
- u32 div_factor;
u8 dmic_ctl_val;
- dev_err(component->dev,
- "%s: mclk_rate = %d, dmic_sample_rate = %d\n",
- __func__, mclk_rate, dmic_clk_rate);
-
- /* Default value to return in case of error */
if (mclk_rate == WCD9335_MCLK_CLK_9P6MHZ)
dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2;
else
dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3;
- if (dmic_clk_rate == 0) {
- dev_err(component->dev,
- "%s: dmic_sample_rate cannot be 0\n",
- __func__);
- goto done;
- }
-
- div_factor = mclk_rate / dmic_clk_rate;
- switch (div_factor) {
- case 2:
- dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2;
- break;
- case 3:
- dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3;
- break;
- case 4:
- dmic_ctl_val = WCD9335_DMIC_CLK_DIV_4;
- break;
- case 6:
- dmic_ctl_val = WCD9335_DMIC_CLK_DIV_6;
- break;
- case 8:
- dmic_ctl_val = WCD9335_DMIC_CLK_DIV_8;
- break;
- case 16:
- dmic_ctl_val = WCD9335_DMIC_CLK_DIV_16;
- break;
- default:
- dev_err(component->dev,
- "%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n",
- __func__, div_factor, mclk_rate, dmic_clk_rate);
- break;
- }
-
-done:
return dmic_ctl_val;
}
@@ -2948,11 +2900,7 @@ static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- dmic_rate_val =
- wcd9335_get_dmic_clk_val(comp,
- wcd->mclk_rate,
- wcd->dmic_sample_rate);
-
+ dmic_rate_val = wcd9335_get_dmic_clk_val(comp, wcd->mclk_rate);
(*dmic_clk_cnt)++;
if (*dmic_clk_cnt == 1) {
snd_soc_component_update_bits(comp, dmic_clk_reg,
@@ -2964,10 +2912,7 @@ static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w,
break;
case SND_SOC_DAPM_POST_PMD:
- dmic_rate_val =
- wcd9335_get_dmic_clk_val(comp,
- wcd->mclk_rate,
- wcd->mad_dmic_sample_rate);
+ dmic_rate_val = wcd9335_get_dmic_clk_val(comp, wcd->mclk_rate);
(*dmic_clk_cnt)--;
if (*dmic_clk_cnt == 0) {
snd_soc_component_update_bits(comp, dmic_clk_reg,
@@ -4024,7 +3969,7 @@ static irqreturn_t wcd9335_slimbus_irq(int irq, void *data)
return ret;
}
-static struct wcd9335_irq wcd9335_irqs[] = {
+static const struct wcd9335_irq wcd9335_irqs[] = {
{
.irq = WCD9335_IRQ_SLIMBUS,
.handler = wcd9335_slimbus_irq,
@@ -4961,7 +4906,7 @@ static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg)
}
}
-static struct regmap_config wcd9335_regmap_config = {
+static const struct regmap_config wcd9335_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.cache_type = REGCACHE_MAPLE,
@@ -4985,7 +4930,7 @@ static const struct regmap_range_cfg wcd9335_ifc_ranges[] = {
},
};
-static struct regmap_config wcd9335_ifc_regmap_config = {
+static const struct regmap_config wcd9335_ifc_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.can_multi_write = true,
@@ -5032,22 +4977,16 @@ static int wcd9335_parse_dt(struct wcd9335_codec *wcd)
int ret;
wcd->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
- if (wcd->reset_gpio < 0) {
- dev_err(dev, "Reset GPIO missing from DT\n");
- return wcd->reset_gpio;
- }
+ if (wcd->reset_gpio < 0)
+ return dev_err_probe(dev, wcd->reset_gpio, "Reset GPIO missing from DT\n");
wcd->mclk = devm_clk_get(dev, "mclk");
- if (IS_ERR(wcd->mclk)) {
- dev_err(dev, "mclk not found\n");
- return PTR_ERR(wcd->mclk);
- }
+ if (IS_ERR(wcd->mclk))
+ return dev_err_probe(dev, PTR_ERR(wcd->mclk), "mclk not found\n");
wcd->native_clk = devm_clk_get(dev, "slimbus");
- if (IS_ERR(wcd->native_clk)) {
- dev_err(dev, "slimbus clock not found\n");
- return PTR_ERR(wcd->native_clk);
- }
+ if (IS_ERR(wcd->native_clk))
+ return dev_err_probe(dev, PTR_ERR(wcd->native_clk), "slimbus clock not found\n");
wcd->supplies[0].supply = "vdd-buck";
wcd->supplies[1].supply = "vdd-buck-sido";
@@ -5056,10 +4995,8 @@ static int wcd9335_parse_dt(struct wcd9335_codec *wcd)
wcd->supplies[4].supply = "vdd-io";
ret = regulator_bulk_get(dev, WCD9335_MAX_SUPPLY, wcd->supplies);
- if (ret) {
- dev_err(dev, "Failed to get supplies: err = %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get supplies\n");
return 0;
}
@@ -5107,7 +5044,6 @@ static int wcd9335_bring_up(struct wcd9335_codec *wcd)
if (byte0 == 0x1) {
dev_info(wcd->dev, "WCD9335 CODEC version is v2.0\n");
- wcd->version = WCD9335_VERSION_2_0;
regmap_write(rm, WCD9335_CODEC_RPM_RST_CTL, 0x01);
regmap_write(rm, WCD9335_SIDO_SIDO_TEST_2, 0x00);
regmap_write(rm, WCD9335_SIDO_SIDO_CCL_8, 0x6F);
@@ -5159,10 +5095,8 @@ static int wcd9335_slim_probe(struct slim_device *slim)
wcd->dev = dev;
ret = wcd9335_parse_dt(wcd);
- if (ret) {
- dev_err(dev, "Error parsing DT: %d\n", ret);
+ if (ret)
return ret;
- }
ret = wcd9335_power_on_reset(wcd);
if (ret)
diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c
index de870c7819ca..291d0c80a6fc 100644
--- a/sound/soc/codecs/wcd934x.c
+++ b/sound/soc/codecs/wcd934x.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019, Linaro Limited
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/interrupt.h>
@@ -475,17 +476,12 @@ enum {
INTn_2_INP_SEL_PROXIMITY,
};
-enum {
- INTERP_MAIN_PATH,
- INTERP_MIX_PATH,
-};
-
struct interp_sample_rate {
int sample_rate;
int rate_val;
};
-static struct interp_sample_rate sr_val_tbl[] = {
+static const struct interp_sample_rate sr_val_tbl[] = {
{8000, 0x0},
{16000, 0x1},
{32000, 0x3},
@@ -527,7 +523,7 @@ static const struct regmap_range_cfg wcd934x_ifc_ranges[] = {
},
};
-static struct regmap_config wcd934x_ifc_regmap_config = {
+static const struct regmap_config wcd934x_ifc_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.max_register = 0xffff,
@@ -571,10 +567,7 @@ struct wcd934x_codec {
struct mutex micb_lock;
u32 micb_ref[WCD934X_MAX_MICBIAS];
u32 pullup_ref[WCD934X_MAX_MICBIAS];
- u32 micb1_mv;
u32 micb2_mv;
- u32 micb3_mv;
- u32 micb4_mv;
};
#define to_wcd934x_codec(_hw) container_of(_hw, struct wcd934x_codec, hw)
@@ -1217,7 +1210,7 @@ static const struct soc_enum cdc_if_tx13_mux_enum =
SOC_ENUM_SINGLE(WCD934X_DATA_HUB_SB_TX13_INP_CFG, 0,
ARRAY_SIZE(cdc_if_tx13_mux_text), cdc_if_tx13_mux_text);
-static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD934X_ANA_MBHC_MECH, 0x80),
WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD934X_ANA_MBHC_MECH, 0x40),
WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD934X_ANA_MBHC_MECH, 0x20),
@@ -1923,8 +1916,10 @@ static int wcd934x_trigger(struct snd_pcm_substream *substream, int cmd,
}
static int wcd934x_set_channel_map(struct snd_soc_dai *dai,
- unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
+ unsigned int tx_num,
+ const unsigned int *tx_slot,
+ unsigned int rx_num,
+ const unsigned int *rx_slot)
{
struct wcd934x_codec *wcd;
int i;
@@ -1958,7 +1953,7 @@ static int wcd934x_set_channel_map(struct snd_soc_dai *dai,
return 0;
}
-static int wcd934x_get_channel_map(struct snd_soc_dai *dai,
+static int wcd934x_get_channel_map(const struct snd_soc_dai *dai,
unsigned int *tx_num, unsigned int *tx_slot,
unsigned int *rx_num, unsigned int *rx_slot)
{
@@ -2206,7 +2201,8 @@ static int wcd934x_get_micbias_val(struct device *dev, const char *micbias,
mv = WCD934X_DEF_MICBIAS_MV;
}
- *micb_mv = mv;
+ if (micb_mv)
+ *micb_mv = mv;
return (mv - 1000) / 50;
}
@@ -2218,17 +2214,14 @@ static int wcd934x_init_dmic(struct snd_soc_component *comp)
u32 def_dmic_rate, dmic_clk_drv;
vout_ctl_1 = wcd934x_get_micbias_val(comp->dev,
- "qcom,micbias1-microvolt",
- &wcd->micb1_mv);
+ "qcom,micbias1-microvolt", NULL);
vout_ctl_2 = wcd934x_get_micbias_val(comp->dev,
"qcom,micbias2-microvolt",
&wcd->micb2_mv);
vout_ctl_3 = wcd934x_get_micbias_val(comp->dev,
- "qcom,micbias3-microvolt",
- &wcd->micb3_mv);
+ "qcom,micbias3-microvolt", NULL);
vout_ctl_4 = wcd934x_get_micbias_val(comp->dev,
- "qcom,micbias4-microvolt",
- &wcd->micb4_mv);
+ "qcom,micbias4-microvolt", NULL);
snd_soc_component_update_bits(comp, WCD934X_ANA_MICB1,
WCD934X_MICB_VAL_MASK, vout_ctl_1);
@@ -4981,25 +4974,23 @@ static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w,
struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
unsigned int decimator;
char *dec_adc_mux_name = NULL;
- char *widget_name = NULL;
- char *wname;
+ char *widget_name;
int ret = 0, amic_n;
u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg;
u16 tx_gain_ctl_reg;
char *dec;
u8 hpf_coff_freq;
- widget_name = kstrndup(w->name, 15, GFP_KERNEL);
- if (!widget_name)
+ char *wname __free(kfree) = kstrndup(w->name, 15, GFP_KERNEL);
+ if (!wname)
return -ENOMEM;
- wname = widget_name;
+ widget_name = wname;
dec_adc_mux_name = strsep(&widget_name, " ");
if (!dec_adc_mux_name) {
dev_err(comp->dev, "%s: Invalid decimator = %s\n",
__func__, w->name);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
dec_adc_mux_name = widget_name;
@@ -5007,16 +4998,14 @@ static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w,
if (!dec) {
dev_err(comp->dev, "%s: decimator index not found\n",
__func__);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
ret = kstrtouint(dec, 10, &decimator);
if (ret < 0) {
dev_err(comp->dev, "%s: Invalid decimator = %s\n",
__func__, wname);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
tx_vol_ctl_reg = WCD934X_CDC_TX0_TX_PATH_CTL + 16 * decimator;
@@ -5109,8 +5098,7 @@ static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w,
WCD934X_DEC_PWR_LVL_DF);
break;
}
-out:
- kfree(wname);
+
return ret;
}
@@ -5864,17 +5852,13 @@ static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd)
struct device_node *ifc_dev_np;
ifc_dev_np = of_parse_phandle(dev->of_node, "slim-ifc-dev", 0);
- if (!ifc_dev_np) {
- dev_err(dev, "No Interface device found\n");
- return -EINVAL;
- }
+ if (!ifc_dev_np)
+ return dev_err_probe(dev, -EINVAL, "No Interface device found\n");
wcd->sidev = of_slim_get_device(wcd->sdev->ctrl, ifc_dev_np);
of_node_put(ifc_dev_np);
- if (!wcd->sidev) {
- dev_err(dev, "Unable to get SLIM Interface device\n");
- return -EINVAL;
- }
+ if (!wcd->sidev)
+ return dev_err_probe(dev, -EINVAL, "Unable to get SLIM Interface device\n");
slim_get_logical_addr(wcd->sidev);
wcd->if_regmap = regmap_init_slimbus(wcd->sidev,
@@ -5920,10 +5904,8 @@ static int wcd934x_codec_probe(struct platform_device *pdev)
mutex_init(&wcd->micb_lock);
ret = wcd934x_codec_parse_data(wcd);
- if (ret) {
- dev_err(wcd->dev, "Failed to get SLIM IRQ\n");
+ if (ret)
return ret;
- }
/* set default rate 9P6MHz */
regmap_update_bits(wcd->regmap, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
diff --git a/sound/soc/codecs/wcd937x-sdw.c b/sound/soc/codecs/wcd937x-sdw.c
new file mode 100644
index 000000000000..3abc8041406a
--- /dev/null
+++ b/sound/soc/codecs/wcd937x-sdw.c
@@ -0,0 +1,1137 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc.h>
+#include "wcd937x.h"
+
+static const struct wcd937x_sdw_ch_info wcd937x_sdw_rx_ch_info[] = {
+ WCD_SDW_CH(WCD937X_HPH_L, WCD937X_HPH_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_HPH_R, WCD937X_HPH_PORT, BIT(1)),
+ WCD_SDW_CH(WCD937X_CLSH, WCD937X_CLSH_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_COMP_L, WCD937X_COMP_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_COMP_R, WCD937X_COMP_PORT, BIT(1)),
+ WCD_SDW_CH(WCD937X_LO, WCD937X_LO_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_DSD_L, WCD937X_DSD_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_DSD_R, WCD937X_DSD_PORT, BIT(1)),
+};
+
+static const struct wcd937x_sdw_ch_info wcd937x_sdw_tx_ch_info[] = {
+ WCD_SDW_CH(WCD937X_ADC1, WCD937X_ADC_1_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_ADC2, WCD937X_ADC_2_3_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_ADC3, WCD937X_ADC_2_3_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_DMIC0, WCD937X_DMIC_0_3_MBHC_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_DMIC1, WCD937X_DMIC_0_3_MBHC_PORT, BIT(1)),
+ WCD_SDW_CH(WCD937X_MBHC, WCD937X_DMIC_0_3_MBHC_PORT, BIT(2)),
+ WCD_SDW_CH(WCD937X_DMIC2, WCD937X_DMIC_0_3_MBHC_PORT, BIT(2)),
+ WCD_SDW_CH(WCD937X_DMIC3, WCD937X_DMIC_0_3_MBHC_PORT, BIT(3)),
+ WCD_SDW_CH(WCD937X_DMIC4, WCD937X_DMIC_4_6_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_DMIC5, WCD937X_DMIC_4_6_PORT, BIT(1)),
+ WCD_SDW_CH(WCD937X_DMIC6, WCD937X_DMIC_4_6_PORT, BIT(2)),
+};
+
+static struct sdw_dpn_prop wcd937x_dpn_prop[WCD937X_MAX_SWR_PORTS] = {
+ {
+ .num = 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 8,
+ .simple_ch_prep_sm = true,
+ }, {
+ .num = 2,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 4,
+ .simple_ch_prep_sm = true,
+ }, {
+ .num = 3,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 4,
+ .simple_ch_prep_sm = true,
+ }, {
+ .num = 4,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 4,
+ .simple_ch_prep_sm = true,
+ }, {
+ .num = 5,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 4,
+ .simple_ch_prep_sm = true,
+ }
+};
+
+struct device *wcd937x_sdw_device_get(struct device_node *np)
+{
+ return bus_find_device_by_of_node(&sdw_bus_type, np);
+}
+EXPORT_SYMBOL_GPL(wcd937x_sdw_device_get);
+
+int wcd937x_sdw_hw_params(struct wcd937x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct sdw_port_config port_config[WCD937X_MAX_SWR_PORTS];
+ unsigned long ch_mask;
+ int i, j;
+
+ wcd->sconfig.ch_count = 1;
+ wcd->active_ports = 0;
+ for (i = 0; i < WCD937X_MAX_SWR_PORTS; i++) {
+ ch_mask = wcd->port_config[i].ch_mask;
+ if (!ch_mask)
+ continue;
+
+ for_each_set_bit(j, &ch_mask, 4)
+ wcd->sconfig.ch_count++;
+
+ port_config[wcd->active_ports] = wcd->port_config[i];
+ wcd->active_ports++;
+ }
+
+ wcd->sconfig.bps = 1;
+ wcd->sconfig.frame_rate = params_rate(params);
+ wcd->sconfig.direction = wcd->is_tx ? SDW_DATA_DIR_TX : SDW_DATA_DIR_RX;
+ wcd->sconfig.type = SDW_STREAM_PCM;
+
+ return sdw_stream_add_slave(wcd->sdev, &wcd->sconfig,
+ &port_config[0], wcd->active_ports,
+ wcd->sruntime);
+}
+EXPORT_SYMBOL_GPL(wcd937x_sdw_hw_params);
+
+static int wcd9370_update_status(struct sdw_slave *slave, enum sdw_slave_status status)
+{
+ struct wcd937x_sdw_priv *wcd = dev_get_drvdata(&slave->dev);
+
+ if (wcd->regmap && status == SDW_SLAVE_ATTACHED) {
+ /* Write out any cached changes that happened between probe and attach */
+ regcache_cache_only(wcd->regmap, false);
+ return regcache_sync(wcd->regmap);
+ }
+
+ return 0;
+}
+
+/*
+ * Handle Soundwire out-of-band interrupt event by triggering
+ * the first irq of the slave_irq irq domain, which then will
+ * be handled by the regmap_irq threaded irq.
+ * Looping is to ensure no interrupts were missed in the process.
+ */
+static int wcd9370_interrupt_callback(struct sdw_slave *slave,
+ struct sdw_slave_intr_status *status)
+{
+ struct wcd937x_sdw_priv *wcd = dev_get_drvdata(&slave->dev);
+ struct irq_domain *slave_irq = wcd->slave_irq;
+ u32 sts1, sts2, sts3;
+
+ do {
+ handle_nested_irq(irq_find_mapping(slave_irq, 0));
+ regmap_read(wcd->regmap, WCD937X_DIGITAL_INTR_STATUS_0, &sts1);
+ regmap_read(wcd->regmap, WCD937X_DIGITAL_INTR_STATUS_1, &sts2);
+ regmap_read(wcd->regmap, WCD937X_DIGITAL_INTR_STATUS_2, &sts3);
+
+ } while (sts1 || sts2 || sts3);
+
+ return IRQ_HANDLED;
+}
+
+static const struct reg_default wcd937x_defaults[] = {
+ /* Default values except for Read-Only & Volatile registers */
+ { WCD937X_ANA_BIAS, 0x00 },
+ { WCD937X_ANA_RX_SUPPLIES, 0x00 },
+ { WCD937X_ANA_HPH, 0x0c },
+ { WCD937X_ANA_EAR, 0x00 },
+ { WCD937X_ANA_EAR_COMPANDER_CTL, 0x02 },
+ { WCD937X_ANA_TX_CH1, 0x20 },
+ { WCD937X_ANA_TX_CH2, 0x00 },
+ { WCD937X_ANA_TX_CH3, 0x20 },
+ { WCD937X_ANA_TX_CH3_HPF, 0x00 },
+ { WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC, 0x00 },
+ { WCD937X_ANA_MICB3_DSP_EN_LOGIC, 0x00 },
+ { WCD937X_ANA_MBHC_MECH, 0x39 },
+ { WCD937X_ANA_MBHC_ELECT, 0x08 },
+ { WCD937X_ANA_MBHC_ZDET, 0x00 },
+ { WCD937X_ANA_MBHC_BTN0, 0x00 },
+ { WCD937X_ANA_MBHC_BTN1, 0x10 },
+ { WCD937X_ANA_MBHC_BTN2, 0x20 },
+ { WCD937X_ANA_MBHC_BTN3, 0x30 },
+ { WCD937X_ANA_MBHC_BTN4, 0x40 },
+ { WCD937X_ANA_MBHC_BTN5, 0x50 },
+ { WCD937X_ANA_MBHC_BTN6, 0x60 },
+ { WCD937X_ANA_MBHC_BTN7, 0x70 },
+ { WCD937X_ANA_MICB1, 0x10 },
+ { WCD937X_ANA_MICB2, 0x10 },
+ { WCD937X_ANA_MICB2_RAMP, 0x00 },
+ { WCD937X_ANA_MICB3, 0x10 },
+ { WCD937X_BIAS_CTL, 0x2a },
+ { WCD937X_BIAS_VBG_FINE_ADJ, 0x55 },
+ { WCD937X_LDOL_VDDCX_ADJUST, 0x01 },
+ { WCD937X_LDOL_DISABLE_LDOL, 0x00 },
+ { WCD937X_MBHC_CTL_CLK, 0x00 },
+ { WCD937X_MBHC_CTL_ANA, 0x00 },
+ { WCD937X_MBHC_CTL_SPARE_1, 0x00 },
+ { WCD937X_MBHC_CTL_SPARE_2, 0x00 },
+ { WCD937X_MBHC_CTL_BCS, 0x00 },
+ { WCD937X_MBHC_TEST_CTL, 0x00 },
+ { WCD937X_LDOH_MODE, 0x2b },
+ { WCD937X_LDOH_BIAS, 0x68 },
+ { WCD937X_LDOH_STB_LOADS, 0x00 },
+ { WCD937X_LDOH_SLOWRAMP, 0x50 },
+ { WCD937X_MICB1_TEST_CTL_1, 0x1a },
+ { WCD937X_MICB1_TEST_CTL_2, 0x18 },
+ { WCD937X_MICB1_TEST_CTL_3, 0xa4 },
+ { WCD937X_MICB2_TEST_CTL_1, 0x1a },
+ { WCD937X_MICB2_TEST_CTL_2, 0x18 },
+ { WCD937X_MICB2_TEST_CTL_3, 0xa4 },
+ { WCD937X_MICB3_TEST_CTL_1, 0x1a },
+ { WCD937X_MICB3_TEST_CTL_2, 0x18 },
+ { WCD937X_MICB3_TEST_CTL_3, 0xa4 },
+ { WCD937X_TX_COM_ADC_VCM, 0x39 },
+ { WCD937X_TX_COM_BIAS_ATEST, 0xc0 },
+ { WCD937X_TX_COM_ADC_INT1_IB, 0x6f },
+ { WCD937X_TX_COM_ADC_INT2_IB, 0x4f },
+ { WCD937X_TX_COM_TXFE_DIV_CTL, 0x2e },
+ { WCD937X_TX_COM_TXFE_DIV_START, 0x00 },
+ { WCD937X_TX_COM_TXFE_DIV_STOP_9P6M, 0xc7 },
+ { WCD937X_TX_COM_TXFE_DIV_STOP_12P288M, 0xff },
+ { WCD937X_TX_1_2_TEST_EN, 0xcc },
+ { WCD937X_TX_1_2_ADC_IB, 0x09 },
+ { WCD937X_TX_1_2_ATEST_REFCTL, 0x0a },
+ { WCD937X_TX_1_2_TEST_CTL, 0x38 },
+ { WCD937X_TX_1_2_TEST_BLK_EN, 0xff },
+ { WCD937X_TX_1_2_TXFE_CLKDIV, 0x00 },
+ { WCD937X_TX_3_TEST_EN, 0xcc },
+ { WCD937X_TX_3_ADC_IB, 0x09 },
+ { WCD937X_TX_3_ATEST_REFCTL, 0x0a },
+ { WCD937X_TX_3_TEST_CTL, 0x38 },
+ { WCD937X_TX_3_TEST_BLK_EN, 0xff },
+ { WCD937X_TX_3_TXFE_CLKDIV, 0x00 },
+ { WCD937X_TX_3_SPARE_MONO, 0x00 },
+ { WCD937X_CLASSH_MODE_1, 0x40 },
+ { WCD937X_CLASSH_MODE_2, 0x3a },
+ { WCD937X_CLASSH_MODE_3, 0x00 },
+ { WCD937X_CLASSH_CTRL_VCL_1, 0x70 },
+ { WCD937X_CLASSH_CTRL_VCL_2, 0x82 },
+ { WCD937X_CLASSH_CTRL_CCL_1, 0x31 },
+ { WCD937X_CLASSH_CTRL_CCL_2, 0x80 },
+ { WCD937X_CLASSH_CTRL_CCL_3, 0x80 },
+ { WCD937X_CLASSH_CTRL_CCL_4, 0x51 },
+ { WCD937X_CLASSH_CTRL_CCL_5, 0x00 },
+ { WCD937X_CLASSH_BUCK_TMUX_A_D, 0x00 },
+ { WCD937X_CLASSH_BUCK_SW_DRV_CNTL, 0x77 },
+ { WCD937X_CLASSH_SPARE, 0x00 },
+ { WCD937X_FLYBACK_EN, 0x4e },
+ { WCD937X_FLYBACK_VNEG_CTRL_1, 0x0b },
+ { WCD937X_FLYBACK_VNEG_CTRL_2, 0x45 },
+ { WCD937X_FLYBACK_VNEG_CTRL_3, 0x74 },
+ { WCD937X_FLYBACK_VNEG_CTRL_4, 0x7f },
+ { WCD937X_FLYBACK_VNEG_CTRL_5, 0x83 },
+ { WCD937X_FLYBACK_VNEG_CTRL_6, 0x98 },
+ { WCD937X_FLYBACK_VNEG_CTRL_7, 0xa9 },
+ { WCD937X_FLYBACK_VNEG_CTRL_8, 0x68 },
+ { WCD937X_FLYBACK_VNEG_CTRL_9, 0x64 },
+ { WCD937X_FLYBACK_VNEGDAC_CTRL_1, 0xed },
+ { WCD937X_FLYBACK_VNEGDAC_CTRL_2, 0xf0 },
+ { WCD937X_FLYBACK_VNEGDAC_CTRL_3, 0xa6 },
+ { WCD937X_FLYBACK_CTRL_1, 0x65 },
+ { WCD937X_FLYBACK_TEST_CTL, 0x00 },
+ { WCD937X_RX_AUX_SW_CTL, 0x00 },
+ { WCD937X_RX_PA_AUX_IN_CONN, 0x00 },
+ { WCD937X_RX_TIMER_DIV, 0x32 },
+ { WCD937X_RX_OCP_CTL, 0x1f },
+ { WCD937X_RX_OCP_COUNT, 0x77 },
+ { WCD937X_RX_BIAS_EAR_DAC, 0xa0 },
+ { WCD937X_RX_BIAS_EAR_AMP, 0xaa },
+ { WCD937X_RX_BIAS_HPH_LDO, 0xa9 },
+ { WCD937X_RX_BIAS_HPH_PA, 0xaa },
+ { WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8a },
+ { WCD937X_RX_BIAS_HPH_RDAC_LDO, 0x88 },
+ { WCD937X_RX_BIAS_HPH_CNP1, 0x82 },
+ { WCD937X_RX_BIAS_HPH_LOWPOWER, 0x82 },
+ { WCD937X_RX_BIAS_AUX_DAC, 0xa0 },
+ { WCD937X_RX_BIAS_AUX_AMP, 0xaa },
+ { WCD937X_RX_BIAS_VNEGDAC_BLEEDER, 0x50 },
+ { WCD937X_RX_BIAS_MISC, 0x00 },
+ { WCD937X_RX_BIAS_BUCK_RST, 0x08 },
+ { WCD937X_RX_BIAS_BUCK_VREF_ERRAMP, 0x44 },
+ { WCD937X_RX_BIAS_FLYB_ERRAMP, 0x40 },
+ { WCD937X_RX_BIAS_FLYB_BUFF, 0xaa },
+ { WCD937X_RX_BIAS_FLYB_MID_RST, 0x14 },
+ { WCD937X_HPH_CNP_EN, 0x80 },
+ { WCD937X_HPH_CNP_WG_CTL, 0x9a },
+ { WCD937X_HPH_CNP_WG_TIME, 0x14 },
+ { WCD937X_HPH_OCP_CTL, 0x28 },
+ { WCD937X_HPH_AUTO_CHOP, 0x16 },
+ { WCD937X_HPH_CHOP_CTL, 0x83 },
+ { WCD937X_HPH_PA_CTL1, 0x46 },
+ { WCD937X_HPH_PA_CTL2, 0x50 },
+ { WCD937X_HPH_L_EN, 0x80 },
+ { WCD937X_HPH_L_TEST, 0xe0 },
+ { WCD937X_HPH_L_ATEST, 0x50 },
+ { WCD937X_HPH_R_EN, 0x80 },
+ { WCD937X_HPH_R_TEST, 0xe0 },
+ { WCD937X_HPH_R_ATEST, 0x54 },
+ { WCD937X_HPH_RDAC_CLK_CTL1, 0x99 },
+ { WCD937X_HPH_RDAC_CLK_CTL2, 0x9b },
+ { WCD937X_HPH_RDAC_LDO_CTL, 0x33 },
+ { WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00 },
+ { WCD937X_HPH_REFBUFF_UHQA_CTL, 0xa8 },
+ { WCD937X_HPH_REFBUFF_LP_CTL, 0x0e },
+ { WCD937X_HPH_L_DAC_CTL, 0x20 },
+ { WCD937X_HPH_R_DAC_CTL, 0x20 },
+ { WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL, 0x55 },
+ { WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0x19 },
+ { WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1, 0xa0 },
+ { WCD937X_EAR_EAR_EN_REG, 0x22 },
+ { WCD937X_EAR_EAR_PA_CON, 0x44 },
+ { WCD937X_EAR_EAR_SP_CON, 0xdb },
+ { WCD937X_EAR_EAR_DAC_CON, 0x80 },
+ { WCD937X_EAR_EAR_CNP_FSM_CON, 0xb2 },
+ { WCD937X_EAR_TEST_CTL, 0x00 },
+ { WCD937X_ANA_NEW_PAGE_REGISTER, 0x00 },
+ { WCD937X_HPH_NEW_ANA_HPH2, 0x00 },
+ { WCD937X_HPH_NEW_ANA_HPH3, 0x00 },
+ { WCD937X_SLEEP_CTL, 0x16 },
+ { WCD937X_SLEEP_WATCHDOG_CTL, 0x00 },
+ { WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00 },
+ { WCD937X_MBHC_NEW_CTL_1, 0x02 },
+ { WCD937X_MBHC_NEW_CTL_2, 0x05 },
+ { WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0xe9 },
+ { WCD937X_MBHC_NEW_ZDET_ANA_CTL, 0x0f },
+ { WCD937X_MBHC_NEW_ZDET_RAMP_CTL, 0x00 },
+ { WCD937X_TX_NEW_TX_CH2_SEL, 0x00 },
+ { WCD937X_AUX_AUXPA, 0x00 },
+ { WCD937X_LDORXTX_MODE, 0x0c },
+ { WCD937X_LDORXTX_CONFIG, 0x10 },
+ { WCD937X_DIE_CRACK_DIE_CRK_DET_EN, 0x00 },
+ { WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40 },
+ { WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x81 },
+ { WCD937X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10 },
+ { WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 },
+ { WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x81 },
+ { WCD937X_HPH_NEW_INT_PA_MISC1, 0x22 },
+ { WCD937X_HPH_NEW_INT_PA_MISC2, 0x00 },
+ { WCD937X_HPH_NEW_INT_PA_RDAC_MISC, 0x00 },
+ { WCD937X_HPH_NEW_INT_HPH_TIMER1, 0xfe },
+ { WCD937X_HPH_NEW_INT_HPH_TIMER2, 0x02 },
+ { WCD937X_HPH_NEW_INT_HPH_TIMER3, 0x4e },
+ { WCD937X_HPH_NEW_INT_HPH_TIMER4, 0x54 },
+ { WCD937X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00 },
+ { WCD937X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 },
+ { WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x62 },
+ { WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01 },
+ { WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11 },
+ { WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL, 0x57 },
+ { WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 0x01 },
+ { WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x00 },
+ { WCD937X_MBHC_NEW_INT_SPARE_2, 0x00 },
+ { WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON, 0xa8 },
+ { WCD937X_EAR_INT_NEW_CNP_VCM_CON1, 0x42 },
+ { WCD937X_EAR_INT_NEW_CNP_VCM_CON2, 0x22 },
+ { WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS, 0x00 },
+ { WCD937X_AUX_INT_EN_REG, 0x00 },
+ { WCD937X_AUX_INT_PA_CTRL, 0x06 },
+ { WCD937X_AUX_INT_SP_CTRL, 0xd2 },
+ { WCD937X_AUX_INT_DAC_CTRL, 0x80 },
+ { WCD937X_AUX_INT_CLK_CTRL, 0x50 },
+ { WCD937X_AUX_INT_TEST_CTRL, 0x00 },
+ { WCD937X_AUX_INT_STATUS_REG, 0x00 },
+ { WCD937X_AUX_INT_MISC, 0x00 },
+ { WCD937X_LDORXTX_INT_BIAS, 0x6e },
+ { WCD937X_LDORXTX_INT_STB_LOADS_DTEST, 0x50 },
+ { WCD937X_LDORXTX_INT_TEST0, 0x1c },
+ { WCD937X_LDORXTX_INT_STARTUP_TIMER, 0xff },
+ { WCD937X_LDORXTX_INT_TEST1, 0x1f },
+ { WCD937X_LDORXTX_INT_STATUS, 0x00 },
+ { WCD937X_SLEEP_INT_WATCHDOG_CTL_1, 0x0a },
+ { WCD937X_SLEEP_INT_WATCHDOG_CTL_2, 0x0a },
+ { WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1, 0x02 },
+ { WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2, 0x60 },
+ { WCD937X_DIGITAL_PAGE_REGISTER, 0x00 },
+ { WCD937X_DIGITAL_CDC_RST_CTL, 0x03 },
+ { WCD937X_DIGITAL_TOP_CLK_CFG, 0x00 },
+ { WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x00 },
+ { WCD937X_DIGITAL_SWR_RST_EN, 0x00 },
+ { WCD937X_DIGITAL_CDC_PATH_MODE, 0x55 },
+ { WCD937X_DIGITAL_CDC_RX_RST, 0x00 },
+ { WCD937X_DIGITAL_CDC_RX0_CTL, 0xfc },
+ { WCD937X_DIGITAL_CDC_RX1_CTL, 0xfc },
+ { WCD937X_DIGITAL_CDC_RX2_CTL, 0xfc },
+ { WCD937X_DIGITAL_DEM_BYPASS_DATA0, 0x55 },
+ { WCD937X_DIGITAL_DEM_BYPASS_DATA1, 0x55 },
+ { WCD937X_DIGITAL_DEM_BYPASS_DATA2, 0x55 },
+ { WCD937X_DIGITAL_DEM_BYPASS_DATA3, 0x01 },
+ { WCD937X_DIGITAL_CDC_COMP_CTL_0, 0x00 },
+ { WCD937X_DIGITAL_CDC_RX_DELAY_CTL, 0x66 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A1_0, 0x00 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A1_1, 0x01 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A2_0, 0x63 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A2_1, 0x04 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A3_0, 0xac },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A3_1, 0x04 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A4_0, 0x1a },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A4_1, 0x03 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A5_0, 0xbc },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A5_1, 0x02 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A6_0, 0xc7 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A7_0, 0xf8 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_C_0, 0x47 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_C_1, 0x43 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_C_2, 0xb1 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_C_3, 0x17 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_R1, 0x4b },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_R2, 0x26 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_R3, 0x32 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_R4, 0x57 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_R5, 0x63 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_R6, 0x7c },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_R7, 0x57 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A1_0, 0x00 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A1_1, 0x01 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A2_0, 0x96 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A2_1, 0x09 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A3_0, 0xab },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A3_1, 0x05 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A4_0, 0x1c },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A4_1, 0x02 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A5_0, 0x17 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A5_1, 0x02 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A6_0, 0xaa },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A7_0, 0xe3 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_C_0, 0x69 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_C_1, 0x54 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_C_2, 0x02 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_C_3, 0x15 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_R1, 0xa4 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_R2, 0xb5 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_R3, 0x86 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_R4, 0x85 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_R5, 0xaa },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_R6, 0xe2 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_R7, 0x62 },
+ { WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0, 0x55 },
+ { WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1, 0xa9 },
+ { WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0, 0x3d },
+ { WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1, 0x2e },
+ { WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2, 0x01 },
+ { WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0, 0x00 },
+ { WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1, 0xfc },
+ { WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2, 0x01 },
+ { WCD937X_DIGITAL_CDC_HPH_GAIN_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_AUX_GAIN_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_EAR_PATH_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_SWR_CLH, 0x00 },
+ { WCD937X_DIGITAL_SWR_CLH_BYP, 0x00 },
+ { WCD937X_DIGITAL_CDC_TX0_CTL, 0x68 },
+ { WCD937X_DIGITAL_CDC_TX1_CTL, 0x68 },
+ { WCD937X_DIGITAL_CDC_TX2_CTL, 0x68 },
+ { WCD937X_DIGITAL_CDC_TX_RST, 0x00 },
+ { WCD937X_DIGITAL_CDC_REQ_CTL, 0x01 },
+ { WCD937X_DIGITAL_CDC_AMIC_CTL, 0x07 },
+ { WCD937X_DIGITAL_CDC_DMIC_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_DMIC1_CTL, 0x01 },
+ { WCD937X_DIGITAL_CDC_DMIC2_CTL, 0x01 },
+ { WCD937X_DIGITAL_CDC_DMIC3_CTL, 0x01 },
+ { WCD937X_DIGITAL_EFUSE_CTL, 0x2b },
+ { WCD937X_DIGITAL_EFUSE_PRG_CTL, 0x00 },
+ { WCD937X_DIGITAL_EFUSE_TEST_CTL_0, 0x00 },
+ { WCD937X_DIGITAL_EFUSE_TEST_CTL_1, 0x00 },
+ { WCD937X_DIGITAL_PDM_WD_CTL0, 0x00 },
+ { WCD937X_DIGITAL_PDM_WD_CTL1, 0x00 },
+ { WCD937X_DIGITAL_PDM_WD_CTL2, 0x00 },
+ { WCD937X_DIGITAL_INTR_MODE, 0x00 },
+ { WCD937X_DIGITAL_INTR_MASK_0, 0xff },
+ { WCD937X_DIGITAL_INTR_MASK_1, 0xff },
+ { WCD937X_DIGITAL_INTR_MASK_2, 0x0f },
+ { WCD937X_DIGITAL_INTR_CLEAR_0, 0x00 },
+ { WCD937X_DIGITAL_INTR_CLEAR_1, 0x00 },
+ { WCD937X_DIGITAL_INTR_CLEAR_2, 0x00 },
+ { WCD937X_DIGITAL_INTR_LEVEL_0, 0x00 },
+ { WCD937X_DIGITAL_INTR_LEVEL_1, 0x00 },
+ { WCD937X_DIGITAL_INTR_LEVEL_2, 0x00 },
+ { WCD937X_DIGITAL_INTR_SET_0, 0x00 },
+ { WCD937X_DIGITAL_INTR_SET_1, 0x00 },
+ { WCD937X_DIGITAL_INTR_SET_2, 0x00 },
+ { WCD937X_DIGITAL_INTR_TEST_0, 0x00 },
+ { WCD937X_DIGITAL_INTR_TEST_1, 0x00 },
+ { WCD937X_DIGITAL_INTR_TEST_2, 0x00 },
+ { WCD937X_DIGITAL_CDC_CONN_RX0_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_CONN_RX1_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_CONN_RX2_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_CONN_TX_CTL, 0x00 },
+ { WCD937X_DIGITAL_LOOP_BACK_MODE, 0x00 },
+ { WCD937X_DIGITAL_SWR_DAC_TEST, 0x00 },
+ { WCD937X_DIGITAL_SWR_HM_TEST_RX_0, 0x40 },
+ { WCD937X_DIGITAL_SWR_HM_TEST_TX_0, 0x40 },
+ { WCD937X_DIGITAL_SWR_HM_TEST_RX_1, 0x00 },
+ { WCD937X_DIGITAL_SWR_HM_TEST_TX_1, 0x00 },
+ { WCD937X_DIGITAL_PAD_CTL_PDM_RX0, 0xf1 },
+ { WCD937X_DIGITAL_PAD_CTL_PDM_RX1, 0xf1 },
+ { WCD937X_DIGITAL_PAD_CTL_PDM_TX0, 0xf1 },
+ { WCD937X_DIGITAL_PAD_CTL_PDM_TX1, 0xf1 },
+ { WCD937X_DIGITAL_PAD_INP_DIS_0, 0x00 },
+ { WCD937X_DIGITAL_PAD_INP_DIS_1, 0x00 },
+ { WCD937X_DIGITAL_DRIVE_STRENGTH_0, 0x00 },
+ { WCD937X_DIGITAL_DRIVE_STRENGTH_1, 0x00 },
+ { WCD937X_DIGITAL_DRIVE_STRENGTH_2, 0x00 },
+ { WCD937X_DIGITAL_RX_DATA_EDGE_CTL, 0x1f },
+ { WCD937X_DIGITAL_TX_DATA_EDGE_CTL, 0x10 },
+ { WCD937X_DIGITAL_GPIO_MODE, 0x00 },
+ { WCD937X_DIGITAL_PIN_CTL_OE, 0x00 },
+ { WCD937X_DIGITAL_PIN_CTL_DATA_0, 0x00 },
+ { WCD937X_DIGITAL_PIN_CTL_DATA_1, 0x00 },
+ { WCD937X_DIGITAL_DIG_DEBUG_CTL, 0x00 },
+ { WCD937X_DIGITAL_DIG_DEBUG_EN, 0x00 },
+ { WCD937X_DIGITAL_ANA_CSR_DBG_ADD, 0x00 },
+ { WCD937X_DIGITAL_ANA_CSR_DBG_CTL, 0x48 },
+ { WCD937X_DIGITAL_SSP_DBG, 0x00 },
+ { WCD937X_DIGITAL_SPARE_0, 0x00 },
+ { WCD937X_DIGITAL_SPARE_1, 0x00 },
+ { WCD937X_DIGITAL_SPARE_2, 0x00 },
+};
+
+static bool wcd937x_rdwr_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WCD937X_ANA_BIAS:
+ case WCD937X_ANA_RX_SUPPLIES:
+ case WCD937X_ANA_HPH:
+ case WCD937X_ANA_EAR:
+ case WCD937X_ANA_EAR_COMPANDER_CTL:
+ case WCD937X_ANA_TX_CH1:
+ case WCD937X_ANA_TX_CH2:
+ case WCD937X_ANA_TX_CH3:
+ case WCD937X_ANA_TX_CH3_HPF:
+ case WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC:
+ case WCD937X_ANA_MICB3_DSP_EN_LOGIC:
+ case WCD937X_ANA_MBHC_MECH:
+ case WCD937X_ANA_MBHC_ELECT:
+ case WCD937X_ANA_MBHC_ZDET:
+ case WCD937X_ANA_MBHC_BTN0:
+ case WCD937X_ANA_MBHC_BTN1:
+ case WCD937X_ANA_MBHC_BTN2:
+ case WCD937X_ANA_MBHC_BTN3:
+ case WCD937X_ANA_MBHC_BTN4:
+ case WCD937X_ANA_MBHC_BTN5:
+ case WCD937X_ANA_MBHC_BTN6:
+ case WCD937X_ANA_MBHC_BTN7:
+ case WCD937X_ANA_MICB1:
+ case WCD937X_ANA_MICB2:
+ case WCD937X_ANA_MICB2_RAMP:
+ case WCD937X_ANA_MICB3:
+ case WCD937X_BIAS_CTL:
+ case WCD937X_BIAS_VBG_FINE_ADJ:
+ case WCD937X_LDOL_VDDCX_ADJUST:
+ case WCD937X_LDOL_DISABLE_LDOL:
+ case WCD937X_MBHC_CTL_CLK:
+ case WCD937X_MBHC_CTL_ANA:
+ case WCD937X_MBHC_CTL_SPARE_1:
+ case WCD937X_MBHC_CTL_SPARE_2:
+ case WCD937X_MBHC_CTL_BCS:
+ case WCD937X_MBHC_TEST_CTL:
+ case WCD937X_LDOH_MODE:
+ case WCD937X_LDOH_BIAS:
+ case WCD937X_LDOH_STB_LOADS:
+ case WCD937X_LDOH_SLOWRAMP:
+ case WCD937X_MICB1_TEST_CTL_1:
+ case WCD937X_MICB1_TEST_CTL_2:
+ case WCD937X_MICB1_TEST_CTL_3:
+ case WCD937X_MICB2_TEST_CTL_1:
+ case WCD937X_MICB2_TEST_CTL_2:
+ case WCD937X_MICB2_TEST_CTL_3:
+ case WCD937X_MICB3_TEST_CTL_1:
+ case WCD937X_MICB3_TEST_CTL_2:
+ case WCD937X_MICB3_TEST_CTL_3:
+ case WCD937X_TX_COM_ADC_VCM:
+ case WCD937X_TX_COM_BIAS_ATEST:
+ case WCD937X_TX_COM_ADC_INT1_IB:
+ case WCD937X_TX_COM_ADC_INT2_IB:
+ case WCD937X_TX_COM_TXFE_DIV_CTL:
+ case WCD937X_TX_COM_TXFE_DIV_START:
+ case WCD937X_TX_COM_TXFE_DIV_STOP_9P6M:
+ case WCD937X_TX_COM_TXFE_DIV_STOP_12P288M:
+ case WCD937X_TX_1_2_TEST_EN:
+ case WCD937X_TX_1_2_ADC_IB:
+ case WCD937X_TX_1_2_ATEST_REFCTL:
+ case WCD937X_TX_1_2_TEST_CTL:
+ case WCD937X_TX_1_2_TEST_BLK_EN:
+ case WCD937X_TX_1_2_TXFE_CLKDIV:
+ case WCD937X_TX_3_TEST_EN:
+ case WCD937X_TX_3_ADC_IB:
+ case WCD937X_TX_3_ATEST_REFCTL:
+ case WCD937X_TX_3_TEST_CTL:
+ case WCD937X_TX_3_TEST_BLK_EN:
+ case WCD937X_TX_3_TXFE_CLKDIV:
+ case WCD937X_CLASSH_MODE_1:
+ case WCD937X_CLASSH_MODE_2:
+ case WCD937X_CLASSH_MODE_3:
+ case WCD937X_CLASSH_CTRL_VCL_1:
+ case WCD937X_CLASSH_CTRL_VCL_2:
+ case WCD937X_CLASSH_CTRL_CCL_1:
+ case WCD937X_CLASSH_CTRL_CCL_2:
+ case WCD937X_CLASSH_CTRL_CCL_3:
+ case WCD937X_CLASSH_CTRL_CCL_4:
+ case WCD937X_CLASSH_CTRL_CCL_5:
+ case WCD937X_CLASSH_BUCK_TMUX_A_D:
+ case WCD937X_CLASSH_BUCK_SW_DRV_CNTL:
+ case WCD937X_CLASSH_SPARE:
+ case WCD937X_FLYBACK_EN:
+ case WCD937X_FLYBACK_VNEG_CTRL_1:
+ case WCD937X_FLYBACK_VNEG_CTRL_2:
+ case WCD937X_FLYBACK_VNEG_CTRL_3:
+ case WCD937X_FLYBACK_VNEG_CTRL_4:
+ case WCD937X_FLYBACK_VNEG_CTRL_5:
+ case WCD937X_FLYBACK_VNEG_CTRL_6:
+ case WCD937X_FLYBACK_VNEG_CTRL_7:
+ case WCD937X_FLYBACK_VNEG_CTRL_8:
+ case WCD937X_FLYBACK_VNEG_CTRL_9:
+ case WCD937X_FLYBACK_VNEGDAC_CTRL_1:
+ case WCD937X_FLYBACK_VNEGDAC_CTRL_2:
+ case WCD937X_FLYBACK_VNEGDAC_CTRL_3:
+ case WCD937X_FLYBACK_CTRL_1:
+ case WCD937X_FLYBACK_TEST_CTL:
+ case WCD937X_RX_AUX_SW_CTL:
+ case WCD937X_RX_PA_AUX_IN_CONN:
+ case WCD937X_RX_TIMER_DIV:
+ case WCD937X_RX_OCP_CTL:
+ case WCD937X_RX_OCP_COUNT:
+ case WCD937X_RX_BIAS_EAR_DAC:
+ case WCD937X_RX_BIAS_EAR_AMP:
+ case WCD937X_RX_BIAS_HPH_LDO:
+ case WCD937X_RX_BIAS_HPH_PA:
+ case WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2:
+ case WCD937X_RX_BIAS_HPH_RDAC_LDO:
+ case WCD937X_RX_BIAS_HPH_CNP1:
+ case WCD937X_RX_BIAS_HPH_LOWPOWER:
+ case WCD937X_RX_BIAS_AUX_DAC:
+ case WCD937X_RX_BIAS_AUX_AMP:
+ case WCD937X_RX_BIAS_VNEGDAC_BLEEDER:
+ case WCD937X_RX_BIAS_MISC:
+ case WCD937X_RX_BIAS_BUCK_RST:
+ case WCD937X_RX_BIAS_BUCK_VREF_ERRAMP:
+ case WCD937X_RX_BIAS_FLYB_ERRAMP:
+ case WCD937X_RX_BIAS_FLYB_BUFF:
+ case WCD937X_RX_BIAS_FLYB_MID_RST:
+ case WCD937X_HPH_CNP_EN:
+ case WCD937X_HPH_CNP_WG_CTL:
+ case WCD937X_HPH_CNP_WG_TIME:
+ case WCD937X_HPH_OCP_CTL:
+ case WCD937X_HPH_AUTO_CHOP:
+ case WCD937X_HPH_CHOP_CTL:
+ case WCD937X_HPH_PA_CTL1:
+ case WCD937X_HPH_PA_CTL2:
+ case WCD937X_HPH_L_EN:
+ case WCD937X_HPH_L_TEST:
+ case WCD937X_HPH_L_ATEST:
+ case WCD937X_HPH_R_EN:
+ case WCD937X_HPH_R_TEST:
+ case WCD937X_HPH_R_ATEST:
+ case WCD937X_HPH_RDAC_CLK_CTL1:
+ case WCD937X_HPH_RDAC_CLK_CTL2:
+ case WCD937X_HPH_RDAC_LDO_CTL:
+ case WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL:
+ case WCD937X_HPH_REFBUFF_UHQA_CTL:
+ case WCD937X_HPH_REFBUFF_LP_CTL:
+ case WCD937X_HPH_L_DAC_CTL:
+ case WCD937X_HPH_R_DAC_CTL:
+ case WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL:
+ case WCD937X_HPH_SURGE_HPHLR_SURGE_EN:
+ case WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1:
+ case WCD937X_EAR_EAR_EN_REG:
+ case WCD937X_EAR_EAR_PA_CON:
+ case WCD937X_EAR_EAR_SP_CON:
+ case WCD937X_EAR_EAR_DAC_CON:
+ case WCD937X_EAR_EAR_CNP_FSM_CON:
+ case WCD937X_EAR_TEST_CTL:
+ case WCD937X_HPH_NEW_ANA_HPH2:
+ case WCD937X_HPH_NEW_ANA_HPH3:
+ case WCD937X_SLEEP_CTL:
+ case WCD937X_SLEEP_WATCHDOG_CTL:
+ case WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL:
+ case WCD937X_MBHC_NEW_CTL_1:
+ case WCD937X_MBHC_NEW_CTL_2:
+ case WCD937X_MBHC_NEW_PLUG_DETECT_CTL:
+ case WCD937X_MBHC_NEW_ZDET_ANA_CTL:
+ case WCD937X_MBHC_NEW_ZDET_RAMP_CTL:
+ case WCD937X_TX_NEW_TX_CH2_SEL:
+ case WCD937X_AUX_AUXPA:
+ case WCD937X_LDORXTX_MODE:
+ case WCD937X_LDORXTX_CONFIG:
+ case WCD937X_DIE_CRACK_DIE_CRK_DET_EN:
+ case WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL:
+ case WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L:
+ case WCD937X_HPH_NEW_INT_RDAC_VREF_CTL:
+ case WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL:
+ case WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R:
+ case WCD937X_HPH_NEW_INT_PA_MISC1:
+ case WCD937X_HPH_NEW_INT_PA_MISC2:
+ case WCD937X_HPH_NEW_INT_PA_RDAC_MISC:
+ case WCD937X_HPH_NEW_INT_HPH_TIMER1:
+ case WCD937X_HPH_NEW_INT_HPH_TIMER2:
+ case WCD937X_HPH_NEW_INT_HPH_TIMER3:
+ case WCD937X_HPH_NEW_INT_HPH_TIMER4:
+ case WCD937X_HPH_NEW_INT_PA_RDAC_MISC2:
+ case WCD937X_HPH_NEW_INT_PA_RDAC_MISC3:
+ case WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI:
+ case WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP:
+ case WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP:
+ case WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL:
+ case WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL:
+ case WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT:
+ case WCD937X_MBHC_NEW_INT_SPARE_2:
+ case WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON:
+ case WCD937X_EAR_INT_NEW_CNP_VCM_CON1:
+ case WCD937X_EAR_INT_NEW_CNP_VCM_CON2:
+ case WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS:
+ case WCD937X_AUX_INT_EN_REG:
+ case WCD937X_AUX_INT_PA_CTRL:
+ case WCD937X_AUX_INT_SP_CTRL:
+ case WCD937X_AUX_INT_DAC_CTRL:
+ case WCD937X_AUX_INT_CLK_CTRL:
+ case WCD937X_AUX_INT_TEST_CTRL:
+ case WCD937X_AUX_INT_MISC:
+ case WCD937X_LDORXTX_INT_BIAS:
+ case WCD937X_LDORXTX_INT_STB_LOADS_DTEST:
+ case WCD937X_LDORXTX_INT_TEST0:
+ case WCD937X_LDORXTX_INT_STARTUP_TIMER:
+ case WCD937X_LDORXTX_INT_TEST1:
+ case WCD937X_SLEEP_INT_WATCHDOG_CTL_1:
+ case WCD937X_SLEEP_INT_WATCHDOG_CTL_2:
+ case WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1:
+ case WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2:
+ case WCD937X_DIGITAL_CDC_RST_CTL:
+ case WCD937X_DIGITAL_TOP_CLK_CFG:
+ case WCD937X_DIGITAL_CDC_ANA_CLK_CTL:
+ case WCD937X_DIGITAL_CDC_DIG_CLK_CTL:
+ case WCD937X_DIGITAL_SWR_RST_EN:
+ case WCD937X_DIGITAL_CDC_PATH_MODE:
+ case WCD937X_DIGITAL_CDC_RX_RST:
+ case WCD937X_DIGITAL_CDC_RX0_CTL:
+ case WCD937X_DIGITAL_CDC_RX1_CTL:
+ case WCD937X_DIGITAL_CDC_RX2_CTL:
+ case WCD937X_DIGITAL_DEM_BYPASS_DATA0:
+ case WCD937X_DIGITAL_DEM_BYPASS_DATA1:
+ case WCD937X_DIGITAL_DEM_BYPASS_DATA2:
+ case WCD937X_DIGITAL_DEM_BYPASS_DATA3:
+ case WCD937X_DIGITAL_CDC_COMP_CTL_0:
+ case WCD937X_DIGITAL_CDC_RX_DELAY_CTL:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A1_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A1_1:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A2_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A2_1:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A3_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A3_1:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A4_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A4_1:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A5_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A5_1:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A6_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A7_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_C_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_C_1:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_C_2:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_C_3:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_R1:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_R2:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_R3:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_R4:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_R5:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_R6:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_R7:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A1_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A1_1:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A2_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A2_1:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A3_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A3_1:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A4_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A4_1:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A5_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A5_1:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A6_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A7_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_C_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_C_1:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_C_2:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_C_3:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_R1:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_R2:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_R3:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_R4:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_R5:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_R6:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_R7:
+ case WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0:
+ case WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1:
+ case WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0:
+ case WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1:
+ case WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2:
+ case WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0:
+ case WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1:
+ case WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2:
+ case WCD937X_DIGITAL_CDC_HPH_GAIN_CTL:
+ case WCD937X_DIGITAL_CDC_AUX_GAIN_CTL:
+ case WCD937X_DIGITAL_CDC_EAR_PATH_CTL:
+ case WCD937X_DIGITAL_CDC_SWR_CLH:
+ case WCD937X_DIGITAL_SWR_CLH_BYP:
+ case WCD937X_DIGITAL_CDC_TX0_CTL:
+ case WCD937X_DIGITAL_CDC_TX1_CTL:
+ case WCD937X_DIGITAL_CDC_TX2_CTL:
+ case WCD937X_DIGITAL_CDC_TX_RST:
+ case WCD937X_DIGITAL_CDC_REQ_CTL:
+ case WCD937X_DIGITAL_CDC_AMIC_CTL:
+ case WCD937X_DIGITAL_CDC_DMIC_CTL:
+ case WCD937X_DIGITAL_CDC_DMIC1_CTL:
+ case WCD937X_DIGITAL_CDC_DMIC2_CTL:
+ case WCD937X_DIGITAL_CDC_DMIC3_CTL:
+ case WCD937X_DIGITAL_EFUSE_CTL:
+ case WCD937X_DIGITAL_EFUSE_PRG_CTL:
+ case WCD937X_DIGITAL_EFUSE_TEST_CTL_0:
+ case WCD937X_DIGITAL_EFUSE_TEST_CTL_1:
+ case WCD937X_DIGITAL_PDM_WD_CTL0:
+ case WCD937X_DIGITAL_PDM_WD_CTL1:
+ case WCD937X_DIGITAL_PDM_WD_CTL2:
+ case WCD937X_DIGITAL_INTR_MODE:
+ case WCD937X_DIGITAL_INTR_MASK_0:
+ case WCD937X_DIGITAL_INTR_MASK_1:
+ case WCD937X_DIGITAL_INTR_MASK_2:
+ case WCD937X_DIGITAL_INTR_CLEAR_0:
+ case WCD937X_DIGITAL_INTR_CLEAR_1:
+ case WCD937X_DIGITAL_INTR_CLEAR_2:
+ case WCD937X_DIGITAL_INTR_LEVEL_0:
+ case WCD937X_DIGITAL_INTR_LEVEL_1:
+ case WCD937X_DIGITAL_INTR_LEVEL_2:
+ case WCD937X_DIGITAL_INTR_SET_0:
+ case WCD937X_DIGITAL_INTR_SET_1:
+ case WCD937X_DIGITAL_INTR_SET_2:
+ case WCD937X_DIGITAL_INTR_TEST_0:
+ case WCD937X_DIGITAL_INTR_TEST_1:
+ case WCD937X_DIGITAL_INTR_TEST_2:
+ case WCD937X_DIGITAL_CDC_CONN_RX0_CTL:
+ case WCD937X_DIGITAL_CDC_CONN_RX1_CTL:
+ case WCD937X_DIGITAL_CDC_CONN_RX2_CTL:
+ case WCD937X_DIGITAL_CDC_CONN_TX_CTL:
+ case WCD937X_DIGITAL_LOOP_BACK_MODE:
+ case WCD937X_DIGITAL_SWR_DAC_TEST:
+ case WCD937X_DIGITAL_SWR_HM_TEST_RX_0:
+ case WCD937X_DIGITAL_SWR_HM_TEST_TX_0:
+ case WCD937X_DIGITAL_SWR_HM_TEST_RX_1:
+ case WCD937X_DIGITAL_SWR_HM_TEST_TX_1:
+ case WCD937X_DIGITAL_SWR_HM_TEST:
+ case WCD937X_DIGITAL_PAD_CTL_PDM_RX0:
+ case WCD937X_DIGITAL_PAD_CTL_PDM_RX1:
+ case WCD937X_DIGITAL_PAD_CTL_PDM_TX0:
+ case WCD937X_DIGITAL_PAD_CTL_PDM_TX1:
+ case WCD937X_DIGITAL_PAD_INP_DIS_0:
+ case WCD937X_DIGITAL_PAD_INP_DIS_1:
+ case WCD937X_DIGITAL_DRIVE_STRENGTH_0:
+ case WCD937X_DIGITAL_DRIVE_STRENGTH_1:
+ case WCD937X_DIGITAL_DRIVE_STRENGTH_2:
+ case WCD937X_DIGITAL_RX_DATA_EDGE_CTL:
+ case WCD937X_DIGITAL_TX_DATA_EDGE_CTL:
+ case WCD937X_DIGITAL_GPIO_MODE:
+ case WCD937X_DIGITAL_PIN_CTL_OE:
+ case WCD937X_DIGITAL_PIN_CTL_DATA_0:
+ case WCD937X_DIGITAL_PIN_CTL_DATA_1:
+ case WCD937X_DIGITAL_PIN_STATUS_0:
+ case WCD937X_DIGITAL_PIN_STATUS_1:
+ case WCD937X_DIGITAL_DIG_DEBUG_CTL:
+ case WCD937X_DIGITAL_DIG_DEBUG_EN:
+ case WCD937X_DIGITAL_ANA_CSR_DBG_ADD:
+ case WCD937X_DIGITAL_ANA_CSR_DBG_CTL:
+ case WCD937X_DIGITAL_SSP_DBG:
+ case WCD937X_DIGITAL_MODE_STATUS_0:
+ case WCD937X_DIGITAL_MODE_STATUS_1:
+ case WCD937X_DIGITAL_SPARE_0:
+ case WCD937X_DIGITAL_SPARE_1:
+ case WCD937X_DIGITAL_SPARE_2:
+ return true;
+ }
+
+ return false;
+}
+
+static bool wcd937x_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WCD937X_ANA_MBHC_RESULT_1:
+ case WCD937X_ANA_MBHC_RESULT_2:
+ case WCD937X_ANA_MBHC_RESULT_3:
+ case WCD937X_MBHC_MOISTURE_DET_FSM_STATUS:
+ case WCD937X_TX_1_2_SAR2_ERR:
+ case WCD937X_TX_1_2_SAR1_ERR:
+ case WCD937X_TX_3_SPARE_MONO:
+ case WCD937X_TX_3_SAR1_ERR:
+ case WCD937X_HPH_L_STATUS:
+ case WCD937X_HPH_R_STATUS:
+ case WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS:
+ case WCD937X_EAR_STATUS_REG_1:
+ case WCD937X_EAR_STATUS_REG_2:
+ case WCD937X_MBHC_NEW_FSM_STATUS:
+ case WCD937X_MBHC_NEW_ADC_RESULT:
+ case WCD937X_DIE_CRACK_DIE_CRK_DET_OUT:
+ case WCD937X_AUX_INT_STATUS_REG:
+ case WCD937X_LDORXTX_INT_STATUS:
+ case WCD937X_DIGITAL_CHIP_ID0:
+ case WCD937X_DIGITAL_CHIP_ID1:
+ case WCD937X_DIGITAL_CHIP_ID2:
+ case WCD937X_DIGITAL_CHIP_ID3:
+ case WCD937X_DIGITAL_EFUSE_T_DATA_0:
+ case WCD937X_DIGITAL_EFUSE_T_DATA_1:
+ case WCD937X_DIGITAL_INTR_STATUS_0:
+ case WCD937X_DIGITAL_INTR_STATUS_1:
+ case WCD937X_DIGITAL_INTR_STATUS_2:
+ case WCD937X_DIGITAL_EFUSE_REG_0:
+ case WCD937X_DIGITAL_EFUSE_REG_1:
+ case WCD937X_DIGITAL_EFUSE_REG_2:
+ case WCD937X_DIGITAL_EFUSE_REG_3:
+ case WCD937X_DIGITAL_EFUSE_REG_4:
+ case WCD937X_DIGITAL_EFUSE_REG_5:
+ case WCD937X_DIGITAL_EFUSE_REG_6:
+ case WCD937X_DIGITAL_EFUSE_REG_7:
+ case WCD937X_DIGITAL_EFUSE_REG_8:
+ case WCD937X_DIGITAL_EFUSE_REG_9:
+ case WCD937X_DIGITAL_EFUSE_REG_10:
+ case WCD937X_DIGITAL_EFUSE_REG_11:
+ case WCD937X_DIGITAL_EFUSE_REG_12:
+ case WCD937X_DIGITAL_EFUSE_REG_13:
+ case WCD937X_DIGITAL_EFUSE_REG_14:
+ case WCD937X_DIGITAL_EFUSE_REG_15:
+ case WCD937X_DIGITAL_EFUSE_REG_16:
+ case WCD937X_DIGITAL_EFUSE_REG_17:
+ case WCD937X_DIGITAL_EFUSE_REG_18:
+ case WCD937X_DIGITAL_EFUSE_REG_19:
+ case WCD937X_DIGITAL_EFUSE_REG_20:
+ case WCD937X_DIGITAL_EFUSE_REG_21:
+ case WCD937X_DIGITAL_EFUSE_REG_22:
+ case WCD937X_DIGITAL_EFUSE_REG_23:
+ case WCD937X_DIGITAL_EFUSE_REG_24:
+ case WCD937X_DIGITAL_EFUSE_REG_25:
+ case WCD937X_DIGITAL_EFUSE_REG_26:
+ case WCD937X_DIGITAL_EFUSE_REG_27:
+ case WCD937X_DIGITAL_EFUSE_REG_28:
+ case WCD937X_DIGITAL_EFUSE_REG_29:
+ case WCD937X_DIGITAL_EFUSE_REG_30:
+ case WCD937X_DIGITAL_EFUSE_REG_31:
+ return true;
+ }
+
+ return wcd937x_rdwr_register(dev, reg);
+}
+
+static bool wcd937x_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WCD937X_ANA_MBHC_RESULT_1:
+ case WCD937X_ANA_MBHC_RESULT_2:
+ case WCD937X_ANA_MBHC_RESULT_3:
+ case WCD937X_MBHC_MOISTURE_DET_FSM_STATUS:
+ case WCD937X_TX_1_2_SAR1_ERR:
+ case WCD937X_TX_1_2_SAR2_ERR:
+ case WCD937X_TX_3_SAR1_ERR:
+ case WCD937X_HPH_L_STATUS:
+ case WCD937X_HPH_R_STATUS:
+ case WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS:
+ case WCD937X_EAR_STATUS_REG_1:
+ case WCD937X_EAR_STATUS_REG_2:
+ case WCD937X_MBHC_NEW_FSM_STATUS:
+ case WCD937X_MBHC_NEW_ADC_RESULT:
+ case WCD937X_DIE_CRACK_DIE_CRK_DET_OUT:
+ case WCD937X_DIGITAL_INTR_STATUS_0:
+ case WCD937X_DIGITAL_INTR_STATUS_1:
+ case WCD937X_DIGITAL_INTR_STATUS_2:
+ case WCD937X_DIGITAL_SWR_HM_TEST:
+ case WCD937X_DIGITAL_PIN_STATUS_0:
+ case WCD937X_DIGITAL_PIN_STATUS_1:
+ case WCD937X_DIGITAL_MODE_STATUS_0:
+ case WCD937X_DIGITAL_MODE_STATUS_1:
+ return true;
+ }
+ return false;
+}
+
+static const struct regmap_config wcd937x_regmap_config = {
+ .name = "wcd937x_csr",
+ .reg_bits = 32,
+ .val_bits = 8,
+ .cache_type = REGCACHE_MAPLE,
+ .reg_defaults = wcd937x_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wcd937x_defaults),
+ .max_register = WCD937X_MAX_REGISTER,
+ .readable_reg = wcd937x_readable_register,
+ .writeable_reg = wcd937x_rdwr_register,
+ .volatile_reg = wcd937x_volatile_register,
+};
+
+static const struct sdw_slave_ops wcd9370_slave_ops = {
+ .update_status = wcd9370_update_status,
+ .interrupt_callback = wcd9370_interrupt_callback,
+};
+
+static int wcd937x_sdw_component_bind(struct device *dev,
+ struct device *master, void *data)
+{
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+
+static void wcd937x_sdw_component_unbind(struct device *dev,
+ struct device *master, void *data)
+{
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_dont_use_autosuspend(dev);
+}
+
+static const struct component_ops wcd937x_sdw_component_ops = {
+ .bind = wcd937x_sdw_component_bind,
+ .unbind = wcd937x_sdw_component_unbind,
+};
+
+static int wcd9370_probe(struct sdw_slave *pdev,
+ const struct sdw_device_id *id)
+{
+ struct device *dev = &pdev->dev;
+ struct wcd937x_sdw_priv *wcd;
+ int ret;
+
+ wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL);
+ if (!wcd)
+ return -ENOMEM;
+
+ /* Port map index starts at 0, however the data port for this codec start at index 1 */
+ if (of_property_read_bool(dev->of_node, "qcom,tx-port-mapping")) {
+ wcd->is_tx = true;
+ ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping",
+ &pdev->m_port_map[1],
+ WCD937X_MAX_TX_SWR_PORTS);
+ } else {
+ ret = of_property_read_u32_array(dev->of_node, "qcom,rx-port-mapping",
+ &pdev->m_port_map[1],
+ WCD937X_MAX_SWR_PORTS);
+ }
+ if (ret < 0)
+ dev_info(dev, "Error getting static port mapping for %s (%d)\n",
+ wcd->is_tx ? "TX" : "RX", ret);
+
+ wcd->sdev = pdev;
+ dev_set_drvdata(dev, wcd);
+
+ pdev->prop.scp_int1_mask = SDW_SCP_INT1_IMPL_DEF |
+ SDW_SCP_INT1_BUS_CLASH |
+ SDW_SCP_INT1_PARITY;
+ pdev->prop.lane_control_support = true;
+ pdev->prop.simple_clk_stop_capable = true;
+ if (wcd->is_tx) {
+ pdev->prop.source_ports = GENMASK(WCD937X_MAX_TX_SWR_PORTS, 0);
+ pdev->prop.src_dpn_prop = wcd937x_dpn_prop;
+ wcd->ch_info = &wcd937x_sdw_tx_ch_info[0];
+ pdev->prop.wake_capable = true;
+
+ wcd->regmap = devm_regmap_init_sdw(pdev, &wcd937x_regmap_config);
+ if (IS_ERR(wcd->regmap))
+ return dev_err_probe(dev, PTR_ERR(wcd->regmap),
+ "Regmap init failed\n");
+
+ /* Start in cache-only until device is enumerated */
+ regcache_cache_only(wcd->regmap, true);
+ } else {
+ pdev->prop.sink_ports = GENMASK(WCD937X_MAX_SWR_PORTS, 0);
+ pdev->prop.sink_dpn_prop = wcd937x_dpn_prop;
+ wcd->ch_info = &wcd937x_sdw_rx_ch_info[0];
+ }
+
+
+ ret = component_add(dev, &wcd937x_sdw_component_ops);
+ if (ret)
+ return ret;
+
+ /* Set suspended until aggregate device is bind */
+ pm_runtime_set_suspended(dev);
+
+ return 0;
+}
+
+static int wcd9370_remove(struct sdw_slave *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ component_del(dev, &wcd937x_sdw_component_ops);
+
+ return 0;
+}
+
+static const struct sdw_device_id wcd9370_slave_id[] = {
+ SDW_SLAVE_ENTRY(0x0217, 0x10a, 0), /* WCD9370 RX/TX Device ID */
+ { },
+};
+MODULE_DEVICE_TABLE(sdw, wcd9370_slave_id);
+
+static int __maybe_unused wcd937x_sdw_runtime_suspend(struct device *dev)
+{
+ struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev);
+
+ if (wcd->regmap) {
+ regcache_cache_only(wcd->regmap, true);
+ regcache_mark_dirty(wcd->regmap);
+ }
+
+ return 0;
+}
+
+static int __maybe_unused wcd937x_sdw_runtime_resume(struct device *dev)
+{
+ struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev);
+
+ if (wcd->regmap) {
+ regcache_cache_only(wcd->regmap, false);
+ regcache_sync(wcd->regmap);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops wcd937x_sdw_pm_ops = {
+ SET_RUNTIME_PM_OPS(wcd937x_sdw_runtime_suspend, wcd937x_sdw_runtime_resume, NULL)
+};
+
+static struct sdw_driver wcd9370_codec_driver = {
+ .probe = wcd9370_probe,
+ .remove = wcd9370_remove,
+ .ops = &wcd9370_slave_ops,
+ .id_table = wcd9370_slave_id,
+ .driver = {
+ .name = "wcd9370-codec",
+ .pm = &wcd937x_sdw_pm_ops,
+ }
+};
+module_sdw_driver(wcd9370_codec_driver);
+
+MODULE_DESCRIPTION("WCD937X SDW codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c
new file mode 100644
index 000000000000..13926f4b0d9f
--- /dev/null
+++ b/sound/soc/codecs/wcd937x.c
@@ -0,0 +1,2971 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+
+#include <linux/component.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "wcd-clsh-v2.h"
+#include "wcd-mbhc-v2.h"
+#include "wcd937x.h"
+
+enum {
+ CHIPID_WCD9370 = 0,
+ CHIPID_WCD9375 = 5,
+};
+
+/* Z value defined in milliohm */
+#define WCD937X_ZDET_VAL_32 (32000)
+#define WCD937X_ZDET_VAL_400 (400000)
+#define WCD937X_ZDET_VAL_1200 (1200000)
+#define WCD937X_ZDET_VAL_100K (100000000)
+/* Z floating defined in ohms */
+#define WCD937X_ZDET_FLOATING_IMPEDANCE (0x0FFFFFFE)
+#define WCD937X_ZDET_NUM_MEASUREMENTS (900)
+#define WCD937X_MBHC_GET_C1(c) (((c) & 0xC000) >> 14)
+#define WCD937X_MBHC_GET_X1(x) ((x) & 0x3FFF)
+/* Z value compared in milliOhm */
+#define WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z) (((z) > 400000) || ((z) < 32000))
+#define WCD937X_MBHC_ZDET_CONST (86 * 16384)
+#define WCD937X_MBHC_MOISTURE_RREF R_24_KOHM
+#define WCD_MBHC_HS_V_MAX 1600
+#define EAR_RX_PATH_AUX 1
+#define WCD937X_MBHC_MAX_BUTTONS 8
+
+#define WCD937X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
+ SNDRV_PCM_RATE_384000)
+
+/* Fractional Rates */
+#define WCD937X_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800)
+
+#define WCD937X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+enum {
+ ALLOW_BUCK_DISABLE,
+ HPH_COMP_DELAY,
+ HPH_PA_DELAY,
+ AMIC2_BCS_ENABLE,
+};
+
+enum {
+ AIF1_PB = 0,
+ AIF1_CAP,
+ NUM_CODEC_DAIS,
+};
+
+struct wcd937x_priv {
+ struct sdw_slave *tx_sdw_dev;
+ struct wcd937x_sdw_priv *sdw_priv[NUM_CODEC_DAIS];
+ struct device *txdev;
+ struct device *rxdev;
+ struct device_node *rxnode;
+ struct device_node *txnode;
+ struct regmap *regmap;
+ /* micb setup lock */
+ struct mutex micb_lock;
+ /* mbhc module */
+ struct wcd_mbhc *wcd_mbhc;
+ struct wcd_mbhc_config mbhc_cfg;
+ struct wcd_mbhc_intr intr_ids;
+ struct wcd_clsh_ctrl *clsh_info;
+ struct irq_domain *virq;
+ struct regmap_irq_chip *wcd_regmap_irq_chip;
+ struct regmap_irq_chip_data *irq_chip;
+ struct regulator_bulk_data supplies[WCD937X_MAX_BULK_SUPPLY];
+ struct regulator *buck_supply;
+ struct snd_soc_jack *jack;
+ unsigned long status_mask;
+ s32 micb_ref[WCD937X_MAX_MICBIAS];
+ s32 pullup_ref[WCD937X_MAX_MICBIAS];
+ u32 hph_mode;
+ int ear_rx_path;
+ u32 micb1_mv;
+ u32 micb2_mv;
+ u32 micb3_mv;
+ int hphr_pdm_wd_int;
+ int hphl_pdm_wd_int;
+ int aux_pdm_wd_int;
+ bool comp1_enable;
+ bool comp2_enable;
+
+ struct gpio_desc *us_euro_gpio;
+ struct gpio_desc *reset_gpio;
+
+ atomic_t rx_clk_cnt;
+ atomic_t ana_clk_count;
+};
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+
+struct wcd937x_mbhc_zdet_param {
+ u16 ldo_ctl;
+ u16 noff;
+ u16 nshift;
+ u16 btn5;
+ u16 btn6;
+ u16 btn7;
+};
+
+static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+ WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD937X_ANA_MBHC_MECH, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD937X_ANA_MBHC_MECH, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD937X_ANA_MBHC_MECH, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_MIC_CLAMP_CTL, WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0x30),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_DETECTION_TYPE, WCD937X_ANA_MBHC_ELECT, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, WCD937X_ANA_MBHC_MECH, 0x04),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_PLUG_TYPE, WCD937X_ANA_MBHC_MECH, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_GND_PLUG_TYPE, WCD937X_ANA_MBHC_MECH, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_SW_HPH_LP_100K_TO_GND, WCD937X_ANA_MBHC_MECH, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_SCHMT_ISRC, WCD937X_ANA_MBHC_ELECT, 0x06),
+ WCD_MBHC_FIELD(WCD_MBHC_FSM_EN, WCD937X_ANA_MBHC_ELECT, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_INSREM_DBNC, WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_DBNC, WCD937X_MBHC_NEW_CTL_1, 0x03),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_VREF, WCD937X_MBHC_NEW_CTL_2, 0x03),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_COMP_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_IN2P_CLAMP_STATE, WCD937X_ANA_MBHC_RESULT_3, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_MIC_SCHMT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_SCHMT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_SCHMT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_OCP_FSM_EN, WCD937X_HPH_OCP_CTL, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x07),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_ISRC_CTL, WCD937X_ANA_MBHC_ELECT, 0x70),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0xFF),
+ WCD_MBHC_FIELD(WCD_MBHC_MICB_CTRL, WCD937X_ANA_MICB2, 0xC0),
+ WCD_MBHC_FIELD(WCD_MBHC_HPH_CNP_WG_TIME, WCD937X_HPH_CNP_WG_TIME, 0xFF),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_PA_EN, WCD937X_ANA_HPH, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_PA_EN, WCD937X_ANA_HPH, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPH_PA_EN, WCD937X_ANA_HPH, 0xC0),
+ WCD_MBHC_FIELD(WCD_MBHC_SWCH_LEVEL_REMOVE, WCD937X_ANA_MBHC_RESULT_3, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_ANC_DET_EN, WCD937X_MBHC_CTL_BCS, 0x02),
+ WCD_MBHC_FIELD(WCD_MBHC_FSM_STATUS, WCD937X_MBHC_NEW_FSM_STATUS, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_MUX_CTL, WCD937X_MBHC_NEW_CTL_2, 0x70),
+ WCD_MBHC_FIELD(WCD_MBHC_MOISTURE_STATUS, WCD937X_MBHC_NEW_FSM_STATUS, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_GND, WCD937X_HPH_PA_CTL2, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_GND, WCD937X_HPH_PA_CTL2, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_DET_EN, WCD937X_HPH_L_TEST, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_DET_EN, WCD937X_HPH_R_TEST, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_STATUS, WCD937X_DIGITAL_INTR_STATUS_0, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_STATUS, WCD937X_DIGITAL_INTR_STATUS_0, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_EN, WCD937X_MBHC_NEW_CTL_1, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_COMPLETE, WCD937X_MBHC_NEW_FSM_STATUS, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_TIMEOUT, WCD937X_MBHC_NEW_FSM_STATUS, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_RESULT, WCD937X_MBHC_NEW_ADC_RESULT, 0xFF),
+ WCD_MBHC_FIELD(WCD_MBHC_MICB2_VOUT, WCD937X_ANA_MICB2, 0x3F),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_MODE, WCD937X_MBHC_NEW_CTL_1, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_DETECTION_DONE, WCD937X_MBHC_NEW_CTL_1, 0x04),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_ISRC_EN, WCD937X_ANA_MBHC_ZDET, 0x02),
+};
+
+static const struct regmap_irq wcd937x_irqs[WCD937X_NUM_IRQS] = {
+ REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_BUTTON_PRESS_DET, 0, BIT(0)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, BIT(1)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_ELECT_INS_REM_DET, 0, BIT(2)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, BIT(3)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_SW_DET, 0, BIT(4)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_OCP_INT, 0, BIT(5)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_CNP_INT, 0, BIT(6)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_OCP_INT, 0, BIT(7)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_CNP_INT, 1, BIT(0)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_EAR_CNP_INT, 1, BIT(1)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_EAR_SCD_INT, 1, BIT(2)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_AUX_CNP_INT, 1, BIT(3)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_AUX_SCD_INT, 1, BIT(4)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_PDM_WD_INT, 1, BIT(5)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_PDM_WD_INT, 1, BIT(6)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_AUX_PDM_WD_INT, 1, BIT(7)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_LDORT_SCD_INT, 2, BIT(0)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_MOISTURE_INT, 2, BIT(1)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_SURGE_DET_INT, 2, BIT(2)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_SURGE_DET_INT, 2, BIT(3)),
+};
+
+static int wcd937x_handle_post_irq(void *data)
+{
+ struct wcd937x_priv *wcd937x;
+
+ if (data)
+ wcd937x = (struct wcd937x_priv *)data;
+ else
+ return IRQ_HANDLED;
+
+ regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_0, 0);
+ regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_1, 0);
+ regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_2, 0);
+
+ return IRQ_HANDLED;
+}
+
+static const u32 wcd937x_config_regs[] = {
+ WCD937X_DIGITAL_INTR_LEVEL_0,
+};
+
+static const struct regmap_irq_chip wcd937x_regmap_irq_chip = {
+ .name = "wcd937x",
+ .irqs = wcd937x_irqs,
+ .num_irqs = ARRAY_SIZE(wcd937x_irqs),
+ .num_regs = 3,
+ .status_base = WCD937X_DIGITAL_INTR_STATUS_0,
+ .mask_base = WCD937X_DIGITAL_INTR_MASK_0,
+ .ack_base = WCD937X_DIGITAL_INTR_CLEAR_0,
+ .use_ack = 1,
+ .clear_ack = 1,
+ .config_base = wcd937x_config_regs,
+ .num_config_bases = ARRAY_SIZE(wcd937x_config_regs),
+ .num_config_regs = 1,
+ .runtime_pm = true,
+ .handle_post_irq = wcd937x_handle_post_irq,
+ .irq_drv_data = NULL,
+};
+
+static void wcd937x_reset(struct wcd937x_priv *wcd937x)
+{
+ usleep_range(20, 30);
+
+ gpiod_set_value(wcd937x->reset_gpio, 1);
+
+ usleep_range(20, 30);
+}
+
+static void wcd937x_io_init(struct regmap *regmap)
+{
+ u32 val = 0, temp = 0, temp1 = 0;
+
+ regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_29, &val);
+
+ val = val & 0x0F;
+
+ regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_16, &temp);
+ regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_17, &temp1);
+
+ if (temp == 0x02 || temp1 > 0x09)
+ regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x0E, val);
+ else
+ regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x0e, 0x0e);
+
+ regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x80, 0x80);
+ usleep_range(1000, 1010);
+
+ regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x40, 0x40);
+ usleep_range(1000, 1010);
+
+ regmap_update_bits(regmap, WCD937X_LDORXTX_CONFIG, BIT(4), 0x00);
+ regmap_update_bits(regmap, WCD937X_BIAS_VBG_FINE_ADJ, 0xf0, BIT(7));
+ regmap_update_bits(regmap, WCD937X_ANA_BIAS, BIT(7), BIT(7));
+ regmap_update_bits(regmap, WCD937X_ANA_BIAS, BIT(6), BIT(6));
+ usleep_range(10000, 10010);
+
+ regmap_update_bits(regmap, WCD937X_ANA_BIAS, BIT(6), 0x00);
+ regmap_update_bits(regmap, WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0xff, 0xd9);
+ regmap_update_bits(regmap, WCD937X_MICB1_TEST_CTL_1, 0xff, 0xfa);
+ regmap_update_bits(regmap, WCD937X_MICB2_TEST_CTL_1, 0xff, 0xfa);
+ regmap_update_bits(regmap, WCD937X_MICB3_TEST_CTL_1, 0xff, 0xfa);
+
+ regmap_update_bits(regmap, WCD937X_MICB1_TEST_CTL_2, 0x38, 0x00);
+ regmap_update_bits(regmap, WCD937X_MICB2_TEST_CTL_2, 0x38, 0x00);
+ regmap_update_bits(regmap, WCD937X_MICB3_TEST_CTL_2, 0x38, 0x00);
+
+ /* Set Bandgap Fine Adjustment to +5mV for Tanggu SMIC part */
+ regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_16, &val);
+ if (val == 0x01) {
+ regmap_update_bits(regmap, WCD937X_BIAS_VBG_FINE_ADJ, 0xF0, 0xB0);
+ } else if (val == 0x02) {
+ regmap_update_bits(regmap, WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x1F, 0x04);
+ regmap_update_bits(regmap, WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x1F, 0x04);
+ regmap_update_bits(regmap, WCD937X_BIAS_VBG_FINE_ADJ, 0xF0, 0xB0);
+ regmap_update_bits(regmap, WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL, 0xF0, 0x50);
+ }
+}
+
+static int wcd937x_rx_clk_enable(struct snd_soc_component *component)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ if (atomic_read(&wcd937x->rx_clk_cnt))
+ return 0;
+
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(3), BIT(3));
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(0), BIT(0));
+ snd_soc_component_update_bits(component, WCD937X_ANA_RX_SUPPLIES, BIT(0), BIT(0));
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_RX0_CTL, BIT(6), 0x00);
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_RX1_CTL, BIT(6), 0x00);
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_RX2_CTL, BIT(6), 0x00);
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(1), BIT(1));
+
+ atomic_inc(&wcd937x->rx_clk_cnt);
+
+ return 0;
+}
+
+static int wcd937x_rx_clk_disable(struct snd_soc_component *component)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ if (!atomic_read(&wcd937x->rx_clk_cnt)) {
+ dev_err(component->dev, "clk already disabled\n");
+ return 0;
+ }
+
+ atomic_dec(&wcd937x->rx_clk_cnt);
+
+ snd_soc_component_update_bits(component, WCD937X_ANA_RX_SUPPLIES, BIT(0), 0x00);
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(1), 0x00);
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(0), 0x00);
+
+ return 0;
+}
+
+static int wcd937x_codec_hphl_dac_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd937x_rx_clk_enable(component);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(0), BIT(0));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_HPH_GAIN_CTL,
+ BIT(2), BIT(2));
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_RDAC_CLK_CTL1,
+ BIT(7), 0x00);
+ set_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ 0x0f, BIT(1));
+ else if (hph_mode == CLS_H_LOHIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ 0x0f, 0x06);
+
+ if (wcd937x->comp1_enable) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(1), BIT(1));
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_L_EN,
+ BIT(5), 0x00);
+
+ if (wcd937x->comp2_enable) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(0), BIT(0));
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_R_EN, BIT(5), 0x00);
+ }
+
+ if (test_bit(HPH_COMP_DELAY, &wcd937x->status_mask)) {
+ usleep_range(5000, 5110);
+ clear_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+ }
+ } else {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(1), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_L_EN,
+ BIT(5), BIT(5));
+ }
+
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_HPH_TIMER1,
+ BIT(1), 0x00);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ 0x0f, BIT(0));
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_hphr_dac_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd937x_rx_clk_enable(component);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(1), BIT(1));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_HPH_GAIN_CTL, BIT(3), BIT(3));
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_RDAC_CLK_CTL1, BIT(7), 0x00);
+ set_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+ 0x0f, BIT(1));
+ else if (hph_mode == CLS_H_LOHIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+ 0x0f, 0x06);
+ if (wcd937x->comp2_enable) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(0), BIT(0));
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_R_EN, BIT(5), 0x00);
+ if (wcd937x->comp1_enable) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(1), BIT(1));
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_L_EN,
+ BIT(5), 0x00);
+ }
+
+ if (test_bit(HPH_COMP_DELAY, &wcd937x->status_mask)) {
+ usleep_range(5000, 5110);
+ clear_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+ }
+ } else {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(0), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_R_EN,
+ BIT(5), BIT(5));
+ }
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_HPH_TIMER1,
+ BIT(1), 0x00);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+ 0x0f, BIT(0));
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_ear_dac_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd937x_rx_clk_enable(component);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_HPH_GAIN_CTL,
+ BIT(2), BIT(2));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(0), BIT(0));
+
+ if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ 0x0f, BIT(1));
+ else if (hph_mode == CLS_H_LOHIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ 0x0f, 0x06);
+ if (wcd937x->comp1_enable)
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(1), BIT(1));
+ usleep_range(5000, 5010);
+
+ snd_soc_component_update_bits(component, WCD937X_FLYBACK_EN, BIT(2), 0x00);
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_EAR,
+ hph_mode);
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_LOHIFI ||
+ hph_mode == CLS_H_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ 0x0f, BIT(0));
+ if (wcd937x->comp1_enable)
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(1), 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_aux_dac_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd937x_rx_clk_enable(component);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+ BIT(2), BIT(2));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(2), BIT(2));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_AUX_GAIN_CTL,
+ BIT(0), BIT(0));
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_AUX,
+ hph_mode);
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+ BIT(2), 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_hphr_pa(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_HPHR,
+ hph_mode);
+ snd_soc_component_update_bits(component, WCD937X_ANA_HPH,
+ BIT(4), BIT(4));
+ usleep_range(100, 110);
+ set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL1,
+ 0x07, 0x03);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+ if (wcd937x->comp2_enable)
+ usleep_range(7000, 7100);
+ else
+ usleep_range(20000, 20100);
+ clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ }
+
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_HPH_TIMER1,
+ BIT(1), BIT(1));
+ if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(1), BIT(1));
+ enable_irq(wcd937x->hphr_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ disable_irq_nosync(wcd937x->hphr_pdm_wd_int);
+ set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_PRE_HPHR_PA_OFF);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+ if (wcd937x->comp2_enable)
+ usleep_range(7000, 7100);
+ else
+ usleep_range(20000, 20100);
+ clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ }
+
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_POST_HPHR_PA_OFF);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL1, 0x07, 0x00);
+ snd_soc_component_update_bits(component, WCD937X_ANA_HPH,
+ BIT(4), 0x00);
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_HPHR,
+ hph_mode);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_hphl_pa(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_HPHL,
+ hph_mode);
+ snd_soc_component_update_bits(component, WCD937X_ANA_HPH,
+ BIT(5), BIT(5));
+ usleep_range(100, 110);
+ set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL0, 0x07, 0x03);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+ if (!wcd937x->comp1_enable)
+ usleep_range(20000, 20100);
+ else
+ usleep_range(7000, 7100);
+ clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ }
+
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_HPH_TIMER1,
+ BIT(1), BIT(1));
+ if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(1), BIT(1));
+ enable_irq(wcd937x->hphl_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ disable_irq_nosync(wcd937x->hphl_pdm_wd_int);
+ set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_PRE_HPHL_PA_OFF);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+ if (!wcd937x->comp1_enable)
+ usleep_range(20000, 20100);
+ else
+ usleep_range(7000, 7100);
+ clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ }
+
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_POST_HPHL_PA_OFF);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL0, 0x07, 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_HPH, BIT(5), 0x00);
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_HPHL,
+ hph_mode);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_aux_pa(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL2,
+ BIT(0), BIT(0));
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(1000, 1010);
+ if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(1), BIT(1));
+ enable_irq(wcd937x->aux_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ disable_irq_nosync(wcd937x->aux_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ usleep_range(2000, 2010);
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_AUX,
+ hph_mode);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL2,
+ BIT(0), 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_ear_pa(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enable watchdog interrupt for HPHL or AUX depending on mux value */
+ wcd937x->ear_rx_path = snd_soc_component_read(component,
+ WCD937X_DIGITAL_CDC_EAR_PATH_CTL);
+
+ if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL2,
+ BIT(0), BIT(0));
+ else
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL0,
+ 0x07, 0x03);
+ if (!wcd937x->comp1_enable)
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_EAR_COMPANDER_CTL,
+ BIT(7), BIT(7));
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(6000, 6010);
+ if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(1), BIT(1));
+
+ if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+ enable_irq(wcd937x->aux_pdm_wd_int);
+ else
+ enable_irq(wcd937x->hphl_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+ disable_irq_nosync(wcd937x->aux_pdm_wd_int);
+ else
+ disable_irq_nosync(wcd937x->hphl_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (!wcd937x->comp1_enable)
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_EAR_COMPANDER_CTL,
+ BIT(7), 0x00);
+ usleep_range(7000, 7010);
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_EAR,
+ hph_mode);
+ snd_soc_component_update_bits(component, WCD937X_FLYBACK_EN,
+ BIT(2), BIT(2));
+
+ if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL2,
+ BIT(0), 0x00);
+ else
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL0,
+ 0x07, 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_enable_rx1(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ if (event == SND_SOC_DAPM_POST_PMD) {
+ wcd937x_rx_clk_disable(component);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(0), 0x00);
+ }
+
+ return 0;
+}
+
+static int wcd937x_enable_rx2(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ if (event == SND_SOC_DAPM_POST_PMD) {
+ wcd937x_rx_clk_disable(component);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(1), 0x00);
+ }
+
+ return 0;
+}
+
+static int wcd937x_enable_rx3(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ if (event == SND_SOC_DAPM_POST_PMD) {
+ usleep_range(6000, 6010);
+ wcd937x_rx_clk_disable(component);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(2), 0x00);
+ }
+
+ return 0;
+}
+
+static int wcd937x_get_micb_vout_ctl_val(u32 micb_mv)
+{
+ if (micb_mv < 1000 || micb_mv > 2850) {
+ pr_err("Unsupported micbias voltage (%u mV)\n", micb_mv);
+ return -EINVAL;
+ }
+
+ return (micb_mv - 1000) / 50;
+}
+
+static int wcd937x_tx_swr_ctrl(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ bool use_amic3 = snd_soc_component_read(component, WCD937X_TX_NEW_TX_CH2_SEL) & BIT(7);
+
+ /* Enable BCS for Headset mic */
+ if (event == SND_SOC_DAPM_PRE_PMU && strnstr(w->name, "ADC", sizeof("ADC")))
+ if (w->shift == 1 && !use_amic3)
+ set_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask);
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_adc(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ atomic_inc(&wcd937x->ana_clk_count);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(7), BIT(7));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(3), BIT(3));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(4), BIT(4));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (w->shift == 1 && test_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask))
+ clear_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask);
+
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(3), 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_enable_req(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_REQ_CTL, BIT(1), BIT(1));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_REQ_CTL, BIT(0), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH2, BIT(6), BIT(6));
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH3_HPF, BIT(6), BIT(6));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x70, 0x70);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH1, BIT(7), BIT(7));
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH2, BIT(6), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH2, BIT(7), BIT(7));
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH3, BIT(7), BIT(7));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH1, BIT(7), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH2, BIT(7), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH3, BIT(7), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(4), 0x00);
+
+ atomic_dec(&wcd937x->ana_clk_count);
+ if (atomic_read(&wcd937x->ana_clk_count) <= 0) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+ BIT(4), 0x00);
+ atomic_set(&wcd937x->ana_clk_count, 0);
+ }
+
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(7), 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ u16 dmic_clk_reg;
+
+ switch (w->shift) {
+ case 0:
+ case 1:
+ dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC1_CTL;
+ break;
+ case 2:
+ case 3:
+ dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC2_CTL;
+ break;
+ case 4:
+ case 5:
+ dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC3_CTL;
+ break;
+ default:
+ dev_err(component->dev, "Invalid DMIC Selection\n");
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(7), BIT(7));
+ snd_soc_component_update_bits(component,
+ dmic_clk_reg, 0x07, BIT(1));
+ snd_soc_component_update_bits(component,
+ dmic_clk_reg, BIT(3), BIT(3));
+ snd_soc_component_update_bits(component,
+ dmic_clk_reg, 0x70, BIT(5));
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_micbias_control(struct snd_soc_component *component,
+ int micb_num, int req, bool is_dapm)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int micb_index = micb_num - 1;
+ u16 micb_reg;
+
+ if (micb_index < 0 || (micb_index > WCD937X_MAX_MICBIAS - 1)) {
+ dev_err(component->dev, "Invalid micbias index, micb_ind:%d\n", micb_index);
+ return -EINVAL;
+ }
+ switch (micb_num) {
+ case MIC_BIAS_1:
+ micb_reg = WCD937X_ANA_MICB1;
+ break;
+ case MIC_BIAS_2:
+ micb_reg = WCD937X_ANA_MICB2;
+ break;
+ case MIC_BIAS_3:
+ micb_reg = WCD937X_ANA_MICB3;
+ break;
+ default:
+ dev_err(component->dev, "Invalid micbias number: %d\n", micb_num);
+ return -EINVAL;
+ }
+
+ mutex_lock(&wcd937x->micb_lock);
+ switch (req) {
+ case MICB_PULLUP_ENABLE:
+ wcd937x->pullup_ref[micb_index]++;
+ if (wcd937x->pullup_ref[micb_index] == 1 &&
+ wcd937x->micb_ref[micb_index] == 0)
+ snd_soc_component_update_bits(component, micb_reg,
+ 0xc0, BIT(7));
+ break;
+ case MICB_PULLUP_DISABLE:
+ if (wcd937x->pullup_ref[micb_index] > 0)
+ wcd937x->pullup_ref[micb_index]++;
+ if (wcd937x->pullup_ref[micb_index] == 0 &&
+ wcd937x->micb_ref[micb_index] == 0)
+ snd_soc_component_update_bits(component, micb_reg,
+ 0xc0, 0x00);
+ break;
+ case MICB_ENABLE:
+ wcd937x->micb_ref[micb_index]++;
+ atomic_inc(&wcd937x->ana_clk_count);
+ if (wcd937x->micb_ref[micb_index] == 1) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ 0xf0, 0xf0);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+ BIT(4), BIT(4));
+ snd_soc_component_update_bits(component,
+ WCD937X_MICB1_TEST_CTL_2,
+ BIT(0), BIT(0));
+ snd_soc_component_update_bits(component,
+ WCD937X_MICB2_TEST_CTL_2,
+ BIT(0), BIT(0));
+ snd_soc_component_update_bits(component,
+ WCD937X_MICB3_TEST_CTL_2,
+ BIT(0), BIT(0));
+ snd_soc_component_update_bits(component,
+ micb_reg, 0xc0, BIT(6));
+
+ if (micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+ WCD_EVENT_POST_MICBIAS_2_ON);
+
+ if (micb_num == MIC_BIAS_2 && is_dapm)
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+ WCD_EVENT_POST_DAPM_MICBIAS_2_ON);
+ }
+ break;
+ case MICB_DISABLE:
+ atomic_dec(&wcd937x->ana_clk_count);
+ if (wcd937x->micb_ref[micb_index] > 0)
+ wcd937x->micb_ref[micb_index]--;
+ if (wcd937x->micb_ref[micb_index] == 0 &&
+ wcd937x->pullup_ref[micb_index] > 0)
+ snd_soc_component_update_bits(component, micb_reg,
+ 0xc0, BIT(7));
+ else if (wcd937x->micb_ref[micb_index] == 0 &&
+ wcd937x->pullup_ref[micb_index] == 0) {
+ if (micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+ WCD_EVENT_PRE_MICBIAS_2_OFF);
+
+ snd_soc_component_update_bits(component, micb_reg,
+ 0xc0, 0x00);
+ if (micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+ WCD_EVENT_POST_MICBIAS_2_OFF);
+ }
+
+ if (is_dapm && micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+ WCD_EVENT_POST_DAPM_MICBIAS_2_OFF);
+ if (atomic_read(&wcd937x->ana_clk_count) <= 0) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+ BIT(4), 0x00);
+ atomic_set(&wcd937x->ana_clk_count, 0);
+ }
+ break;
+ }
+ mutex_unlock(&wcd937x->micb_lock);
+
+ return 0;
+}
+
+static int __wcd937x_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ int micb_num = w->shift;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd937x_micbias_control(component, micb_num,
+ MICB_ENABLE, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(1000, 1100);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd937x_micbias_control(component, micb_num,
+ MICB_DISABLE, true);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ return __wcd937x_codec_enable_micbias(w, event);
+}
+
+static int __wcd937x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ int micb_num = w->shift;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd937x_micbias_control(component, micb_num, MICB_PULLUP_ENABLE, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(1000, 1100);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd937x_micbias_control(component, micb_num, MICB_PULLUP_DISABLE, true);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ return __wcd937x_codec_enable_micbias_pullup(w, event);
+}
+
+static int wcd937x_connect_port(struct wcd937x_sdw_priv *wcd, u8 port_idx, u8 ch_id, bool enable)
+{
+ struct sdw_port_config *port_config = &wcd->port_config[port_idx - 1];
+ const struct wcd937x_sdw_ch_info *ch_info = &wcd->ch_info[ch_id];
+ u8 port_num = ch_info->port_num;
+ u8 ch_mask = ch_info->ch_mask;
+
+ port_config->num = port_num;
+
+ if (enable)
+ port_config->ch_mask |= ch_mask;
+ else
+ port_config->ch_mask &= ~ch_mask;
+
+ return 0;
+}
+
+static int wcd937x_rx_hph_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wcd937x->hph_mode;
+ return 0;
+}
+
+static int wcd937x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ u32 mode_val;
+
+ mode_val = ucontrol->value.enumerated.item[0];
+
+ if (!mode_val)
+ mode_val = CLS_AB;
+
+ if (mode_val == wcd937x->hph_mode)
+ return 0;
+
+ switch (mode_val) {
+ case CLS_H_NORMAL:
+ case CLS_H_HIFI:
+ case CLS_H_LP:
+ case CLS_AB:
+ case CLS_H_LOHIFI:
+ case CLS_H_ULP:
+ case CLS_AB_LP:
+ case CLS_AB_HIFI:
+ wcd937x->hph_mode = mode_val;
+ return 1;
+ }
+
+ dev_dbg(component->dev, "%s: Invalid HPH Mode\n", __func__);
+ return -EINVAL;
+}
+
+static int wcd937x_get_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc;
+ bool hphr;
+
+ mc = (struct soc_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+
+ ucontrol->value.integer.value[0] = hphr ? wcd937x->comp2_enable :
+ wcd937x->comp1_enable;
+ return 0;
+}
+
+static int wcd937x_set_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[AIF1_PB];
+ int value = ucontrol->value.integer.value[0];
+ struct soc_mixer_control *mc;
+ int portidx;
+ bool hphr;
+
+ mc = (struct soc_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+
+ if (hphr) {
+ if (value == wcd937x->comp2_enable)
+ return 0;
+
+ wcd937x->comp2_enable = value;
+ } else {
+ if (value == wcd937x->comp1_enable)
+ return 0;
+
+ wcd937x->comp1_enable = value;
+ }
+
+ portidx = wcd->ch_info[mc->reg].port_num;
+
+ if (value)
+ wcd937x_connect_port(wcd, portidx, mc->reg, true);
+ else
+ wcd937x_connect_port(wcd, portidx, mc->reg, false);
+
+ return 1;
+}
+
+static int wcd937x_get_swr_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(comp);
+ struct wcd937x_sdw_priv *wcd;
+ int dai_id = mixer->shift;
+ int ch_idx = mixer->reg;
+ int portidx;
+
+ wcd = wcd937x->sdw_priv[dai_id];
+ portidx = wcd->ch_info[ch_idx].port_num;
+
+ ucontrol->value.integer.value[0] = wcd->port_enable[portidx];
+
+ return 0;
+}
+
+static int wcd937x_set_swr_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(comp);
+ struct wcd937x_sdw_priv *wcd;
+ int dai_id = mixer->shift;
+ int ch_idx = mixer->reg;
+ int portidx;
+ bool enable;
+
+ wcd = wcd937x->sdw_priv[dai_id];
+
+ portidx = wcd->ch_info[ch_idx].port_num;
+
+ enable = ucontrol->value.integer.value[0];
+
+ if (enable == wcd->port_enable[portidx]) {
+ wcd937x_connect_port(wcd, portidx, ch_idx, enable);
+ return 0;
+ }
+
+ wcd->port_enable[portidx] = enable;
+ wcd937x_connect_port(wcd, portidx, ch_idx, enable);
+
+ return 1;
+}
+
+static const char * const rx_hph_mode_mux_text[] = {
+ "CLS_H_NORMAL", "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB",
+ "CLS_H_LOHIFI", "CLS_H_ULP", "CLS_AB_LP", "CLS_AB_HIFI",
+};
+
+static const struct soc_enum rx_hph_mode_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), rx_hph_mode_mux_text);
+
+/* MBHC related */
+static void wcd937x_mbhc_clk_setup(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_1,
+ WCD937X_MBHC_CTL_RCO_EN_MASK, enable);
+}
+
+static void wcd937x_mbhc_mbhc_bias_control(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component, WCD937X_ANA_MBHC_ELECT,
+ WCD937X_ANA_MBHC_BIAS_EN, enable);
+}
+
+static void wcd937x_mbhc_program_btn_thr(struct snd_soc_component *component,
+ int *btn_low, int *btn_high,
+ int num_btn, bool is_micbias)
+{
+ int i, vth;
+
+ if (num_btn > WCD_MBHC_DEF_BUTTONS) {
+ dev_err(component->dev, "%s: invalid number of buttons: %d\n",
+ __func__, num_btn);
+ return;
+ }
+
+ for (i = 0; i < num_btn; i++) {
+ vth = ((btn_high[i] * 2) / 25) & 0x3F;
+ snd_soc_component_write_field(component, WCD937X_ANA_MBHC_BTN0 + i,
+ WCD937X_MBHC_BTN_VTH_MASK, vth);
+ }
+}
+
+static bool wcd937x_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num)
+{
+ u8 val;
+
+ if (micb_num == MIC_BIAS_2) {
+ val = snd_soc_component_read_field(component,
+ WCD937X_ANA_MICB2,
+ WCD937X_ANA_MICB2_ENABLE_MASK);
+ if (val == WCD937X_MICB_ENABLE)
+ return true;
+ }
+ return false;
+}
+
+static void wcd937x_mbhc_hph_l_pull_up_control(struct snd_soc_component *component,
+ int pull_up_cur)
+{
+ /* Default pull up current to 2uA */
+ if (pull_up_cur > HS_PULLUP_I_OFF || pull_up_cur < HS_PULLUP_I_3P0_UA)
+ pull_up_cur = HS_PULLUP_I_2P0_UA;
+
+ snd_soc_component_write_field(component,
+ WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT,
+ WCD937X_HSDET_PULLUP_C_MASK, pull_up_cur);
+}
+
+static int wcd937x_mbhc_request_micbias(struct snd_soc_component *component,
+ int micb_num, int req)
+{
+ return wcd937x_micbias_control(component, micb_num, req, false);
+}
+
+static void wcd937x_mbhc_micb_ramp_control(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP,
+ WCD937X_RAMP_SHIFT_CTRL_MASK, 0x0C);
+ snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP,
+ WCD937X_RAMP_EN_MASK, 1);
+ } else {
+ snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP,
+ WCD937X_RAMP_EN_MASK, 0);
+ snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP,
+ WCD937X_RAMP_SHIFT_CTRL_MASK, 0);
+ }
+}
+
+static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
+ int req_volt, int micb_num)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0;
+
+ switch (micb_num) {
+ case MIC_BIAS_1:
+ micb_reg = WCD937X_ANA_MICB1;
+ break;
+ case MIC_BIAS_2:
+ micb_reg = WCD937X_ANA_MICB2;
+ break;
+ case MIC_BIAS_3:
+ micb_reg = WCD937X_ANA_MICB3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ mutex_lock(&wcd937x->micb_lock);
+ /*
+ * If requested micbias voltage is same as current micbias
+ * voltage, then just return. Otherwise, adjust voltage as
+ * per requested value. If micbias is already enabled, then
+ * to avoid slow micbias ramp-up or down enable pull-up
+ * momentarily, change the micbias value and then re-enable
+ * micbias.
+ */
+ micb_en = snd_soc_component_read_field(component, micb_reg,
+ WCD937X_MICB_EN_MASK);
+ cur_vout_ctl = snd_soc_component_read_field(component, micb_reg,
+ WCD937X_MICB_VOUT_MASK);
+
+ req_vout_ctl = wcd937x_get_micb_vout_ctl_val(req_volt);
+ if (req_vout_ctl < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (cur_vout_ctl == req_vout_ctl) {
+ ret = 0;
+ goto exit;
+ }
+
+ if (micb_en == WCD937X_MICB_ENABLE)
+ snd_soc_component_write_field(component, micb_reg,
+ WCD937X_MICB_EN_MASK,
+ WCD937X_MICB_PULL_UP);
+
+ snd_soc_component_write_field(component, micb_reg,
+ WCD937X_MICB_VOUT_MASK,
+ req_vout_ctl);
+
+ if (micb_en == WCD937X_MICB_ENABLE) {
+ snd_soc_component_write_field(component, micb_reg,
+ WCD937X_MICB_EN_MASK,
+ WCD937X_MICB_ENABLE);
+ /*
+ * Add 2ms delay as per HW requirement after enabling
+ * micbias
+ */
+ usleep_range(2000, 2100);
+ }
+exit:
+ mutex_unlock(&wcd937x->micb_lock);
+ return ret;
+}
+
+static int wcd937x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component,
+ int micb_num, bool req_en)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int micb_mv;
+
+ if (micb_num != MIC_BIAS_2)
+ return -EINVAL;
+ /*
+ * If device tree micbias level is already above the minimum
+ * voltage needed to detect threshold microphone, then do
+ * not change the micbias, just return.
+ */
+ if (wcd937x->micb2_mv >= WCD_MBHC_THR_HS_MICB_MV)
+ return 0;
+
+ micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd937x->micb2_mv;
+
+ return wcd937x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2);
+}
+
+static void wcd937x_mbhc_get_result_params(struct snd_soc_component *component,
+ s16 *d1_a, u16 noff,
+ int32_t *zdet)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int i;
+ int val, val1;
+ s16 c1;
+ s32 x1, d1;
+ s32 denom;
+ static const int minCode_param[] = {
+ 3277, 1639, 820, 410, 205, 103, 52, 26
+ };
+
+ regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MBHC_ZDET, 0x20, 0x20);
+ for (i = 0; i < WCD937X_ZDET_NUM_MEASUREMENTS; i++) {
+ regmap_read(wcd937x->regmap, WCD937X_ANA_MBHC_RESULT_2, &val);
+ if (val & 0x80)
+ break;
+ }
+ val = val << 0x8;
+ regmap_read(wcd937x->regmap, WCD937X_ANA_MBHC_RESULT_1, &val1);
+ val |= val1;
+ regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MBHC_ZDET, 0x20, 0x00);
+ x1 = WCD937X_MBHC_GET_X1(val);
+ c1 = WCD937X_MBHC_GET_C1(val);
+ /* If ramp is not complete, give additional 5ms */
+ if (c1 < 2 && x1)
+ usleep_range(5000, 5050);
+
+ if (!c1 || !x1) {
+ dev_err(component->dev, "Impedance detect ramp error, c1=%d, x1=0x%x\n",
+ c1, x1);
+ goto ramp_down;
+ }
+ d1 = d1_a[c1];
+ denom = (x1 * d1) - (1 << (14 - noff));
+ if (denom > 0)
+ *zdet = (WCD937X_MBHC_ZDET_CONST * 1000) / denom;
+ else if (x1 < minCode_param[noff])
+ *zdet = WCD937X_ZDET_FLOATING_IMPEDANCE;
+
+ dev_err(component->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d (milliohm)\n",
+ __func__, d1, c1, x1, *zdet);
+ramp_down:
+ i = 0;
+ while (x1) {
+ regmap_read(wcd937x->regmap,
+ WCD937X_ANA_MBHC_RESULT_1, &val);
+ regmap_read(wcd937x->regmap,
+ WCD937X_ANA_MBHC_RESULT_2, &val1);
+ val = val << 0x08;
+ val |= val1;
+ x1 = WCD937X_MBHC_GET_X1(val);
+ i++;
+ if (i == WCD937X_ZDET_NUM_MEASUREMENTS)
+ break;
+ }
+}
+
+static void wcd937x_mbhc_zdet_ramp(struct snd_soc_component *component,
+ struct wcd937x_mbhc_zdet_param *zdet_param,
+ s32 *zl, s32 *zr, s16 *d1_a)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ s32 zdet = 0;
+
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL,
+ WCD937X_ZDET_MAXV_CTL_MASK, zdet_param->ldo_ctl);
+ snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN5,
+ WCD937X_VTH_MASK, zdet_param->btn5);
+ snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN6,
+ WCD937X_VTH_MASK, zdet_param->btn6);
+ snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN7,
+ WCD937X_VTH_MASK, zdet_param->btn7);
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL,
+ WCD937X_ZDET_RANGE_CTL_MASK, zdet_param->noff);
+ snd_soc_component_update_bits(component, WCD937X_MBHC_NEW_ZDET_RAMP_CTL,
+ 0x0F, zdet_param->nshift);
+
+ if (!zl)
+ goto z_right;
+ /* Start impedance measurement for HPH_L */
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_ZDET, 0x80, 0x80);
+ wcd937x_mbhc_get_result_params(component, d1_a, zdet_param->noff, &zdet);
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_ZDET, 0x80, 0x00);
+
+ *zl = zdet;
+
+z_right:
+ if (!zr)
+ return;
+ /* Start impedance measurement for HPH_R */
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_ZDET, 0x40, 0x40);
+ wcd937x_mbhc_get_result_params(component, d1_a, zdet_param->noff, &zdet);
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_ZDET, 0x40, 0x00);
+
+ *zr = zdet;
+}
+
+static void wcd937x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component,
+ s32 *z_val, int flag_l_r)
+{
+ s16 q1;
+ int q1_cal;
+
+ if (*z_val < (WCD937X_ZDET_VAL_400 / 1000))
+ q1 = snd_soc_component_read(component,
+ WCD937X_DIGITAL_EFUSE_REG_23 + (2 * flag_l_r));
+ else
+ q1 = snd_soc_component_read(component,
+ WCD937X_DIGITAL_EFUSE_REG_24 + (2 * flag_l_r));
+ if (q1 & 0x80)
+ q1_cal = (10000 - ((q1 & 0x7F) * 25));
+ else
+ q1_cal = (10000 + (q1 * 25));
+ if (q1_cal > 0)
+ *z_val = ((*z_val) * 10000) / q1_cal;
+}
+
+static void wcd937x_wcd_mbhc_calc_impedance(struct snd_soc_component *component,
+ u32 *zl, u32 *zr)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ s16 reg0, reg1, reg2, reg3, reg4;
+ s32 z1l, z1r, z1ls;
+ int zMono, z_diff1, z_diff2;
+ bool is_fsm_disable = false;
+ struct wcd937x_mbhc_zdet_param zdet_param[] = {
+ {4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */
+ {2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */
+ {1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */
+ {1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */
+ };
+ struct wcd937x_mbhc_zdet_param *zdet_param_ptr = NULL;
+ s16 d1_a[][4] = {
+ {0, 30, 90, 30},
+ {0, 30, 30, 5},
+ {0, 30, 30, 5},
+ {0, 30, 30, 5},
+ };
+ s16 *d1 = NULL;
+
+ reg0 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN5);
+ reg1 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN6);
+ reg2 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN7);
+ reg3 = snd_soc_component_read(component, WCD937X_MBHC_CTL_CLK);
+ reg4 = snd_soc_component_read(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL);
+
+ if (snd_soc_component_read(component, WCD937X_ANA_MBHC_ELECT) & 0x80) {
+ is_fsm_disable = true;
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_ELECT, 0x80, 0x00);
+ }
+
+ /* For NO-jack, disable L_DET_EN before Z-det measurements */
+ if (wcd937x->mbhc_cfg.hphl_swh)
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_MECH, 0x80, 0x00);
+
+ /* Turn off 100k pull down on HPHL */
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_MECH, 0x01, 0x00);
+
+ /* Disable surge protection before impedance detection.
+ * This is done to give correct value for high impedance.
+ */
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0x00);
+ /* 1ms delay needed after disable surge protection */
+ usleep_range(1000, 1010);
+
+ /* First get impedance on Left */
+ d1 = d1_a[1];
+ zdet_param_ptr = &zdet_param[1];
+ wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1l, NULL, d1);
+
+ if (!WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z1l))
+ goto left_ch_impedance;
+
+ /* Second ramp for left ch */
+ if (z1l < WCD937X_ZDET_VAL_32) {
+ zdet_param_ptr = &zdet_param[0];
+ d1 = d1_a[0];
+ } else if ((z1l > WCD937X_ZDET_VAL_400) &&
+ (z1l <= WCD937X_ZDET_VAL_1200)) {
+ zdet_param_ptr = &zdet_param[2];
+ d1 = d1_a[2];
+ } else if (z1l > WCD937X_ZDET_VAL_1200) {
+ zdet_param_ptr = &zdet_param[3];
+ d1 = d1_a[3];
+ }
+ wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1l, NULL, d1);
+
+left_ch_impedance:
+ if (z1l == WCD937X_ZDET_FLOATING_IMPEDANCE ||
+ z1l > WCD937X_ZDET_VAL_100K) {
+ *zl = WCD937X_ZDET_FLOATING_IMPEDANCE;
+ zdet_param_ptr = &zdet_param[1];
+ d1 = d1_a[1];
+ } else {
+ *zl = z1l / 1000;
+ wcd937x_wcd_mbhc_qfuse_cal(component, zl, 0);
+ }
+
+ /* Start of right impedance ramp and calculation */
+ wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1r, d1);
+ if (WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z1r)) {
+ if ((z1r > WCD937X_ZDET_VAL_1200 &&
+ zdet_param_ptr->noff == 0x6) ||
+ ((*zl) != WCD937X_ZDET_FLOATING_IMPEDANCE))
+ goto right_ch_impedance;
+ /* Second ramp for right ch */
+ if (z1r < WCD937X_ZDET_VAL_32) {
+ zdet_param_ptr = &zdet_param[0];
+ d1 = d1_a[0];
+ } else if ((z1r > WCD937X_ZDET_VAL_400) &&
+ (z1r <= WCD937X_ZDET_VAL_1200)) {
+ zdet_param_ptr = &zdet_param[2];
+ d1 = d1_a[2];
+ } else if (z1r > WCD937X_ZDET_VAL_1200) {
+ zdet_param_ptr = &zdet_param[3];
+ d1 = d1_a[3];
+ }
+ wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1r, d1);
+ }
+right_ch_impedance:
+ if (z1r == WCD937X_ZDET_FLOATING_IMPEDANCE ||
+ z1r > WCD937X_ZDET_VAL_100K) {
+ *zr = WCD937X_ZDET_FLOATING_IMPEDANCE;
+ } else {
+ *zr = z1r / 1000;
+ wcd937x_wcd_mbhc_qfuse_cal(component, zr, 1);
+ }
+
+ /* Mono/stereo detection */
+ if ((*zl == WCD937X_ZDET_FLOATING_IMPEDANCE) &&
+ (*zr == WCD937X_ZDET_FLOATING_IMPEDANCE)) {
+ dev_err(component->dev,
+ "%s: plug type is invalid or extension cable\n",
+ __func__);
+ goto zdet_complete;
+ }
+ if ((*zl == WCD937X_ZDET_FLOATING_IMPEDANCE) ||
+ (*zr == WCD937X_ZDET_FLOATING_IMPEDANCE) ||
+ ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) ||
+ ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) {
+ wcd_mbhc_set_hph_type(wcd937x->wcd_mbhc, WCD_MBHC_HPH_MONO);
+ goto zdet_complete;
+ }
+ snd_soc_component_write_field(component, WCD937X_HPH_R_ATEST,
+ WCD937X_HPHPA_GND_OVR_MASK, 1);
+ snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2,
+ WCD937X_HPHPA_GND_R_MASK, 1);
+ if (*zl < (WCD937X_ZDET_VAL_32 / 1000))
+ wcd937x_mbhc_zdet_ramp(component, &zdet_param[0], &z1ls, NULL, d1);
+ else
+ wcd937x_mbhc_zdet_ramp(component, &zdet_param[1], &z1ls, NULL, d1);
+ snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2,
+ WCD937X_HPHPA_GND_R_MASK, 0);
+ snd_soc_component_write_field(component, WCD937X_HPH_R_ATEST,
+ WCD937X_HPHPA_GND_OVR_MASK, 0);
+ z1ls /= 1000;
+ wcd937x_wcd_mbhc_qfuse_cal(component, &z1ls, 0);
+ /* Parallel of left Z and 9 ohm pull down resistor */
+ zMono = ((*zl) * 9) / ((*zl) + 9);
+ z_diff1 = (z1ls > zMono) ? (z1ls - zMono) : (zMono - z1ls);
+ z_diff2 = ((*zl) > z1ls) ? ((*zl) - z1ls) : (z1ls - (*zl));
+ if ((z_diff1 * (*zl + z1ls)) > (z_diff2 * (z1ls + zMono)))
+ wcd_mbhc_set_hph_type(wcd937x->wcd_mbhc, WCD_MBHC_HPH_STEREO);
+ else
+ wcd_mbhc_set_hph_type(wcd937x->wcd_mbhc, WCD_MBHC_HPH_MONO);
+
+ /* Enable surge protection again after impedance detection */
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0);
+zdet_complete:
+ snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN5, reg0);
+ snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN6, reg1);
+ snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN7, reg2);
+ /* Turn on 100k pull down on HPHL */
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_MECH, 0x01, 0x01);
+
+ /* For NO-jack, re-enable L_DET_EN after Z-det measurements */
+ if (wcd937x->mbhc_cfg.hphl_swh)
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_MECH, 0x80, 0x80);
+
+ snd_soc_component_write(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL, reg4);
+ snd_soc_component_write(component, WCD937X_MBHC_CTL_CLK, reg3);
+ if (is_fsm_disable)
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_ELECT, 0x80, 0x80);
+}
+
+static void wcd937x_mbhc_gnd_det_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH,
+ WCD937X_MBHC_HSG_PULLUP_COMP_EN, 1);
+ snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH,
+ WCD937X_MBHC_GND_DET_EN_MASK, 1);
+ } else {
+ snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH,
+ WCD937X_MBHC_GND_DET_EN_MASK, 0);
+ snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH,
+ WCD937X_MBHC_HSG_PULLUP_COMP_EN, 0);
+ }
+}
+
+static void wcd937x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2,
+ WCD937X_HPHPA_GND_R_MASK, enable);
+ snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2,
+ WCD937X_HPHPA_GND_L_MASK, enable);
+}
+
+static void wcd937x_mbhc_moisture_config(struct snd_soc_component *component)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ if (wcd937x->mbhc_cfg.moist_rref == R_OFF) {
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+ WCD937X_M_RTH_CTL_MASK, R_OFF);
+ return;
+ }
+
+ /* Do not enable moisture detection if jack type is NC */
+ if (!wcd937x->mbhc_cfg.hphl_swh) {
+ dev_err(component->dev, "%s: disable moisture detection for NC\n",
+ __func__);
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+ WCD937X_M_RTH_CTL_MASK, R_OFF);
+ return;
+ }
+
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+ WCD937X_M_RTH_CTL_MASK, wcd937x->mbhc_cfg.moist_rref);
+}
+
+static void wcd937x_mbhc_moisture_detect_en(struct snd_soc_component *component, bool enable)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ if (enable)
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+ WCD937X_M_RTH_CTL_MASK, wcd937x->mbhc_cfg.moist_rref);
+ else
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+ WCD937X_M_RTH_CTL_MASK, R_OFF);
+}
+
+static bool wcd937x_mbhc_get_moisture_status(struct snd_soc_component *component)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ bool ret = false;
+
+ if (wcd937x->mbhc_cfg.moist_rref == R_OFF) {
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+ WCD937X_M_RTH_CTL_MASK, R_OFF);
+ goto done;
+ }
+
+ /* Do not enable moisture detection if jack type is NC */
+ if (!wcd937x->mbhc_cfg.hphl_swh) {
+ dev_err(component->dev, "%s: disable moisture detection for NC\n",
+ __func__);
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+ WCD937X_M_RTH_CTL_MASK, R_OFF);
+ goto done;
+ }
+
+ /*
+ * If moisture_en is already enabled, then skip to plug type
+ * detection.
+ */
+ if (snd_soc_component_read_field(component, WCD937X_MBHC_NEW_CTL_2, WCD937X_M_RTH_CTL_MASK))
+ goto done;
+
+ wcd937x_mbhc_moisture_detect_en(component, true);
+ /* Read moisture comparator status */
+ ret = ((snd_soc_component_read(component, WCD937X_MBHC_NEW_FSM_STATUS)
+ & 0x20) ? 0 : 1);
+done:
+ return ret;
+}
+
+static void wcd937x_mbhc_moisture_polling_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component,
+ WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL,
+ WCD937X_MOISTURE_EN_POLLING_MASK, enable);
+}
+
+static const struct wcd_mbhc_cb mbhc_cb = {
+ .clk_setup = wcd937x_mbhc_clk_setup,
+ .mbhc_bias = wcd937x_mbhc_mbhc_bias_control,
+ .set_btn_thr = wcd937x_mbhc_program_btn_thr,
+ .micbias_enable_status = wcd937x_mbhc_micb_en_status,
+ .hph_pull_up_control_v2 = wcd937x_mbhc_hph_l_pull_up_control,
+ .mbhc_micbias_control = wcd937x_mbhc_request_micbias,
+ .mbhc_micb_ramp_control = wcd937x_mbhc_micb_ramp_control,
+ .mbhc_micb_ctrl_thr_mic = wcd937x_mbhc_micb_ctrl_threshold_mic,
+ .compute_impedance = wcd937x_wcd_mbhc_calc_impedance,
+ .mbhc_gnd_det_ctrl = wcd937x_mbhc_gnd_det_ctrl,
+ .hph_pull_down_ctrl = wcd937x_mbhc_hph_pull_down_ctrl,
+ .mbhc_moisture_config = wcd937x_mbhc_moisture_config,
+ .mbhc_get_moisture_status = wcd937x_mbhc_get_moisture_status,
+ .mbhc_moisture_polling_ctrl = wcd937x_mbhc_moisture_polling_ctrl,
+ .mbhc_moisture_detect_en = wcd937x_mbhc_moisture_detect_en,
+};
+
+static int wcd937x_get_hph_type(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wcd_mbhc_get_hph_type(wcd937x->wcd_mbhc);
+
+ return 0;
+}
+
+static int wcd937x_hph_impedance_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u32 zl, zr;
+ bool hphr;
+ struct soc_mixer_control *mc;
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ mc = (struct soc_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+ wcd_mbhc_get_impedance(wcd937x->wcd_mbhc, &zl, &zr);
+ ucontrol->value.integer.value[0] = hphr ? zr : zl;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new hph_type_detect_controls[] = {
+ SOC_SINGLE_EXT("HPH Type", 0, 0, WCD_MBHC_HPH_STEREO, 0,
+ wcd937x_get_hph_type, NULL),
+};
+
+static const struct snd_kcontrol_new impedance_detect_controls[] = {
+ SOC_SINGLE_EXT("HPHL Impedance", 0, 0, INT_MAX, 0,
+ wcd937x_hph_impedance_get, NULL),
+ SOC_SINGLE_EXT("HPHR Impedance", 0, 1, INT_MAX, 0,
+ wcd937x_hph_impedance_get, NULL),
+};
+
+static int wcd937x_mbhc_init(struct snd_soc_component *component)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ struct wcd_mbhc_intr *intr_ids = &wcd937x->intr_ids;
+
+ intr_ids->mbhc_sw_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_MBHC_SW_DET);
+ intr_ids->mbhc_btn_press_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_MBHC_BUTTON_PRESS_DET);
+ intr_ids->mbhc_btn_release_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET);
+ intr_ids->mbhc_hs_ins_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET);
+ intr_ids->mbhc_hs_rem_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_MBHC_ELECT_INS_REM_DET);
+ intr_ids->hph_left_ocp = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_HPHL_OCP_INT);
+ intr_ids->hph_right_ocp = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_HPHR_OCP_INT);
+
+ wcd937x->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true);
+ if (IS_ERR(wcd937x->wcd_mbhc))
+ return PTR_ERR(wcd937x->wcd_mbhc);
+
+ snd_soc_add_component_controls(component, impedance_detect_controls,
+ ARRAY_SIZE(impedance_detect_controls));
+ snd_soc_add_component_controls(component, hph_type_detect_controls,
+ ARRAY_SIZE(hph_type_detect_controls));
+
+ return 0;
+}
+
+static void wcd937x_mbhc_deinit(struct snd_soc_component *component)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ wcd_mbhc_deinit(wcd937x->wcd_mbhc);
+}
+
+/* END MBHC */
+
+static const struct snd_kcontrol_new wcd937x_snd_controls[] = {
+ SOC_SINGLE_TLV("EAR_PA Volume", WCD937X_ANA_EAR_COMPANDER_CTL,
+ 2, 0x10, 0, ear_pa_gain),
+ SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum,
+ wcd937x_rx_hph_mode_get, wcd937x_rx_hph_mode_put),
+
+ SOC_SINGLE_EXT("HPHL_COMP Switch", SND_SOC_NOPM, 0, 1, 0,
+ wcd937x_get_compander, wcd937x_set_compander),
+ SOC_SINGLE_EXT("HPHR_COMP Switch", SND_SOC_NOPM, 1, 1, 0,
+ wcd937x_get_compander, wcd937x_set_compander),
+
+ SOC_SINGLE_TLV("HPHL Volume", WCD937X_HPH_L_EN, 0, 20, 1, line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", WCD937X_HPH_R_EN, 0, 20, 1, line_gain),
+ SOC_SINGLE_TLV("ADC1 Volume", WCD937X_ANA_TX_CH1, 0, 20, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", WCD937X_ANA_TX_CH2, 0, 20, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC3 Volume", WCD937X_ANA_TX_CH3, 0, 20, 0, analog_gain),
+
+ SOC_SINGLE_EXT("HPHL Switch", WCD937X_HPH_L, 0, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("HPHR Switch", WCD937X_HPH_R, 0, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+
+ SOC_SINGLE_EXT("ADC1 Switch", WCD937X_ADC1, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("ADC2 Switch", WCD937X_ADC2, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("ADC3 Switch", WCD937X_ADC3, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC0 Switch", WCD937X_DMIC0, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC1 Switch", WCD937X_DMIC1, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("MBHC Switch", WCD937X_MBHC, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC2 Switch", WCD937X_DMIC2, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC3 Switch", WCD937X_DMIC3, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC4 Switch", WCD937X_DMIC4, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC5 Switch", WCD937X_DMIC5, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+};
+
+static const struct snd_kcontrol_new adc1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new adc2_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new adc3_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic2_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic3_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic4_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic5_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic6_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new ear_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new aux_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphl_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphr_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const char * const adc2_mux_text[] = {
+ "INP2", "INP3"
+};
+
+static const char * const rdac3_mux_text[] = {
+ "RX1", "RX3"
+};
+
+static const struct soc_enum adc2_enum =
+ SOC_ENUM_SINGLE(WCD937X_TX_NEW_TX_CH2_SEL, 7,
+ ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
+static const struct soc_enum rdac3_enum =
+ SOC_ENUM_SINGLE(WCD937X_DIGITAL_CDC_EAR_PATH_CTL, 0,
+ ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text);
+
+static const struct snd_kcontrol_new tx_adc2_mux = SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
+static const struct snd_kcontrol_new rx_rdac3_mux = SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum);
+
+static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = {
+ /* Input widgets */
+ SND_SOC_DAPM_INPUT("AMIC1"),
+ SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_INPUT("AMIC3"),
+ SND_SOC_DAPM_INPUT("IN1_HPHL"),
+ SND_SOC_DAPM_INPUT("IN2_HPHR"),
+ SND_SOC_DAPM_INPUT("IN3_AUX"),
+
+ /* TX widgets */
+ SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0,
+ wcd937x_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0,
+ wcd937x_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER_E("ADC1 REQ", SND_SOC_NOPM, 0, 0,
+ NULL, 0, wcd937x_enable_req,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("ADC2 REQ", SND_SOC_NOPM, 0, 0,
+ NULL, 0, wcd937x_enable_req,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux),
+
+ /* TX mixers */
+ SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0,
+ adc1_switch, ARRAY_SIZE(adc1_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, 1, 0,
+ adc2_switch, ARRAY_SIZE(adc2_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* MIC_BIAS widgets */
+ SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0,
+ wcd937x_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0,
+ wcd937x_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0,
+ wcd937x_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT", 1, SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* RX widgets */
+ SND_SOC_DAPM_PGA_E("EAR PGA", WCD937X_ANA_EAR, 7, 0, NULL, 0,
+ wcd937x_codec_enable_ear_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("AUX PGA", WCD937X_AUX_AUXPA, 7, 0, NULL, 0,
+ wcd937x_codec_enable_aux_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHL PGA", WCD937X_ANA_HPH, 7, 0, NULL, 0,
+ wcd937x_codec_enable_hphl_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHR PGA", WCD937X_ANA_HPH, 6, 0, NULL, 0,
+ wcd937x_codec_enable_hphr_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0,
+ wcd937x_codec_hphl_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0,
+ wcd937x_codec_hphr_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0,
+ wcd937x_codec_ear_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RDAC4", NULL, SND_SOC_NOPM, 0, 0,
+ wcd937x_codec_aux_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("RDAC3_MUX", SND_SOC_NOPM, 0, 0, &rx_rdac3_mux),
+
+ SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0,
+ wcd937x_enable_rx1, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0,
+ wcd937x_enable_rx2, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("RX3", SND_SOC_NOPM, 0, 0, NULL, 0,
+ wcd937x_enable_rx3, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* RX mixer widgets*/
+ SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0,
+ ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)),
+ SND_SOC_DAPM_MIXER("AUX_RDAC", SND_SOC_NOPM, 0, 0,
+ aux_rdac_switch, ARRAY_SIZE(aux_rdac_switch)),
+ SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0,
+ hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)),
+ SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0,
+ hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)),
+
+ /* TX output widgets */
+ SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("WCD_TX_OUTPUT"),
+
+ /* RX output widgets */
+ SND_SOC_DAPM_OUTPUT("EAR"),
+ SND_SOC_DAPM_OUTPUT("AUX"),
+ SND_SOC_DAPM_OUTPUT("HPHL"),
+ SND_SOC_DAPM_OUTPUT("HPHR"),
+
+ /* MIC_BIAS pull up widgets */
+ SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0,
+ wcd937x_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0,
+ wcd937x_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0,
+ wcd937x_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_widget wcd9375_dapm_widgets[] = {
+ /* Input widgets */
+ SND_SOC_DAPM_INPUT("AMIC4"),
+
+ /* TX widgets */
+ SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 2, 0,
+ wcd937x_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER_E("ADC3 REQ", SND_SOC_NOPM, 0, 0,
+ NULL, 0, wcd937x_enable_req,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+ wcd937x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0,
+ wcd937x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 2, 0,
+ wcd937x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 3, 0,
+ wcd937x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 4, 0,
+ wcd937x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 5, 0,
+ wcd937x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* TX mixer widgets */
+ SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0,
+ 0, dmic1_switch, ARRAY_SIZE(dmic1_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, 1,
+ 0, dmic2_switch, ARRAY_SIZE(dmic2_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, 2,
+ 0, dmic3_switch, ARRAY_SIZE(dmic3_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, 3,
+ 0, dmic4_switch, ARRAY_SIZE(dmic4_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, 4,
+ 0, dmic5_switch, ARRAY_SIZE(dmic5_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, 5,
+ 0, dmic6_switch, ARRAY_SIZE(dmic6_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("ADC3_MIXER", SND_SOC_NOPM, 2, 0, adc3_switch,
+ ARRAY_SIZE(adc3_switch), wcd937x_tx_swr_ctrl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* Output widgets */
+ SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC3_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC4_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC5_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC6_OUTPUT"),
+};
+
+static const struct snd_soc_dapm_route wcd937x_audio_map[] = {
+ { "ADC1_OUTPUT", NULL, "ADC1_MIXER" },
+ { "ADC1_MIXER", "Switch", "ADC1 REQ" },
+ { "ADC1 REQ", NULL, "ADC1" },
+ { "ADC1", NULL, "AMIC1" },
+
+ { "ADC2_OUTPUT", NULL, "ADC2_MIXER" },
+ { "ADC2_MIXER", "Switch", "ADC2 REQ" },
+ { "ADC2 REQ", NULL, "ADC2" },
+ { "ADC2", NULL, "ADC2 MUX" },
+ { "ADC2 MUX", "INP3", "AMIC3" },
+ { "ADC2 MUX", "INP2", "AMIC2" },
+
+ { "IN1_HPHL", NULL, "VDD_BUCK" },
+ { "IN1_HPHL", NULL, "CLS_H_PORT" },
+ { "RX1", NULL, "IN1_HPHL" },
+ { "RDAC1", NULL, "RX1" },
+ { "HPHL_RDAC", "Switch", "RDAC1" },
+ { "HPHL PGA", NULL, "HPHL_RDAC" },
+ { "HPHL", NULL, "HPHL PGA" },
+
+ { "IN2_HPHR", NULL, "VDD_BUCK" },
+ { "IN2_HPHR", NULL, "CLS_H_PORT" },
+ { "RX2", NULL, "IN2_HPHR" },
+ { "RDAC2", NULL, "RX2" },
+ { "HPHR_RDAC", "Switch", "RDAC2" },
+ { "HPHR PGA", NULL, "HPHR_RDAC" },
+ { "HPHR", NULL, "HPHR PGA" },
+
+ { "IN3_AUX", NULL, "VDD_BUCK" },
+ { "IN3_AUX", NULL, "CLS_H_PORT" },
+ { "RX3", NULL, "IN3_AUX" },
+ { "RDAC4", NULL, "RX3" },
+ { "AUX_RDAC", "Switch", "RDAC4" },
+ { "AUX PGA", NULL, "AUX_RDAC" },
+ { "AUX", NULL, "AUX PGA" },
+
+ { "RDAC3_MUX", "RX3", "RX3" },
+ { "RDAC3_MUX", "RX1", "RX1" },
+ { "RDAC3", NULL, "RDAC3_MUX" },
+ { "EAR_RDAC", "Switch", "RDAC3" },
+ { "EAR PGA", NULL, "EAR_RDAC" },
+ { "EAR", NULL, "EAR PGA" },
+};
+
+static const struct snd_soc_dapm_route wcd9375_audio_map[] = {
+ { "ADC3_OUTPUT", NULL, "ADC3_MIXER" },
+ { "ADC3_OUTPUT", NULL, "ADC3_MIXER" },
+ { "ADC3_MIXER", "Switch", "ADC3 REQ" },
+ { "ADC3 REQ", NULL, "ADC3" },
+ { "ADC3", NULL, "AMIC4" },
+
+ { "DMIC1_OUTPUT", NULL, "DMIC1_MIXER" },
+ { "DMIC1_MIXER", "Switch", "DMIC1" },
+
+ { "DMIC2_OUTPUT", NULL, "DMIC2_MIXER" },
+ { "DMIC2_MIXER", "Switch", "DMIC2" },
+
+ { "DMIC3_OUTPUT", NULL, "DMIC3_MIXER" },
+ { "DMIC3_MIXER", "Switch", "DMIC3" },
+
+ { "DMIC4_OUTPUT", NULL, "DMIC4_MIXER" },
+ { "DMIC4_MIXER", "Switch", "DMIC4" },
+
+ { "DMIC5_OUTPUT", NULL, "DMIC5_MIXER" },
+ { "DMIC5_MIXER", "Switch", "DMIC5" },
+
+ { "DMIC6_OUTPUT", NULL, "DMIC6_MIXER" },
+ { "DMIC6_MIXER", "Switch", "DMIC6" },
+};
+
+static int wcd937x_set_micbias_data(struct wcd937x_priv *wcd937x)
+{
+ int vout_ctl[3];
+
+ /* Set micbias voltage */
+ vout_ctl[0] = wcd937x_get_micb_vout_ctl_val(wcd937x->micb1_mv);
+ vout_ctl[1] = wcd937x_get_micb_vout_ctl_val(wcd937x->micb2_mv);
+ vout_ctl[2] = wcd937x_get_micb_vout_ctl_val(wcd937x->micb3_mv);
+ if ((vout_ctl[0] | vout_ctl[1] | vout_ctl[2]) < 0)
+ return -EINVAL;
+
+ regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB1, WCD937X_ANA_MICB_VOUT, vout_ctl[0]);
+ regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB2, WCD937X_ANA_MICB_VOUT, vout_ctl[1]);
+ regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB3, WCD937X_ANA_MICB_VOUT, vout_ctl[2]);
+
+ return 0;
+}
+
+static irqreturn_t wcd937x_wd_handle_irq(int irq, void *data)
+{
+ return IRQ_HANDLED;
+}
+
+static const struct irq_chip wcd_irq_chip = {
+ .name = "WCD937x",
+};
+
+static int wcd_irq_chip_map(struct irq_domain *irqd, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(virq, &wcd_irq_chip, handle_simple_irq);
+ irq_set_nested_thread(virq, 1);
+ irq_set_noprobe(virq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops wcd_domain_ops = {
+ .map = wcd_irq_chip_map,
+};
+
+static int wcd937x_irq_init(struct wcd937x_priv *wcd, struct device *dev)
+{
+ wcd->virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL);
+ if (!(wcd->virq)) {
+ dev_err(dev, "%s: Failed to add IRQ domain\n", __func__);
+ return -EINVAL;
+ }
+
+ return devm_regmap_add_irq_chip(dev, wcd->regmap,
+ irq_create_mapping(wcd->virq, 0),
+ IRQF_ONESHOT, 0, &wcd937x_regmap_irq_chip,
+ &wcd->irq_chip);
+}
+
+static int wcd937x_soc_codec_probe(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ struct sdw_slave *tx_sdw_dev = wcd937x->tx_sdw_dev;
+ struct device *dev = component->dev;
+ unsigned long time_left;
+ int i, ret;
+ u32 chipid;
+
+ time_left = wait_for_completion_timeout(&tx_sdw_dev->initialization_complete,
+ msecs_to_jiffies(5000));
+ if (!time_left) {
+ dev_err(dev, "soundwire device init timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ snd_soc_component_init_regmap(component, wcd937x->regmap);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ chipid = (snd_soc_component_read(component,
+ WCD937X_DIGITAL_EFUSE_REG_0) & 0x1e) >> 1;
+ if (chipid != CHIPID_WCD9370 && chipid != CHIPID_WCD9375) {
+ dev_err(dev, "Got unknown chip id: 0x%x\n", chipid);
+ pm_runtime_put(dev);
+ return -EINVAL;
+ }
+
+ wcd937x->clsh_info = wcd_clsh_ctrl_alloc(component, WCD937X);
+ if (IS_ERR(wcd937x->clsh_info)) {
+ pm_runtime_put(dev);
+ return PTR_ERR(wcd937x->clsh_info);
+ }
+
+ wcd937x_io_init(wcd937x->regmap);
+ /* Set all interrupts as edge triggered */
+ for (i = 0; i < wcd937x_regmap_irq_chip.num_regs; i++)
+ regmap_write(wcd937x->regmap, (WCD937X_DIGITAL_INTR_LEVEL_0 + i), 0);
+
+ pm_runtime_put(dev);
+
+ wcd937x->hphr_pdm_wd_int = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_HPHR_PDM_WD_INT);
+ wcd937x->hphl_pdm_wd_int = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_HPHL_PDM_WD_INT);
+ wcd937x->aux_pdm_wd_int = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_AUX_PDM_WD_INT);
+
+ /* Request for watchdog interrupt */
+ ret = devm_request_threaded_irq(dev, wcd937x->hphr_pdm_wd_int, NULL, wcd937x_wd_handle_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ "HPHR PDM WDOG INT", wcd937x);
+ if (ret)
+ dev_err(dev, "Failed to request HPHR watchdog interrupt (%d)\n", ret);
+
+ ret = devm_request_threaded_irq(dev, wcd937x->hphl_pdm_wd_int, NULL, wcd937x_wd_handle_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ "HPHL PDM WDOG INT", wcd937x);
+ if (ret)
+ dev_err(dev, "Failed to request HPHL watchdog interrupt (%d)\n", ret);
+
+ ret = devm_request_threaded_irq(dev, wcd937x->aux_pdm_wd_int, NULL, wcd937x_wd_handle_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ "AUX PDM WDOG INT", wcd937x);
+ if (ret)
+ dev_err(dev, "Failed to request Aux watchdog interrupt (%d)\n", ret);
+
+ /* Disable watchdog interrupt for HPH and AUX */
+ disable_irq_nosync(wcd937x->hphr_pdm_wd_int);
+ disable_irq_nosync(wcd937x->hphl_pdm_wd_int);
+ disable_irq_nosync(wcd937x->aux_pdm_wd_int);
+
+ if (chipid == CHIPID_WCD9375) {
+ ret = snd_soc_dapm_new_controls(dapm, wcd9375_dapm_widgets,
+ ARRAY_SIZE(wcd9375_dapm_widgets));
+ if (ret < 0) {
+ dev_err(component->dev, "Failed to add snd_ctls\n");
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, wcd9375_audio_map,
+ ARRAY_SIZE(wcd9375_audio_map));
+ if (ret < 0) {
+ dev_err(component->dev, "Failed to add routes\n");
+ return ret;
+ }
+ }
+
+ ret = wcd937x_mbhc_init(component);
+ if (ret)
+ dev_err(component->dev, "mbhc initialization failed\n");
+
+ return ret;
+}
+
+static void wcd937x_soc_codec_remove(struct snd_soc_component *component)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ wcd937x_mbhc_deinit(component);
+ free_irq(wcd937x->aux_pdm_wd_int, wcd937x);
+ free_irq(wcd937x->hphl_pdm_wd_int, wcd937x);
+ free_irq(wcd937x->hphr_pdm_wd_int, wcd937x);
+
+ wcd_clsh_ctrl_free(wcd937x->clsh_info);
+}
+
+static int wcd937x_codec_set_jack(struct snd_soc_component *comp,
+ struct snd_soc_jack *jack, void *data)
+{
+ struct wcd937x_priv *wcd = dev_get_drvdata(comp->dev);
+ int ret = 0;
+
+ if (jack)
+ ret = wcd_mbhc_start(wcd->wcd_mbhc, &wcd->mbhc_cfg, jack);
+ else
+ wcd_mbhc_stop(wcd->wcd_mbhc);
+
+ return ret;
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_wcd937x = {
+ .name = "wcd937x_codec",
+ .probe = wcd937x_soc_codec_probe,
+ .remove = wcd937x_soc_codec_remove,
+ .controls = wcd937x_snd_controls,
+ .num_controls = ARRAY_SIZE(wcd937x_snd_controls),
+ .dapm_widgets = wcd937x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wcd937x_dapm_widgets),
+ .dapm_routes = wcd937x_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(wcd937x_audio_map),
+ .set_jack = wcd937x_codec_set_jack,
+ .endianness = 1,
+};
+
+static void wcd937x_dt_parse_micbias_info(struct device *dev, struct wcd937x_priv *wcd)
+{
+ struct device_node *np = dev->of_node;
+ u32 prop_val = 0;
+ int ret = 0;
+
+ ret = of_property_read_u32(np, "qcom,micbias1-microvolt", &prop_val);
+ if (!ret)
+ wcd->micb1_mv = prop_val / 1000;
+ else
+ dev_warn(dev, "Micbias1 DT property not found\n");
+
+ ret = of_property_read_u32(np, "qcom,micbias2-microvolt", &prop_val);
+ if (!ret)
+ wcd->micb2_mv = prop_val / 1000;
+ else
+ dev_warn(dev, "Micbias2 DT property not found\n");
+
+ ret = of_property_read_u32(np, "qcom,micbias3-microvolt", &prop_val);
+ if (!ret)
+ wcd->micb3_mv = prop_val / 1000;
+ else
+ dev_warn(dev, "Micbias3 DT property not found\n");
+}
+
+static bool wcd937x_swap_gnd_mic(struct snd_soc_component *component, bool active)
+{
+ int value;
+ struct wcd937x_priv *wcd937x;
+
+ wcd937x = snd_soc_component_get_drvdata(component);
+
+ value = gpiod_get_value(wcd937x->us_euro_gpio);
+ gpiod_set_value(wcd937x->us_euro_gpio, !value);
+
+ return true;
+}
+
+static int wcd937x_codec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev);
+ struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id];
+
+ return wcd937x_sdw_hw_params(wcd, substream, params, dai);
+}
+
+static int wcd937x_codec_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev);
+ struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id];
+
+ return sdw_stream_remove_slave(wcd->sdev, wcd->sruntime);
+}
+
+static int wcd937x_codec_set_sdw_stream(struct snd_soc_dai *dai,
+ void *stream, int direction)
+{
+ struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev);
+ struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id];
+
+ wcd->sruntime = stream;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops wcd937x_sdw_dai_ops = {
+ .hw_params = wcd937x_codec_hw_params,
+ .hw_free = wcd937x_codec_free,
+ .set_stream = wcd937x_codec_set_sdw_stream,
+};
+
+static struct snd_soc_dai_driver wcd937x_dais[] = {
+ [0] = {
+ .name = "wcd937x-sdw-rx",
+ .playback = {
+ .stream_name = "WCD AIF Playback",
+ .rates = WCD937X_RATES | WCD937X_FRAC_RATES,
+ .formats = WCD937X_FORMATS,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &wcd937x_sdw_dai_ops,
+ },
+ [1] = {
+ .name = "wcd937x-sdw-tx",
+ .capture = {
+ .stream_name = "WCD AIF Capture",
+ .rates = WCD937X_RATES,
+ .formats = WCD937X_FORMATS,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &wcd937x_sdw_dai_ops,
+ },
+};
+
+static int wcd937x_bind(struct device *dev)
+{
+ struct wcd937x_priv *wcd937x = dev_get_drvdata(dev);
+ int ret;
+
+ /* Give the SDW subdevices some more time to settle */
+ usleep_range(5000, 5010);
+
+ ret = component_bind_all(dev, wcd937x);
+ if (ret) {
+ dev_err(dev, "Slave bind failed, ret = %d\n", ret);
+ return ret;
+ }
+
+ wcd937x->rxdev = wcd937x_sdw_device_get(wcd937x->rxnode);
+ if (!wcd937x->rxdev) {
+ dev_err(dev, "could not find slave with matching of node\n");
+ return -EINVAL;
+ }
+
+ wcd937x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd937x->rxdev);
+ wcd937x->sdw_priv[AIF1_PB]->wcd937x = wcd937x;
+
+ wcd937x->txdev = wcd937x_sdw_device_get(wcd937x->txnode);
+ if (!wcd937x->txdev) {
+ dev_err(dev, "could not find txslave with matching of node\n");
+ return -EINVAL;
+ }
+
+ wcd937x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd937x->txdev);
+ wcd937x->sdw_priv[AIF1_CAP]->wcd937x = wcd937x;
+ wcd937x->tx_sdw_dev = dev_to_sdw_dev(wcd937x->txdev);
+ if (!wcd937x->tx_sdw_dev) {
+ dev_err(dev, "could not get txslave with matching of dev\n");
+ return -EINVAL;
+ }
+
+ /*
+ * As TX is the main CSR reg interface, which should not be suspended first.
+ * expicilty add the dependency link
+ */
+ if (!device_link_add(wcd937x->rxdev, wcd937x->txdev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
+ dev_err(dev, "Could not devlink TX and RX\n");
+ return -EINVAL;
+ }
+
+ if (!device_link_add(dev, wcd937x->txdev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
+ dev_err(dev, "Could not devlink WCD and TX\n");
+ return -EINVAL;
+ }
+
+ if (!device_link_add(dev, wcd937x->rxdev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
+ dev_err(dev, "Could not devlink WCD and RX\n");
+ return -EINVAL;
+ }
+
+ wcd937x->regmap = dev_get_regmap(&wcd937x->tx_sdw_dev->dev, NULL);
+ if (!wcd937x->regmap) {
+ dev_err(dev, "could not get TX device regmap\n");
+ return -EINVAL;
+ }
+
+ ret = wcd937x_irq_init(wcd937x, dev);
+ if (ret) {
+ dev_err(dev, "IRQ init failed: %d\n", ret);
+ return ret;
+ }
+
+ wcd937x->sdw_priv[AIF1_PB]->slave_irq = wcd937x->virq;
+ wcd937x->sdw_priv[AIF1_CAP]->slave_irq = wcd937x->virq;
+
+ ret = wcd937x_set_micbias_data(wcd937x);
+ if (ret < 0) {
+ dev_err(dev, "Bad micbias pdata\n");
+ return ret;
+ }
+
+ ret = snd_soc_register_component(dev, &soc_codec_dev_wcd937x,
+ wcd937x_dais, ARRAY_SIZE(wcd937x_dais));
+ if (ret)
+ dev_err(dev, "Codec registration failed\n");
+
+ return ret;
+}
+
+static void wcd937x_unbind(struct device *dev)
+{
+ struct wcd937x_priv *wcd937x = dev_get_drvdata(dev);
+
+ snd_soc_unregister_component(dev);
+ device_link_remove(dev, wcd937x->txdev);
+ device_link_remove(dev, wcd937x->rxdev);
+ device_link_remove(wcd937x->rxdev, wcd937x->txdev);
+ component_unbind_all(dev, wcd937x);
+ mutex_destroy(&wcd937x->micb_lock);
+}
+
+static const struct component_master_ops wcd937x_comp_ops = {
+ .bind = wcd937x_bind,
+ .unbind = wcd937x_unbind,
+};
+
+static int wcd937x_add_slave_components(struct wcd937x_priv *wcd937x,
+ struct device *dev,
+ struct component_match **matchptr)
+{
+ struct device_node *np = dev->of_node;
+
+ wcd937x->rxnode = of_parse_phandle(np, "qcom,rx-device", 0);
+ if (!wcd937x->rxnode) {
+ dev_err(dev, "Couldn't parse phandle to qcom,rx-device!\n");
+ return -ENODEV;
+ }
+ of_node_get(wcd937x->rxnode);
+ component_match_add_release(dev, matchptr, component_release_of,
+ component_compare_of, wcd937x->rxnode);
+
+ wcd937x->txnode = of_parse_phandle(np, "qcom,tx-device", 0);
+ if (!wcd937x->txnode) {
+ dev_err(dev, "Couldn't parse phandle to qcom,tx-device\n");
+ return -ENODEV;
+ }
+ of_node_get(wcd937x->txnode);
+ component_match_add_release(dev, matchptr, component_release_of,
+ component_compare_of, wcd937x->txnode);
+
+ return 0;
+}
+
+static int wcd937x_probe(struct platform_device *pdev)
+{
+ struct component_match *match = NULL;
+ struct device *dev = &pdev->dev;
+ struct wcd937x_priv *wcd937x;
+ struct wcd_mbhc_config *cfg;
+ int ret;
+
+ wcd937x = devm_kzalloc(dev, sizeof(*wcd937x), GFP_KERNEL);
+ if (!wcd937x)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, wcd937x);
+ mutex_init(&wcd937x->micb_lock);
+
+ wcd937x->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(wcd937x->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(wcd937x->reset_gpio),
+ "failed to reset wcd gpio\n");
+
+ wcd937x->us_euro_gpio = devm_gpiod_get_optional(dev, "us-euro", GPIOD_OUT_LOW);
+ if (IS_ERR(wcd937x->us_euro_gpio))
+ return dev_err_probe(dev, PTR_ERR(wcd937x->us_euro_gpio),
+ "us-euro swap Control GPIO not found\n");
+
+ cfg = &wcd937x->mbhc_cfg;
+ cfg->swap_gnd_mic = wcd937x_swap_gnd_mic;
+
+ wcd937x->supplies[0].supply = "vdd-rxtx";
+ wcd937x->supplies[1].supply = "vdd-px";
+ wcd937x->supplies[2].supply = "vdd-mic-bias";
+ wcd937x->supplies[3].supply = "vdd-buck";
+
+ ret = devm_regulator_bulk_get(dev, WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get supplies\n");
+
+ ret = regulator_bulk_enable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+ if (ret) {
+ regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+ return dev_err_probe(dev, ret, "Failed to enable supplies\n");
+ }
+
+ wcd937x_dt_parse_micbias_info(dev, wcd937x);
+
+ cfg->mbhc_micbias = MIC_BIAS_2;
+ cfg->anc_micbias = MIC_BIAS_2;
+ cfg->v_hs_max = WCD_MBHC_HS_V_MAX;
+ cfg->num_btn = WCD937X_MBHC_MAX_BUTTONS;
+ cfg->micb_mv = wcd937x->micb2_mv;
+ cfg->linein_th = 5000;
+ cfg->hs_thr = 1700;
+ cfg->hph_thr = 50;
+
+ wcd_dt_parse_mbhc_data(dev, &wcd937x->mbhc_cfg);
+
+ ret = wcd937x_add_slave_components(wcd937x, dev, &match);
+ if (ret)
+ goto err_disable_regulators;
+
+ wcd937x_reset(wcd937x);
+
+ ret = component_master_add_with_match(dev, &wcd937x_comp_ops, match);
+ if (ret)
+ goto err_disable_regulators;
+
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+ return 0;
+
+err_disable_regulators:
+ regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+ regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+
+ return ret;
+}
+
+static void wcd937x_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct wcd937x_priv *wcd937x = dev_get_drvdata(dev);
+
+ component_master_del(&pdev->dev, &wcd937x_comp_ops);
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_dont_use_autosuspend(dev);
+
+ regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+ regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id wcd937x_of_match[] = {
+ { .compatible = "qcom,wcd9370-codec" },
+ { .compatible = "qcom,wcd9375-codec" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wcd937x_of_match);
+#endif
+
+static struct platform_driver wcd937x_codec_driver = {
+ .probe = wcd937x_probe,
+ .remove_new = wcd937x_remove,
+ .driver = {
+ .name = "wcd937x_codec",
+ .of_match_table = of_match_ptr(wcd937x_of_match),
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(wcd937x_codec_driver);
+MODULE_DESCRIPTION("WCD937X Codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wcd937x.h b/sound/soc/codecs/wcd937x.h
new file mode 100644
index 000000000000..37bff16e88dd
--- /dev/null
+++ b/sound/soc/codecs/wcd937x.h
@@ -0,0 +1,624 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _WCD937X_REGISTERS_H
+#define _WCD937X_REGISTERS_H
+
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+
+#define WCD937X_BASE_ADDRESS 0x3000
+#define WCD937X_ANA_BIAS 0x3001
+#define WCD937X_ANA_RX_SUPPLIES 0x3008
+#define WCD937X_ANA_HPH 0x3009
+#define WCD937X_ANA_EAR 0x300A
+#define WCD937X_ANA_EAR_COMPANDER_CTL 0x300B
+#define WCD937X_EAR_GAIN_MASK GENMASK(6, 2)
+#define WCD937X_ANA_TX_CH1 0x300E
+#define WCD937X_ANA_TX_CH2 0x300F
+#define WCD937X_ANA_TX_CH3 0x3010
+#define WCD937X_ANA_TX_CH3_HPF 0x3011
+#define WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC 0x3012
+#define WCD937X_ANA_MICB3_DSP_EN_LOGIC 0x3013
+#define WCD937X_ANA_MBHC_MECH 0x3014
+#define WCD937X_MBHC_L_DET_EN_MASK BIT(7)
+#define WCD937X_MBHC_L_DET_EN BIT(7)
+#define WCD937X_MBHC_GND_DET_EN_MASK BIT(6)
+#define WCD937X_MBHC_MECH_DETECT_TYPE_MASK BIT(5)
+#define WCD937X_MBHC_MECH_DETECT_TYPE_INS 1
+#define WCD937X_MBHC_HPHL_PLUG_TYPE_MASK BIT(4)
+#define WCD937X_MBHC_HPHL_PLUG_TYPE_NO 1
+#define WCD937X_MBHC_GND_PLUG_TYPE_MASK BIT(3)
+#define WCD937X_MBHC_GND_PLUG_TYPE_NO 1
+#define WCD937X_MBHC_HSL_PULLUP_COMP_EN BIT(2)
+#define WCD937X_MBHC_HSG_PULLUP_COMP_EN BIT(1)
+#define WCD937X_MBHC_HPHL_100K_TO_GND_EN BIT(0)
+#define WCD937X_ANA_MBHC_ELECT 0x3015
+#define WCD937X_ANA_MBHC_BD_ISRC_CTL_MASK GENMASK(6, 4)
+#define WCD937X_ANA_MBHC_BD_ISRC_100UA GENMASK(5, 4)
+#define WCD937X_ANA_MBHC_BD_ISRC_OFF 0
+#define WCD937X_ANA_MBHC_BIAS_EN_MASK BIT(0)
+#define WCD937X_ANA_MBHC_BIAS_EN BIT(0)
+#define WCD937X_ANA_MBHC_ZDET 0x3016
+#define WCD937X_ANA_MBHC_RESULT_1 0x3017
+#define WCD937X_ANA_MBHC_RESULT_2 0x3018
+#define WCD937X_ANA_MBHC_RESULT_3 0x3019
+#define WCD937X_MBHC_BTN_RESULT_MASK GENMASK(2, 0)
+#define WCD937X_ANA_MBHC_BTN0 0x301A
+#define WCD937X_MBHC_BTN_VTH_MASK GENMASK(7, 2)
+#define WCD937X_ANA_MBHC_BTN1 0x301B
+#define WCD937X_ANA_MBHC_BTN2 0x301C
+#define WCD937X_ANA_MBHC_BTN3 0x301D
+#define WCD937X_ANA_MBHC_BTN4 0x301E
+#define WCD937X_ANA_MBHC_BTN5 0x301F
+#define WCD937X_VTH_MASK GENMASK(7, 2)
+#define WCD937X_ANA_MBHC_BTN6 0x3020
+#define WCD937X_ANA_MBHC_BTN7 0x3021
+#define WCD937X_ANA_MICB1 0x3022
+#define WCD937X_MICB_VOUT_MASK GENMASK(5, 0)
+#define WCD937X_MICB_EN_MASK GENMASK(7, 6)
+#define WCD937X_MICB_DISABLE 0
+#define WCD937X_MICB_ENABLE 1
+#define WCD937X_MICB_PULL_UP 2
+#define WCD937X_MICB_PULL_DOWN 3
+#define WCD937X_ANA_MICB2 0x3023
+#define WCD937X_ANA_MICB2_ENABLE BIT(6)
+#define WCD937X_ANA_MICB2_ENABLE_MASK GENMASK(7, 6)
+#define WCD937X_ANA_MICB2_VOUT_MASK GENMASK(5, 0)
+#define WCD937X_ANA_MICB2_RAMP 0x3024
+#define WCD937X_RAMP_EN_MASK BIT(7)
+#define WCD937X_RAMP_SHIFT_CTRL_MASK GENMASK(4, 2)
+#define WCD937X_ANA_MICB3 0x3025
+#define WCD937X_ANA_MICB_EN GENMASK(7, 6)
+#define WCD937X_MICB_DISABLE 0
+#define WCD937X_MICB_ENABLE 1
+#define WCD937X_MICB_PULL_UP 2
+#define WCD937X_ANA_MICB_VOUT GENMASK(5, 0)
+#define WCD937X_BIAS_CTL 0x3028
+#define WCD937X_BIAS_VBG_FINE_ADJ 0x3029
+#define WCD937X_LDOL_VDDCX_ADJUST 0x3040
+#define WCD937X_LDOL_DISABLE_LDOL 0x3041
+#define WCD937X_MBHC_CTL_CLK 0x3056
+#define WCD937X_MBHC_CTL_ANA 0x3057
+#define WCD937X_MBHC_CTL_SPARE_1 0x3058
+#define WCD937X_MBHC_CTL_SPARE_2 0x3059
+#define WCD937X_MBHC_CTL_BCS 0x305A
+#define WCD937X_MBHC_MOISTURE_DET_FSM_STATUS 0x305B
+#define WCD937X_MBHC_TEST_CTL 0x305C
+#define WCD937X_LDOH_MODE 0x3067
+#define WCD937X_LDOH_BIAS 0x3068
+#define WCD937X_LDOH_STB_LOADS 0x3069
+#define WCD937X_LDOH_SLOWRAMP 0x306A
+#define WCD937X_MICB1_TEST_CTL_1 0x306B
+#define WCD937X_MICB1_TEST_CTL_2 0x306C
+#define WCD937X_MICB1_TEST_CTL_3 0x306D
+#define WCD937X_MICB2_TEST_CTL_1 0x306E
+#define WCD937X_MICB2_TEST_CTL_2 0x306F
+#define WCD937X_MICB2_TEST_CTL_3 0x3070
+#define WCD937X_MICB3_TEST_CTL_1 0x3071
+#define WCD937X_MICB3_TEST_CTL_2 0x3072
+#define WCD937X_MICB3_TEST_CTL_3 0x3073
+#define WCD937X_TX_COM_ADC_VCM 0x3077
+#define WCD937X_TX_COM_BIAS_ATEST 0x3078
+#define WCD937X_TX_COM_ADC_INT1_IB 0x3079
+#define WCD937X_TX_COM_ADC_INT2_IB 0x307A
+#define WCD937X_TX_COM_TXFE_DIV_CTL 0x307B
+#define WCD937X_TX_COM_TXFE_DIV_START 0x307C
+#define WCD937X_TX_COM_TXFE_DIV_STOP_9P6M 0x307D
+#define WCD937X_TX_COM_TXFE_DIV_STOP_12P288M 0x307E
+#define WCD937X_TX_1_2_TEST_EN 0x307F
+#define WCD937X_TX_1_2_ADC_IB 0x3080
+#define WCD937X_TX_1_2_ATEST_REFCTL 0x3081
+#define WCD937X_TX_1_2_TEST_CTL 0x3082
+#define WCD937X_TX_1_2_TEST_BLK_EN 0x3083
+#define WCD937X_TX_1_2_TXFE_CLKDIV 0x3084
+#define WCD937X_TX_1_2_SAR2_ERR 0x3085
+#define WCD937X_TX_1_2_SAR1_ERR 0x3086
+#define WCD937X_TX_3_TEST_EN 0x3087
+#define WCD937X_TX_3_ADC_IB 0x3088
+#define WCD937X_TX_3_ATEST_REFCTL 0x3089
+#define WCD937X_TX_3_TEST_CTL 0x308A
+#define WCD937X_TX_3_TEST_BLK_EN 0x308B
+#define WCD937X_TX_3_TXFE_CLKDIV 0x308C
+#define WCD937X_TX_3_SPARE_MONO 0x308D
+#define WCD937X_TX_3_SAR1_ERR 0x308E
+#define WCD937X_CLASSH_MODE_1 0x3097
+#define WCD937X_CLASSH_MODE_2 0x3098
+#define WCD937X_CLASSH_MODE_3 0x3099
+#define WCD937X_CLASSH_CTRL_VCL_1 0x309A
+#define WCD937X_CLASSH_CTRL_VCL_2 0x309B
+#define WCD937X_CLASSH_CTRL_CCL_1 0x309C
+#define WCD937X_CLASSH_CTRL_CCL_2 0x309D
+#define WCD937X_CLASSH_CTRL_CCL_3 0x309E
+#define WCD937X_CLASSH_CTRL_CCL_4 0x309F
+#define WCD937X_CLASSH_CTRL_CCL_5 0x30A0
+#define WCD937X_CLASSH_BUCK_TMUX_A_D 0x30A1
+#define WCD937X_CLASSH_BUCK_SW_DRV_CNTL 0x30A2
+#define WCD937X_CLASSH_SPARE 0x30A3
+#define WCD937X_FLYBACK_EN 0x30A4
+#define WCD937X_FLYBACK_VNEG_CTRL_1 0x30A5
+#define WCD937X_FLYBACK_VNEG_CTRL_2 0x30A6
+#define WCD937X_FLYBACK_VNEG_CTRL_3 0x30A7
+#define WCD937X_FLYBACK_VNEG_CTRL_4 0x30A8
+#define WCD937X_FLYBACK_VNEG_CTRL_5 0x30A9
+#define WCD937X_FLYBACK_VNEG_CTRL_6 0x30AA
+#define WCD937X_FLYBACK_VNEG_CTRL_7 0x30AB
+#define WCD937X_FLYBACK_VNEG_CTRL_8 0x30AC
+#define WCD937X_FLYBACK_VNEG_CTRL_9 0x30AD
+#define WCD937X_FLYBACK_VNEGDAC_CTRL_1 0x30AE
+#define WCD937X_FLYBACK_VNEGDAC_CTRL_2 0x30AF
+#define WCD937X_FLYBACK_VNEGDAC_CTRL_3 0x30B0
+#define WCD937X_FLYBACK_CTRL_1 0x30B1
+#define WCD937X_FLYBACK_TEST_CTL 0x30B2
+#define WCD937X_RX_AUX_SW_CTL 0x30B3
+#define WCD937X_RX_PA_AUX_IN_CONN 0x30B4
+#define WCD937X_RX_TIMER_DIV 0x30B5
+#define WCD937X_RX_OCP_CTL 0x30B6
+#define WCD937X_RX_OCP_COUNT 0x30B7
+#define WCD937X_RX_BIAS_EAR_DAC 0x30B8
+#define WCD937X_RX_BIAS_EAR_AMP 0x30B9
+#define WCD937X_RX_BIAS_HPH_LDO 0x30BA
+#define WCD937X_RX_BIAS_HPH_PA 0x30BB
+#define WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2 0x30BC
+#define WCD937X_RX_BIAS_HPH_RDAC_LDO 0x30BD
+#define WCD937X_RX_BIAS_HPH_CNP1 0x30BE
+#define WCD937X_RX_BIAS_HPH_LOWPOWER 0x30BF
+#define WCD937X_RX_BIAS_AUX_DAC 0x30C0
+#define WCD937X_RX_BIAS_AUX_AMP 0x30C1
+#define WCD937X_RX_BIAS_VNEGDAC_BLEEDER 0x30C2
+#define WCD937X_RX_BIAS_MISC 0x30C3
+#define WCD937X_RX_BIAS_BUCK_RST 0x30C4
+#define WCD937X_RX_BIAS_BUCK_VREF_ERRAMP 0x30C5
+#define WCD937X_RX_BIAS_FLYB_ERRAMP 0x30C6
+#define WCD937X_RX_BIAS_FLYB_BUFF 0x30C7
+#define WCD937X_RX_BIAS_FLYB_MID_RST 0x30C8
+#define WCD937X_HPH_L_STATUS 0x30C9
+#define WCD937X_HPH_R_STATUS 0x30CA
+#define WCD937X_HPH_CNP_EN 0x30CB
+#define WCD937X_HPH_CNP_WG_CTL 0x30CC
+#define WCD937X_HPH_CNP_WG_TIME 0x30CD
+#define WCD937X_HPH_OCP_CTL 0x30CE
+#define WCD937X_HPH_AUTO_CHOP 0x30CF
+#define WCD937X_HPH_CHOP_CTL 0x30D0
+#define WCD937X_HPH_PA_CTL1 0x30D1
+#define WCD937X_HPH_PA_CTL2 0x30D2
+#define WCD937X_HPHPA_GND_R_MASK BIT(6)
+#define WCD937X_HPHPA_GND_L_MASK BIT(4)
+#define WCD937X_HPH_L_EN 0x30D3
+#define WCD937X_HPH_L_TEST 0x30D4
+#define WCD937X_HPH_L_ATEST 0x30D5
+#define WCD937X_HPH_R_EN 0x30D6
+#define WCD937X_GAIN_SRC_SEL_MASK BIT(5)
+#define WCD937X_GAIN_SRC_SEL_REGISTER 1
+#define WCD937X_HPH_R_TEST 0x30D7
+#define WCD937X_HPH_R_ATEST 0x30D8
+#define WCD937X_HPH_RDAC_CLK_CTL1 0x30D9
+#define WCD937X_HPHPA_GND_OVR_MASK BIT(1)
+#define WCD937X_CHOP_CLK_EN_MASK BIT(7)
+#define WCD937X_HPH_RDAC_CLK_CTL2 0x30DA
+#define WCD937X_HPH_RDAC_LDO_CTL 0x30DB
+#define WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL 0x30DC
+#define WCD937X_HPH_REFBUFF_UHQA_CTL 0x30DD
+#define WCD937X_HPH_REFBUFF_LP_CTL 0x30DE
+#define WCD937X_PREREF_FLIT_BYPASS_MASK BIT(0)
+#define WCD937X_HPH_L_DAC_CTL 0x30DF
+#define WCD937X_HPH_R_DAC_CTL 0x30E0
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL 0x30E1
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_EN 0x30E2
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1 0x30E3
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS 0x30E4
+#define WCD937X_EAR_EAR_EN_REG 0x30E9
+#define WCD937X_EAR_EAR_PA_CON 0x30EA
+#define WCD937X_EAR_EAR_SP_CON 0x30EB
+#define WCD937X_EAR_EAR_DAC_CON 0x30EC
+#define WCD937X_EAR_EAR_CNP_FSM_CON 0x30ED
+#define WCD937X_EAR_TEST_CTL 0x30EE
+#define WCD937X_EAR_STATUS_REG_1 0x30EF
+#define WCD937X_EAR_STATUS_REG_2 0x30F0
+#define WCD937X_ANA_NEW_PAGE_REGISTER 0x3100
+#define WCD937X_HPH_NEW_ANA_HPH2 0x3101
+#define WCD937X_HPH_NEW_ANA_HPH3 0x3102
+#define WCD937X_SLEEP_CTL 0x3103
+#define WCD937X_SLEEP_WATCHDOG_CTL 0x3104
+#define WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL 0x311F
+#define WCD937X_MBHC_NEW_CTL_1 0x3120
+#define WCD937X_MBHC_CTL_RCO_EN_MASK BIT(7)
+#define WCD937X_MBHC_CTL_RCO_EN BIT(7)
+#define WCD937X_MBHC_BTN_DBNC_MASK GENMASK(1, 0)
+#define WCD937X_MBHC_BTN_DBNC_T_16_MS 0x2
+#define WCD937X_MBHC_NEW_CTL_2 0x3121
+#define WCD937X_MBHC_NEW_PLUG_DETECT_CTL 0x3122
+#define WCD937X_MBHC_NEW_ZDET_ANA_CTL 0x3123
+#define WCD937X_M_RTH_CTL_MASK GENMASK(3, 2)
+#define WCD937X_MBHC_HS_VREF_CTL_MASK GENMASK(1, 0)
+#define WCD937X_MBHC_HS_VREF_1P5_V 0x1
+#define WCD937X_MBHC_DBNC_TIMER_INSREM_DBNC_T_96_MS 0x6
+#define WCD937X_ZDET_RANGE_CTL_MASK GENMASK(3, 0)
+#define WCD937X_ZDET_MAXV_CTL_MASK GENMASK(6, 4)
+#define WCD937X_MBHC_NEW_ZDET_RAMP_CTL 0x3124
+#define WCD937X_MBHC_NEW_FSM_STATUS 0x3125
+#define WCD937X_MBHC_NEW_ADC_RESULT 0x3126
+#define WCD937X_TX_NEW_TX_CH2_SEL 0x3127
+#define WCD937X_AUX_AUXPA 0x3128
+#define WCD937X_AUXPA_CLK_EN_MASK BIT(4)
+#define WCD937X_AUXPA_CLK_EN_MASK BIT(4)
+#define WCD937X_LDORXTX_MODE 0x3129
+#define WCD937X_LDORXTX_CONFIG 0x312A
+#define WCD937X_DIE_CRACK_DIE_CRK_DET_EN 0x312C
+#define WCD937X_DIE_CRACK_DIE_CRK_DET_OUT 0x312D
+#define WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL 0x3132
+#define WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L 0x3133
+#define WCD937X_HPH_NEW_INT_RDAC_VREF_CTL 0x3134
+#define WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL 0x3135
+#define WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R 0x3136
+#define WCD937X_HPH_NEW_INT_PA_MISC1 0x3137
+#define WCD937X_HPH_NEW_INT_PA_MISC2 0x3138
+#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC 0x3139
+#define WCD937X_HPH_NEW_INT_HPH_TIMER1 0x313A
+#define WCD937X_HPH_NEW_INT_HPH_TIMER2 0x313B
+#define WCD937X_HPH_NEW_INT_HPH_TIMER3 0x313C
+#define WCD937X_HPH_NEW_INT_HPH_TIMER4 0x313D
+#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC2 0x313E
+#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC3 0x313F
+#define WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI 0x3145
+#define WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP 0x3146
+#define WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP 0x3147
+#define WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL 0x31AF
+#define WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL 0x31B0
+#define WCD937X_MOISTURE_EN_POLLING_MASK BIT(2)
+#define WCD937X_HSDET_PULLUP_C_MASK GENMASK(4, 0)
+#define WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT 0x31B1
+#define WCD937X_MBHC_NEW_INT_SPARE_2 0x31B2
+#define WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON 0x31B7
+#define WCD937X_EAR_INT_NEW_CNP_VCM_CON1 0x31B8
+#define WCD937X_EAR_INT_NEW_CNP_VCM_CON2 0x31B9
+#define WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS 0x31BA
+#define WCD937X_AUX_INT_EN_REG 0x31BD
+#define WCD937X_AUX_INT_PA_CTRL 0x31BE
+#define WCD937X_AUX_INT_SP_CTRL 0x31BF
+#define WCD937X_AUX_INT_DAC_CTRL 0x31C0
+#define WCD937X_AUX_INT_CLK_CTRL 0x31C1
+#define WCD937X_AUX_INT_TEST_CTRL 0x31C2
+#define WCD937X_AUX_INT_STATUS_REG 0x31C3
+#define WCD937X_AUX_INT_MISC 0x31C4
+#define WCD937X_LDORXTX_INT_BIAS 0x31C5
+#define WCD937X_LDORXTX_INT_STB_LOADS_DTEST 0x31C6
+#define WCD937X_LDORXTX_INT_TEST0 0x31C7
+#define WCD937X_LDORXTX_INT_STARTUP_TIMER 0x31C8
+#define WCD937X_LDORXTX_INT_TEST1 0x31C9
+#define WCD937X_LDORXTX_INT_STATUS 0x31CA
+#define WCD937X_SLEEP_INT_WATCHDOG_CTL_1 0x31D0
+#define WCD937X_SLEEP_INT_WATCHDOG_CTL_2 0x31D1
+#define WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1 0x31D3
+#define WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2 0x31D4
+#define WCD937X_DIGITAL_PAGE_REGISTER 0x3400
+#define WCD937X_DIGITAL_CHIP_ID0 0x3401
+#define WCD937X_DIGITAL_CHIP_ID1 0x3402
+#define WCD937X_DIGITAL_CHIP_ID2 0x3403
+#define WCD937X_DIGITAL_CHIP_ID3 0x3404
+#define WCD937X_DIGITAL_CDC_RST_CTL 0x3406
+#define WCD937X_DIGITAL_TOP_CLK_CFG 0x3407
+#define WCD937X_DIGITAL_CDC_ANA_CLK_CTL 0x3408
+#define WCD937X_DIGITAL_CDC_DIG_CLK_CTL 0x3409
+#define WCD937X_DIGITAL_SWR_RST_EN 0x340A
+#define WCD937X_DIGITAL_CDC_PATH_MODE 0x340B
+#define WCD937X_DIGITAL_CDC_RX_RST 0x340C
+#define WCD937X_DIGITAL_CDC_RX0_CTL 0x340D
+#define WCD937X_DIGITAL_CDC_RX1_CTL 0x340E
+#define WCD937X_DIGITAL_CDC_RX2_CTL 0x340F
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA0 0x3410
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA1 0x3411
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA2 0x3412
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA3 0x3413
+#define WCD937X_DIGITAL_CDC_COMP_CTL_0 0x3414
+#define WCD937X_DIGITAL_CDC_RX_DELAY_CTL 0x3417
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A1_0 0x3418
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A1_1 0x3419
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A2_0 0x341A
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A2_1 0x341B
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A3_0 0x341C
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A3_1 0x341D
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A4_0 0x341E
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A4_1 0x341F
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A5_0 0x3420
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A5_1 0x3421
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A6_0 0x3422
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A7_0 0x3423
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_0 0x3424
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_1 0x3425
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_2 0x3426
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_3 0x3427
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R1 0x3428
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R2 0x3429
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R3 0x342A
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R4 0x342B
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R5 0x342C
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R6 0x342D
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R7 0x342E
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A1_0 0x342F
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A1_1 0x3430
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A2_0 0x3431
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A2_1 0x3432
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A3_0 0x3433
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A3_1 0x3434
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A4_0 0x3435
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A4_1 0x3436
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A5_0 0x3437
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A5_1 0x3438
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A6_0 0x3439
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A7_0 0x343A
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_0 0x343B
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_1 0x343C
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_2 0x343D
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_3 0x343E
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R1 0x343F
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R2 0x3440
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R3 0x3441
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R4 0x3442
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R5 0x3443
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R6 0x3444
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R7 0x3445
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0 0x3446
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1 0x3447
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0 0x3448
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1 0x3449
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2 0x344A
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0 0x344B
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1 0x344C
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2 0x344D
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_CTL 0x344E
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_CTL 0x344F
+#define WCD937X_DIGITAL_CDC_EAR_PATH_CTL 0x3450
+#define WCD937X_DIGITAL_CDC_SWR_CLH 0x3451
+#define WCD937X_DIGITAL_SWR_CLH_BYP 0x3452
+#define WCD937X_DIGITAL_CDC_TX0_CTL 0x3453
+#define WCD937X_DIGITAL_CDC_TX1_CTL 0x3454
+#define WCD937X_DIGITAL_CDC_TX2_CTL 0x3455
+#define WCD937X_DIGITAL_CDC_TX_RST 0x3456
+#define WCD937X_DIGITAL_CDC_REQ_CTL 0x3457
+#define WCD937X_DIGITAL_CDC_AMIC_CTL 0x345A
+#define WCD937X_DIGITAL_CDC_DMIC_CTL 0x345B
+#define WCD937X_DIGITAL_CDC_DMIC1_CTL 0x345C
+#define WCD937X_DIGITAL_CDC_DMIC2_CTL 0x345D
+#define WCD937X_DIGITAL_CDC_DMIC3_CTL 0x345E
+#define WCD937X_DIGITAL_EFUSE_CTL 0x345F
+#define WCD937X_DIGITAL_EFUSE_PRG_CTL 0x3460
+#define WCD937X_DIGITAL_EFUSE_TEST_CTL_0 0x3461
+#define WCD937X_DIGITAL_EFUSE_TEST_CTL_1 0x3462
+#define WCD937X_DIGITAL_EFUSE_T_DATA_0 0x3463
+#define WCD937X_DIGITAL_EFUSE_T_DATA_1 0x3464
+#define WCD937X_DIGITAL_PDM_WD_CTL0 0x3465
+#define WCD937X_DIGITAL_PDM_WD_CTL1 0x3466
+#define WCD937X_DIGITAL_PDM_WD_CTL2 0x3467
+#define WCD937X_DIGITAL_INTR_MODE 0x346A
+#define WCD937X_DIGITAL_INTR_MASK_0 0x346B
+#define WCD937X_DIGITAL_INTR_MASK_1 0x346C
+#define WCD937X_DIGITAL_INTR_MASK_2 0x346D
+#define WCD937X_DIGITAL_INTR_STATUS_0 0x346E
+#define WCD937X_DIGITAL_INTR_STATUS_1 0x346F
+#define WCD937X_DIGITAL_INTR_STATUS_2 0x3470
+#define WCD937X_DIGITAL_INTR_CLEAR_0 0x3471
+#define WCD937X_DIGITAL_INTR_CLEAR_1 0x3472
+#define WCD937X_DIGITAL_INTR_CLEAR_2 0x3473
+#define WCD937X_DIGITAL_INTR_LEVEL_0 0x3474
+#define WCD937X_DIGITAL_INTR_LEVEL_1 0x3475
+#define WCD937X_DIGITAL_INTR_LEVEL_2 0x3476
+#define WCD937X_DIGITAL_INTR_SET_0 0x3477
+#define WCD937X_DIGITAL_INTR_SET_1 0x3478
+#define WCD937X_DIGITAL_INTR_SET_2 0x3479
+#define WCD937X_DIGITAL_INTR_TEST_0 0x347A
+#define WCD937X_DIGITAL_INTR_TEST_1 0x347B
+#define WCD937X_DIGITAL_INTR_TEST_2 0x347C
+#define WCD937X_DIGITAL_CDC_CONN_RX0_CTL 0x347F
+#define WCD937X_DIGITAL_CDC_CONN_RX1_CTL 0x3480
+#define WCD937X_DIGITAL_CDC_CONN_RX2_CTL 0x3481
+#define WCD937X_DIGITAL_CDC_CONN_TX_CTL 0x3482
+#define WCD937X_DIGITAL_LOOP_BACK_MODE 0x3483
+#define WCD937X_DIGITAL_SWR_DAC_TEST 0x3484
+#define WCD937X_DIGITAL_SWR_HM_TEST_RX_0 0x3485
+#define WCD937X_DIGITAL_SWR_HM_TEST_TX_0 0x3491
+#define WCD937X_DIGITAL_SWR_HM_TEST_RX_1 0x3492
+#define WCD937X_DIGITAL_SWR_HM_TEST_TX_1 0x3493
+#define WCD937X_DIGITAL_SWR_HM_TEST 0x3494
+#define WCD937X_DIGITAL_PAD_CTL_PDM_RX0 0x3495
+#define WCD937X_DIGITAL_PAD_CTL_PDM_RX1 0x3496
+#define WCD937X_DIGITAL_PAD_CTL_PDM_TX0 0x3497
+#define WCD937X_DIGITAL_PAD_CTL_PDM_TX1 0x3498
+#define WCD937X_DIGITAL_PAD_INP_DIS_0 0x3499
+#define WCD937X_DIGITAL_PAD_INP_DIS_1 0x349A
+#define WCD937X_DIGITAL_DRIVE_STRENGTH_0 0x349B
+#define WCD937X_DIGITAL_DRIVE_STRENGTH_1 0x349C
+#define WCD937X_DIGITAL_DRIVE_STRENGTH_2 0x349D
+#define WCD937X_DIGITAL_RX_DATA_EDGE_CTL 0x349E
+#define WCD937X_DIGITAL_TX_DATA_EDGE_CTL 0x349F
+#define WCD937X_DIGITAL_GPIO_MODE 0x34A0
+#define WCD937X_DIGITAL_PIN_CTL_OE 0x34A1
+#define WCD937X_DIGITAL_PIN_CTL_DATA_0 0x34A2
+#define WCD937X_DIGITAL_PIN_CTL_DATA_1 0x34A3
+#define WCD937X_DIGITAL_PIN_STATUS_0 0x34A4
+#define WCD937X_DIGITAL_PIN_STATUS_1 0x34A5
+#define WCD937X_DIGITAL_DIG_DEBUG_CTL 0x34A6
+#define WCD937X_DIGITAL_DIG_DEBUG_EN 0x34A7
+#define WCD937X_DIGITAL_ANA_CSR_DBG_ADD 0x34A8
+#define WCD937X_DIGITAL_ANA_CSR_DBG_CTL 0x34A9
+#define WCD937X_DIGITAL_SSP_DBG 0x34AA
+#define WCD937X_DIGITAL_MODE_STATUS_0 0x34AB
+#define WCD937X_DIGITAL_MODE_STATUS_1 0x34AC
+#define WCD937X_DIGITAL_SPARE_0 0x34AD
+#define WCD937X_DIGITAL_SPARE_1 0x34AE
+#define WCD937X_DIGITAL_SPARE_2 0x34AF
+#define WCD937X_DIGITAL_EFUSE_REG_0 0x34B0
+#define WCD937X_DIGITAL_EFUSE_REG_1 0x34B1
+#define WCD937X_DIGITAL_EFUSE_REG_2 0x34B2
+#define WCD937X_DIGITAL_EFUSE_REG_3 0x34B3
+#define WCD937X_DIGITAL_EFUSE_REG_4 0x34B4
+#define WCD937X_DIGITAL_EFUSE_REG_5 0x34B5
+#define WCD937X_DIGITAL_EFUSE_REG_6 0x34B6
+#define WCD937X_DIGITAL_EFUSE_REG_7 0x34B7
+#define WCD937X_DIGITAL_EFUSE_REG_8 0x34B8
+#define WCD937X_DIGITAL_EFUSE_REG_9 0x34B9
+#define WCD937X_DIGITAL_EFUSE_REG_10 0x34BA
+#define WCD937X_DIGITAL_EFUSE_REG_11 0x34BB
+#define WCD937X_DIGITAL_EFUSE_REG_12 0x34BC
+#define WCD937X_DIGITAL_EFUSE_REG_13 0x34BD
+#define WCD937X_DIGITAL_EFUSE_REG_14 0x34BE
+#define WCD937X_DIGITAL_EFUSE_REG_15 0x34BF
+#define WCD937X_DIGITAL_EFUSE_REG_16 0x34C0
+#define WCD937X_DIGITAL_EFUSE_REG_17 0x34C1
+#define WCD937X_DIGITAL_EFUSE_REG_18 0x34C2
+#define WCD937X_DIGITAL_EFUSE_REG_19 0x34C3
+#define WCD937X_DIGITAL_EFUSE_REG_20 0x34C4
+#define WCD937X_DIGITAL_EFUSE_REG_21 0x34C5
+#define WCD937X_DIGITAL_EFUSE_REG_22 0x34C6
+#define WCD937X_DIGITAL_EFUSE_REG_23 0x34C7
+#define WCD937X_DIGITAL_EFUSE_REG_24 0x34C8
+#define WCD937X_DIGITAL_EFUSE_REG_25 0x34C9
+#define WCD937X_DIGITAL_EFUSE_REG_26 0x34CA
+#define WCD937X_DIGITAL_EFUSE_REG_27 0x34CB
+#define WCD937X_DIGITAL_EFUSE_REG_28 0x34CC
+#define WCD937X_DIGITAL_EFUSE_REG_29 0x34CD
+#define WCD937X_DIGITAL_EFUSE_REG_30 0x34CE
+#define WCD937X_DIGITAL_EFUSE_REG_31 0x34CF
+#define WCD937X_MAX_REGISTER (WCD937X_DIGITAL_EFUSE_REG_31)
+
+#define WCD937X_MAX_MICBIAS 3
+#define WCD937X_MAX_BULK_SUPPLY 4
+#define WCD937X_MAX_TX_SWR_PORTS 4
+#define WCD937X_MAX_SWR_PORTS 5
+#define WCD937X_MAX_SWR_CH_IDS 15
+
+struct wcd937x_sdw_ch_info {
+ int port_num;
+ unsigned int ch_mask;
+};
+
+#define WCD_SDW_CH(id, pn, cmask) \
+ [id] = { \
+ .port_num = pn, \
+ .ch_mask = cmask, \
+ }
+
+struct wcd937x_priv;
+struct wcd937x_sdw_priv {
+ struct sdw_slave *sdev;
+ struct sdw_stream_config sconfig;
+ struct sdw_stream_runtime *sruntime;
+ struct sdw_port_config port_config[WCD937X_MAX_SWR_PORTS];
+ const struct wcd937x_sdw_ch_info *ch_info;
+ bool port_enable[WCD937X_MAX_SWR_CH_IDS];
+ int active_ports;
+ bool is_tx;
+ struct wcd937x_priv *wcd937x;
+ struct irq_domain *slave_irq;
+ struct regmap *regmap;
+};
+
+#if IS_ENABLED(CONFIG_SND_SOC_WCD937X_SDW)
+int wcd937x_sdw_free(struct wcd937x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+int wcd937x_sdw_set_sdw_stream(struct wcd937x_sdw_priv *wcd,
+ struct snd_soc_dai *dai,
+ void *stream, int direction);
+int wcd937x_sdw_hw_params(struct wcd937x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai);
+
+struct device *wcd937x_sdw_device_get(struct device_node *np);
+
+#else
+int wcd937x_sdw_free(struct wcd937x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ return -EOPNOTSUPP;
+}
+
+int wcd937x_sdw_set_sdw_stream(struct wcd937x_sdw_priv *wcd,
+ struct snd_soc_dai *dai,
+ void *stream, int direction)
+{
+ return -EOPNOTSUPP;
+}
+
+int wcd937x_sdw_hw_params(struct wcd937x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
+enum {
+ /* INTR_CTRL_INT_MASK_0 */
+ WCD937X_IRQ_MBHC_BUTTON_PRESS_DET = 0,
+ WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET,
+ WCD937X_IRQ_MBHC_ELECT_INS_REM_DET,
+ WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+ WCD937X_IRQ_MBHC_SW_DET,
+ WCD937X_IRQ_HPHR_OCP_INT,
+ WCD937X_IRQ_HPHR_CNP_INT,
+ WCD937X_IRQ_HPHL_OCP_INT,
+
+ /* INTR_CTRL_INT_MASK_1 */
+ WCD937X_IRQ_HPHL_CNP_INT,
+ WCD937X_IRQ_EAR_CNP_INT,
+ WCD937X_IRQ_EAR_SCD_INT,
+ WCD937X_IRQ_AUX_CNP_INT,
+ WCD937X_IRQ_AUX_SCD_INT,
+ WCD937X_IRQ_HPHL_PDM_WD_INT,
+ WCD937X_IRQ_HPHR_PDM_WD_INT,
+ WCD937X_IRQ_AUX_PDM_WD_INT,
+
+ /* INTR_CTRL_INT_MASK_2 */
+ WCD937X_IRQ_LDORT_SCD_INT,
+ WCD937X_IRQ_MBHC_MOISTURE_INT,
+ WCD937X_IRQ_HPHL_SURGE_DET_INT,
+ WCD937X_IRQ_HPHR_SURGE_DET_INT,
+ WCD937X_NUM_IRQS,
+};
+
+enum wcd937x_tx_sdw_ports {
+ WCD937X_ADC_1_PORT = 1,
+ WCD937X_ADC_2_3_PORT,
+ WCD937X_DMIC_0_3_MBHC_PORT,
+ WCD937X_DMIC_4_6_PORT,
+};
+
+enum wcd937x_tx_sdw_channels {
+ WCD937X_ADC1,
+ WCD937X_ADC2,
+ WCD937X_ADC3,
+ WCD937X_DMIC0,
+ WCD937X_DMIC1,
+ WCD937X_MBHC,
+ WCD937X_DMIC2,
+ WCD937X_DMIC3,
+ WCD937X_DMIC4,
+ WCD937X_DMIC5,
+ WCD937X_DMIC6,
+};
+
+enum wcd937x_rx_sdw_ports {
+ WCD937X_HPH_PORT = 1,
+ WCD937X_CLSH_PORT,
+ WCD937X_COMP_PORT,
+ WCD937X_LO_PORT,
+ WCD937X_DSD_PORT,
+};
+
+enum wcd937x_rx_sdw_channels {
+ WCD937X_HPH_L,
+ WCD937X_HPH_R,
+ WCD937X_CLSH,
+ WCD937X_COMP_L,
+ WCD937X_COMP_R,
+ WCD937X_LO,
+ WCD937X_DSD_R,
+ WCD937X_DSD_L,
+};
+
+#endif
diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c
index a1f04010da95..c995bcc59ead 100644
--- a/sound/soc/codecs/wcd938x-sdw.c
+++ b/sound/soc/codecs/wcd938x-sdw.c
@@ -21,7 +21,7 @@
#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m))
-static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = {
+static const struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = {
WCD_SDW_CH(WCD938X_HPH_L, WCD938X_HPH_PORT, BIT(0)),
WCD_SDW_CH(WCD938X_HPH_R, WCD938X_HPH_PORT, BIT(1)),
WCD_SDW_CH(WCD938X_CLSH, WCD938X_CLSH_PORT, BIT(0)),
@@ -32,7 +32,7 @@ static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = {
WCD_SDW_CH(WCD938X_DSD_R, WCD938X_DSD_PORT, BIT(1)),
};
-static struct wcd938x_sdw_ch_info wcd938x_sdw_tx_ch_info[] = {
+static const struct wcd938x_sdw_ch_info wcd938x_sdw_tx_ch_info[] = {
WCD_SDW_CH(WCD938X_ADC1, WCD938X_ADC_1_2_PORT, BIT(0)),
WCD_SDW_CH(WCD938X_ADC2, WCD938X_ADC_1_2_PORT, BIT(1)),
WCD_SDW_CH(WCD938X_ADC3, WCD938X_ADC_3_4_PORT, BIT(0)),
diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index 6021aa5a5689..12b32d5dc580 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -206,7 +206,6 @@ struct wcd938x_priv {
bool comp1_enable;
bool comp2_enable;
bool ldoh;
- bool bcs_dis;
};
static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800);
@@ -222,7 +221,7 @@ struct wcd938x_mbhc_zdet_param {
u16 btn7;
};
-static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD938X_ANA_MBHC_MECH, 0x80),
WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD938X_ANA_MBHC_MECH, 0x40),
WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD938X_ANA_MBHC_MECH, 0x20),
@@ -419,7 +418,7 @@ static int wcd938x_io_init(struct wcd938x_priv *wcd938x)
}
-static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info,
+static int wcd938x_sdw_connect_port(const struct wcd938x_sdw_ch_info *ch_info,
struct sdw_port_config *port_config,
u8 enable)
{
@@ -1650,31 +1649,6 @@ static int wcd938x_ldoh_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static int wcd938x_bcs_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
-
- ucontrol->value.integer.value[0] = wcd938x->bcs_dis;
-
- return 0;
-}
-
-static int wcd938x_bcs_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
-
- if (wcd938x->bcs_dis == ucontrol->value.integer.value[0])
- return 0;
-
- wcd938x->bcs_dis = ucontrol->value.integer.value[0];
-
- return 1;
-}
-
static const char * const tx_mode_mux_text_wcd9380[] = {
"ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP",
};
@@ -1982,7 +1956,7 @@ static bool wcd938x_mbhc_micb_en_status(struct snd_soc_component *component, int
if (micb_num == MIC_BIAS_2) {
val = snd_soc_component_read_field(component,
WCD938X_ANA_MICB2,
- WCD938X_ANA_MICB2_ENABLE_MASK);
+ WCD938X_MICB_EN_MASK);
if (val == WCD938X_MICB_ENABLE)
return true;
}
@@ -2695,8 +2669,6 @@ static const struct snd_kcontrol_new wcd938x_snd_controls[] = {
wcd938x_get_swr_port, wcd938x_set_swr_port),
SOC_SINGLE_EXT("LDOH Enable Switch", SND_SOC_NOPM, 0, 1, 0,
wcd938x_ldoh_get, wcd938x_ldoh_put),
- SOC_SINGLE_EXT("ADC2_BCS Disable Switch", SND_SOC_NOPM, 0, 1, 0,
- wcd938x_bcs_get, wcd938x_bcs_put),
SOC_SINGLE_TLV("ADC1 Volume", WCD938X_ANA_TX_CH1, 0, 20, 0, analog_gain),
SOC_SINGLE_TLV("ADC2 Volume", WCD938X_ANA_TX_CH2, 0, 20, 0, analog_gain),
@@ -3055,7 +3027,7 @@ static irqreturn_t wcd938x_wd_handle_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static struct irq_chip wcd_irq_chip = {
+static const struct irq_chip wcd_irq_chip = {
.name = "WCD938x",
};
diff --git a/sound/soc/codecs/wcd938x.h b/sound/soc/codecs/wcd938x.h
index 74b1498fec38..b2ad98026ae2 100644
--- a/sound/soc/codecs/wcd938x.h
+++ b/sound/soc/codecs/wcd938x.h
@@ -75,9 +75,6 @@
#define WCD938X_MICB_PULL_UP 2
#define WCD938X_MICB_PULL_DOWN 3
#define WCD938X_ANA_MICB2 (0x3023)
-#define WCD938X_ANA_MICB2_ENABLE BIT(6)
-#define WCD938X_ANA_MICB2_ENABLE_MASK GENMASK(7, 6)
-#define WCD938X_ANA_MICB2_VOUT_MASK GENMASK(5, 0)
#define WCD938X_ANA_MICB2_RAMP (0x3024)
#define WCD938X_RAMP_EN_MASK BIT(7)
#define WCD938X_RAMP_SHIFT_CTRL_MASK GENMASK(4, 2)
@@ -645,10 +642,6 @@ enum wcd938x_rx_sdw_channels {
WCD938X_DSD_R,
WCD938X_DSD_L,
};
-enum {
- WCD938X_SDW_DIR_RX,
- WCD938X_SDW_DIR_TX,
-};
struct wcd938x_priv;
struct wcd938x_sdw_priv {
@@ -656,10 +649,9 @@ struct wcd938x_sdw_priv {
struct sdw_stream_config sconfig;
struct sdw_stream_runtime *sruntime;
struct sdw_port_config port_config[WCD938X_MAX_SWR_PORTS];
- struct wcd938x_sdw_ch_info *ch_info;
+ const struct wcd938x_sdw_ch_info *ch_info;
bool port_enable[WCD938X_MAX_SWR_CH_IDS];
int active_ports;
- int num_ports;
bool is_tx;
struct wcd938x_priv *wcd938x;
struct irq_domain *slave_irq;
diff --git a/sound/soc/codecs/wcd939x-sdw.c b/sound/soc/codecs/wcd939x-sdw.c
index 8acb5651c5bc..94b1e99a3ca0 100644
--- a/sound/soc/codecs/wcd939x-sdw.c
+++ b/sound/soc/codecs/wcd939x-sdw.c
@@ -23,7 +23,7 @@
#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m))
-static struct wcd939x_sdw_ch_info wcd939x_sdw_rx_ch_info[] = {
+static const struct wcd939x_sdw_ch_info wcd939x_sdw_rx_ch_info[] = {
WCD_SDW_CH(WCD939X_HPH_L, WCD939X_HPH_PORT, BIT(0)),
WCD_SDW_CH(WCD939X_HPH_R, WCD939X_HPH_PORT, BIT(1)),
WCD_SDW_CH(WCD939X_CLSH, WCD939X_CLSH_PORT, BIT(0)),
@@ -36,7 +36,7 @@ static struct wcd939x_sdw_ch_info wcd939x_sdw_rx_ch_info[] = {
WCD_SDW_CH(WCD939X_HIFI_PCM_R, WCD939X_HIFI_PCM_PORT, BIT(1)),
};
-static struct wcd939x_sdw_ch_info wcd939x_sdw_tx_ch_info[] = {
+static const struct wcd939x_sdw_ch_info wcd939x_sdw_tx_ch_info[] = {
WCD_SDW_CH(WCD939X_ADC1, WCD939X_ADC_1_4_PORT, BIT(0)),
WCD_SDW_CH(WCD939X_ADC2, WCD939X_ADC_1_4_PORT, BIT(1)),
WCD_SDW_CH(WCD939X_ADC3, WCD939X_ADC_1_4_PORT, BIT(2)),
diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c
index c49894aad8a5..68fc591670dc 100644
--- a/sound/soc/codecs/wcd939x.c
+++ b/sound/soc/codecs/wcd939x.c
@@ -85,7 +85,6 @@ enum {
#define WCD939X_MBHC_GET_X1(x) ((x) & 0x3FFF)
/* Z value compared in milliOhm */
-#define WCD939X_MBHC_IS_SECOND_RAMP_REQUIRED(z) false
#define WCD939X_ANA_MBHC_ZDET_CONST (1018 * 1024)
enum {
@@ -182,8 +181,6 @@ struct wcd939x_priv {
/* typec handling */
bool typec_analog_mux;
#if IS_ENABLED(CONFIG_TYPEC)
- struct typec_mux_dev *typec_mux;
- struct typec_switch_dev *typec_sw;
enum typec_orientation typec_orientation;
unsigned long typec_mode;
struct typec_switch *typec_switch;
@@ -221,7 +218,7 @@ static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800);
static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
-static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD939X_ANA_MBHC_MECH, 0x80),
WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD939X_ANA_MBHC_MECH, 0x40),
WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD939X_ANA_MBHC_MECH, 0x20),
@@ -292,7 +289,7 @@ static const struct regmap_irq wcd939x_irqs[WCD939X_NUM_IRQS] = {
REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08),
};
-static struct regmap_irq_chip wcd939x_regmap_irq_chip = {
+static const struct regmap_irq_chip wcd939x_regmap_irq_chip = {
.name = "wcd939x",
.irqs = wcd939x_irqs,
.num_irqs = ARRAY_SIZE(wcd939x_irqs),
@@ -415,7 +412,7 @@ static int wcd939x_io_init(struct snd_soc_component *component)
return 0;
}
-static int wcd939x_sdw_connect_port(struct wcd939x_sdw_ch_info *ch_info,
+static int wcd939x_sdw_connect_port(const struct wcd939x_sdw_ch_info *ch_info,
struct sdw_port_config *port_config,
u8 enable)
{
@@ -525,7 +522,7 @@ static int wcd939x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
WCD939X_DIGITAL_CDC_COMP_CTL_0,
WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN,
true);
- /* 5msec compander delay as per HW requirement */
+ /* 5msec compander delay as per HW requirement */
if (!wcd939x->comp2_enable ||
snd_soc_component_read_field(component,
WCD939X_DIGITAL_CDC_COMP_CTL_0,
@@ -1268,25 +1265,20 @@ static int wcd939x_micbias_control(struct snd_soc_component *component,
{
struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
int micb_index = micb_num - 1;
- u16 micb_field;
u16 micb_reg;
switch (micb_num) {
case MIC_BIAS_1:
micb_reg = WCD939X_ANA_MICB1;
- micb_field = WCD939X_MICB1_ENABLE;
break;
case MIC_BIAS_2:
micb_reg = WCD939X_ANA_MICB2;
- micb_field = WCD939X_MICB2_ENABLE;
break;
case MIC_BIAS_3:
micb_reg = WCD939X_ANA_MICB3;
- micb_field = WCD939X_MICB3_ENABLE;
break;
case MIC_BIAS_4:
micb_reg = WCD939X_ANA_MICB4;
- micb_field = WCD939X_MICB4_ENABLE;
break;
default:
dev_err(component->dev, "%s: Invalid micbias number: %d\n",
@@ -1300,7 +1292,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component,
if (wcd939x->pullup_ref[micb_index] == 1 &&
wcd939x->micb_ref[micb_index] == 0)
snd_soc_component_write_field(component, micb_reg,
- micb_field, MICB_BIAS_PULL_UP);
+ WCD939X_MICB_ENABLE,
+ MICB_BIAS_PULL_UP);
break;
case MICB_PULLUP_DISABLE:
if (wcd939x->pullup_ref[micb_index] > 0)
@@ -1308,7 +1301,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component,
if (wcd939x->pullup_ref[micb_index] == 0 &&
wcd939x->micb_ref[micb_index] == 0)
snd_soc_component_write_field(component, micb_reg,
- micb_field, MICB_BIAS_DISABLE);
+ WCD939X_MICB_ENABLE,
+ MICB_BIAS_DISABLE);
break;
case MICB_ENABLE:
wcd939x->micb_ref[micb_index]++;
@@ -1345,7 +1339,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component,
snd_soc_component_write_field(component,
WCD939X_MICB4_TEST_CTL_2,
WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true);
- snd_soc_component_write_field(component, micb_reg, micb_field,
+ snd_soc_component_write_field(component, micb_reg,
+ WCD939X_MICB_ENABLE,
MICB_BIAS_ENABLE);
if (micb_num == MIC_BIAS_2)
wcd_mbhc_event_notify(wcd939x->wcd_mbhc,
@@ -1362,7 +1357,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component,
if (wcd939x->micb_ref[micb_index] == 0 &&
wcd939x->pullup_ref[micb_index] > 0)
snd_soc_component_write_field(component, micb_reg,
- micb_field, MICB_BIAS_PULL_UP);
+ WCD939X_MICB_ENABLE,
+ MICB_BIAS_PULL_UP);
else if (wcd939x->micb_ref[micb_index] == 0 &&
wcd939x->pullup_ref[micb_index] == 0) {
if (micb_num == MIC_BIAS_2)
@@ -1370,7 +1366,8 @@ static int wcd939x_micbias_control(struct snd_soc_component *component,
WCD_EVENT_PRE_MICBIAS_2_OFF);
snd_soc_component_write_field(component, micb_reg,
- micb_field, MICB_BIAS_DISABLE);
+ WCD939X_MICB_ENABLE,
+ MICB_BIAS_DISABLE);
if (micb_num == MIC_BIAS_2)
wcd_mbhc_event_notify(wcd939x->wcd_mbhc,
WCD_EVENT_POST_MICBIAS_2_OFF);
@@ -1869,11 +1866,10 @@ static void wcd939x_mbhc_program_btn_thr(struct snd_soc_component *component,
static bool wcd939x_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num)
{
-
if (micb_num == MIC_BIAS_2) {
u8 val;
- val = FIELD_GET(WCD939X_MICB2_ENABLE,
+ val = FIELD_GET(WCD939X_MICB_ENABLE,
snd_soc_component_read(component, WCD939X_ANA_MICB2));
if (val == MICB_BIAS_ENABLE)
return true;
@@ -1935,7 +1931,6 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
int req_volt, int micb_num)
{
struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
- unsigned int micb_en_field, micb_vout_ctl_field;
unsigned int micb_reg, cur_vout_ctl, micb_en;
int req_vout_ctl;
int ret = 0;
@@ -1943,23 +1938,15 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
switch (micb_num) {
case MIC_BIAS_1:
micb_reg = WCD939X_ANA_MICB1;
- micb_en_field = WCD939X_MICB1_ENABLE;
- micb_vout_ctl_field = WCD939X_MICB1_VOUT_CTL;
break;
case MIC_BIAS_2:
micb_reg = WCD939X_ANA_MICB2;
- micb_en_field = WCD939X_MICB2_ENABLE;
- micb_vout_ctl_field = WCD939X_MICB2_VOUT_CTL;
break;
case MIC_BIAS_3:
micb_reg = WCD939X_ANA_MICB3;
- micb_en_field = WCD939X_MICB3_ENABLE;
- micb_vout_ctl_field = WCD939X_MICB1_VOUT_CTL;
break;
case MIC_BIAS_4:
micb_reg = WCD939X_ANA_MICB4;
- micb_en_field = WCD939X_MICB4_ENABLE;
- micb_vout_ctl_field = WCD939X_MICB2_VOUT_CTL;
break;
default:
return -EINVAL;
@@ -1975,9 +1962,9 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
* micbias.
*/
micb_en = snd_soc_component_read_field(component, micb_reg,
- micb_en_field);
+ WCD939X_MICB_ENABLE);
cur_vout_ctl = snd_soc_component_read_field(component, micb_reg,
- micb_vout_ctl_field);
+ WCD939X_MICB_VOUT_CTL);
req_vout_ctl = wcd939x_get_micb_vout_ctl_val(req_volt);
if (req_vout_ctl < 0) {
@@ -1996,14 +1983,16 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
if (micb_en == MICB_BIAS_ENABLE)
snd_soc_component_write_field(component, micb_reg,
- micb_en_field, MICB_BIAS_PULL_DOWN);
+ WCD939X_MICB_ENABLE,
+ MICB_BIAS_PULL_DOWN);
snd_soc_component_write_field(component, micb_reg,
- micb_vout_ctl_field, req_vout_ctl);
+ WCD939X_MICB_VOUT_CTL, req_vout_ctl);
if (micb_en == MICB_BIAS_ENABLE) {
snd_soc_component_write_field(component, micb_reg,
- micb_en_field, MICB_BIAS_ENABLE);
+ WCD939X_MICB_ENABLE,
+ MICB_BIAS_ENABLE);
/*
* Add 2ms delay as per HW requirement after enabling
* micbias
@@ -2916,13 +2905,13 @@ static int wcd939x_set_micbias_data(struct wcd939x_priv *wcd939x)
return -EINVAL;
regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB1,
- WCD939X_MICB1_VOUT_CTL, vout_ctl_1);
+ WCD939X_MICB_VOUT_CTL, vout_ctl_1);
regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB2,
- WCD939X_MICB2_VOUT_CTL, vout_ctl_2);
+ WCD939X_MICB_VOUT_CTL, vout_ctl_2);
regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB3,
- WCD939X_MICB3_VOUT_CTL, vout_ctl_3);
+ WCD939X_MICB_VOUT_CTL, vout_ctl_3);
regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB4,
- WCD939X_MICB4_VOUT_CTL, vout_ctl_4);
+ WCD939X_MICB_VOUT_CTL, vout_ctl_4);
return 0;
}
@@ -2966,7 +2955,7 @@ static irqreturn_t wcd939x_wd_handle_irq(int irq, void *data)
* \- regmap_irq_thread()
* \- handle_nested_irq(i)
*/
-static struct irq_chip wcd_irq_chip = {
+static const struct irq_chip wcd_irq_chip = {
.name = "WCD939x",
};
@@ -3528,6 +3517,68 @@ static const struct component_master_ops wcd939x_comp_ops = {
.unbind = wcd939x_unbind,
};
+static void __maybe_unused wcd939x_typec_mux_unregister(void *data)
+{
+ struct typec_mux_dev *typec_mux = data;
+
+ typec_mux_unregister(typec_mux);
+}
+
+static void __maybe_unused wcd939x_typec_switch_unregister(void *data)
+{
+ struct typec_switch_dev *typec_sw = data;
+
+ typec_switch_unregister(typec_sw);
+}
+
+static int wcd939x_add_typec(struct wcd939x_priv *wcd939x, struct device *dev)
+{
+#if IS_ENABLED(CONFIG_TYPEC)
+ int ret;
+ struct typec_mux_dev *typec_mux;
+ struct typec_switch_dev *typec_sw;
+ struct typec_mux_desc mux_desc = {
+ .drvdata = wcd939x,
+ .fwnode = dev_fwnode(dev),
+ .set = wcd939x_typec_mux_set,
+ };
+ struct typec_switch_desc sw_desc = {
+ .drvdata = wcd939x,
+ .fwnode = dev_fwnode(dev),
+ .set = wcd939x_typec_switch_set,
+ };
+
+ /*
+ * Is USBSS is used to mux analog lines,
+ * register a typec mux/switch to get typec events
+ */
+ if (!wcd939x->typec_analog_mux)
+ return 0;
+
+ typec_mux = typec_mux_register(dev, &mux_desc);
+ if (IS_ERR(typec_mux))
+ return dev_err_probe(dev, PTR_ERR(typec_mux),
+ "failed to register typec mux\n");
+
+ ret = devm_add_action_or_reset(dev, wcd939x_typec_mux_unregister,
+ typec_mux);
+ if (ret)
+ return ret;
+
+ typec_sw = typec_switch_register(dev, &sw_desc);
+ if (IS_ERR(typec_sw))
+ return dev_err_probe(dev, PTR_ERR(typec_sw),
+ "failed to register typec switch\n");
+
+ ret = devm_add_action_or_reset(dev, wcd939x_typec_switch_unregister,
+ typec_sw);
+ if (ret)
+ return ret;
+#endif
+
+ return 0;
+}
+
static int wcd939x_add_slave_components(struct wcd939x_priv *wcd939x,
struct device *dev,
struct component_match **matchptr)
@@ -3576,42 +3627,13 @@ static int wcd939x_probe(struct platform_device *pdev)
return -EINVAL;
}
-#if IS_ENABLED(CONFIG_TYPEC)
- /*
- * Is USBSS is used to mux analog lines,
- * register a typec mux/switch to get typec events
- */
- if (wcd939x->typec_analog_mux) {
- struct typec_mux_desc mux_desc = {
- .drvdata = wcd939x,
- .fwnode = dev_fwnode(dev),
- .set = wcd939x_typec_mux_set,
- };
- struct typec_switch_desc sw_desc = {
- .drvdata = wcd939x,
- .fwnode = dev_fwnode(dev),
- .set = wcd939x_typec_switch_set,
- };
-
- wcd939x->typec_mux = typec_mux_register(dev, &mux_desc);
- if (IS_ERR(wcd939x->typec_mux)) {
- ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_mux),
- "failed to register typec mux\n");
- goto err_disable_regulators;
- }
-
- wcd939x->typec_sw = typec_switch_register(dev, &sw_desc);
- if (IS_ERR(wcd939x->typec_sw)) {
- ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_sw),
- "failed to register typec switch\n");
- goto err_unregister_typec_mux;
- }
- }
-#endif /* CONFIG_TYPEC */
+ ret = wcd939x_add_typec(wcd939x, dev);
+ if (ret)
+ goto err_disable_regulators;
ret = wcd939x_add_slave_components(wcd939x, dev, &match);
if (ret)
- goto err_unregister_typec_switch;
+ goto err_disable_regulators;
wcd939x_reset(wcd939x);
@@ -3628,18 +3650,6 @@ static int wcd939x_probe(struct platform_device *pdev)
return 0;
-#if IS_ENABLED(CONFIG_TYPEC)
-err_unregister_typec_mux:
- if (wcd939x->typec_analog_mux)
- typec_mux_unregister(wcd939x->typec_mux);
-#endif /* CONFIG_TYPEC */
-
-err_unregister_typec_switch:
-#if IS_ENABLED(CONFIG_TYPEC)
- if (wcd939x->typec_analog_mux)
- typec_switch_unregister(wcd939x->typec_sw);
-#endif /* CONFIG_TYPEC */
-
err_disable_regulators:
regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies);
regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies);
diff --git a/sound/soc/codecs/wcd939x.h b/sound/soc/codecs/wcd939x.h
index 807cf3113d20..1571c2120cfc 100644
--- a/sound/soc/codecs/wcd939x.h
+++ b/sound/soc/codecs/wcd939x.h
@@ -91,11 +91,9 @@
#define WCD939X_ANA_MBHC_BTN7 (0x3021)
#define WCD939X_MBHC_BTN7_VTH GENMASK(7, 2)
#define WCD939X_ANA_MICB1 (0x3022)
-#define WCD939X_MICB1_ENABLE GENMASK(7, 6)
-#define WCD939X_MICB1_VOUT_CTL GENMASK(5, 0)
+#define WCD939X_MICB_ENABLE GENMASK(7, 6)
+#define WCD939X_MICB_VOUT_CTL GENMASK(5, 0)
#define WCD939X_ANA_MICB2 (0x3023)
-#define WCD939X_MICB2_ENABLE GENMASK(7, 6)
-#define WCD939X_MICB2_VOUT_CTL GENMASK(5, 0)
#define WCD939X_ANA_MICB2_RAMP (0x3024)
#define WCD939X_MICB2_RAMP_RAMP_ENABLE BIT(7)
#define WCD939X_MICB2_RAMP_MB2_IN2P_SHORT_ENABLE BIT(6)
@@ -103,11 +101,7 @@
#define WCD939X_MICB2_RAMP_SHIFT_CTL GENMASK(4, 2)
#define WCD939X_MICB2_RAMP_USB_MGDET_MICB2_RAMP GENMASK(1, 0)
#define WCD939X_ANA_MICB3 (0x3025)
-#define WCD939X_MICB3_ENABLE GENMASK(7, 6)
-#define WCD939X_MICB3_VOUT_CTL GENMASK(5, 0)
#define WCD939X_ANA_MICB4 (0x3026)
-#define WCD939X_MICB4_ENABLE GENMASK(7, 6)
-#define WCD939X_MICB4_VOUT_CTL GENMASK(5, 0)
#define WCD939X_BIAS_CTL (0x3028)
#define WCD939X_BIAS_VBG_FINE_ADJ (0x3029)
#define WCD939X_LDOL_VDDCX_ADJUST (0x3040)
@@ -909,21 +903,15 @@ enum wcd939x_rx_sdw_channels {
WCD939X_HIFI_PCM_R,
};
-enum {
- WCD939X_SDW_DIR_RX,
- WCD939X_SDW_DIR_TX,
-};
-
struct wcd939x_priv;
struct wcd939x_sdw_priv {
struct sdw_slave *sdev;
struct sdw_stream_config sconfig;
struct sdw_stream_runtime *sruntime;
struct sdw_port_config port_config[WCD939X_MAX_SWR_PORTS];
- struct wcd939x_sdw_ch_info *ch_info;
+ const struct wcd939x_sdw_ch_info *ch_info;
bool port_enable[WCD939X_MAX_SWR_CH_IDS];
int active_ports;
- int num_ports;
bool is_tx;
struct wcd939x_priv *wcd939x;
struct irq_domain *slave_irq;
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index 8f862729a2ca..edd2cb185c42 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -115,14 +115,6 @@ struct wm0010_priv {
struct completion boot_completion;
};
-struct wm0010_spi_msg {
- struct spi_message m;
- struct spi_transfer t;
- u8 *tx_buf;
- u8 *rx_buf;
- size_t len;
-};
-
static const struct snd_soc_dapm_widget wm0010_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("CLKIN", SND_SOC_NOPM, 0, 0, NULL, 0),
};
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 68d2d6444533..9f8549b34e30 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -601,7 +601,7 @@ static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl)
return -EINVAL;
}
- switch (cs_dsp->fw_ver) {
+ switch (cs_dsp->wmfw_ver) {
case 0:
case 1:
ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 1253695bebd8..0478599d0f35 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -634,7 +634,7 @@ static bool wsa881x_volatile_register(struct device *dev, unsigned int reg)
}
}
-static struct regmap_config wsa881x_regmap_config = {
+static const struct regmap_config wsa881x_regmap_config = {
.reg_bits = 32,
.val_bits = 8,
.cache_type = REGCACHE_MAPLE,
diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
index a2e86ef7d18f..d0ab4e2290b6 100644
--- a/sound/soc/codecs/wsa883x.c
+++ b/sound/soc/codecs/wsa883x.c
@@ -9,7 +9,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/printk.h>
#include <linux/regmap.h>
@@ -935,7 +934,7 @@ static bool wsa883x_volatile_register(struct device *dev, unsigned int reg)
return wsa883x_readonly_register(dev, reg);
}
-static struct regmap_config wsa883x_regmap_config = {
+static const struct regmap_config wsa883x_regmap_config = {
.reg_bits = 32,
.val_bits = 8,
.cache_type = REGCACHE_MAPLE,
@@ -1399,6 +1398,14 @@ static int wsa883x_probe(struct sdw_slave *pdev,
wsa883x->sconfig.direction = SDW_DATA_DIR_RX;
wsa883x->sconfig.type = SDW_STREAM_PDM;
+ /**
+ * Port map index starts with 0, however the data port for this codec
+ * are from index 1
+ */
+ if (of_property_read_u32_array(dev->of_node, "qcom,port-mapping", &pdev->m_port_map[1],
+ WSA883X_MAX_SWR_PORTS))
+ dev_dbg(dev, "Static Port mapping not specified\n");
+
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;
diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c
index a9767ef0e39d..d17ae17b2938 100644
--- a/sound/soc/codecs/wsa884x.c
+++ b/sound/soc/codecs/wsa884x.c
@@ -1319,7 +1319,7 @@ static bool wsa884x_volatile_register(struct device *dev, unsigned int reg)
return wsa884x_readonly_register(dev, reg);
}
-static struct regmap_config wsa884x_regmap_config = {
+static const struct regmap_config wsa884x_regmap_config = {
.reg_bits = 32,
.val_bits = 8,
.cache_type = REGCACHE_MAPLE,
@@ -1887,6 +1887,14 @@ static int wsa884x_probe(struct sdw_slave *pdev,
wsa884x->sconfig.direction = SDW_DATA_DIR_RX;
wsa884x->sconfig.type = SDW_STREAM_PDM;
+ /**
+ * Port map index starts with 0, however the data port for this codec
+ * are from index 1
+ */
+ if (of_property_read_u32_array(dev->of_node, "qcom,port-mapping", &pdev->m_port_map[1],
+ WSA884X_MAX_SWR_PORTS))
+ dev_dbg(dev, "Static Port mapping not specified\n");
+
pdev->prop.sink_ports = GENMASK(WSA884X_MAX_SWR_PORTS, 0);
pdev->prop.simple_clk_stop_capable = true;
pdev->prop.sink_dpn_prop = wsa884x_sink_dpn_prop;