aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2021-04-23 19:01:02 +0100
committerMark Brown <broonie@kernel.org>2021-04-23 19:01:02 +0100
commitffc9841d5200a484ea0ecc645157b4d7b873f3a6 (patch)
treec5216df939963608cefcd94bdf2934a2b880b54d /sound/soc/codecs
parentMerge remote-tracking branch 'asoc/for-5.12' into asoc-linus (diff)
parentASoC: simple-card: Fix breakage on kontron-sl28-var3-ads2 (diff)
downloadlinux-dev-ffc9841d5200a484ea0ecc645157b4d7b873f3a6.tar.xz
linux-dev-ffc9841d5200a484ea0ecc645157b4d7b873f3a6.zip
Merge remote-tracking branch 'asoc/for-5.13' into asoc-next
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/Kconfig51
-rw-r--r--sound/soc/codecs/Makefile16
-rw-r--r--sound/soc/codecs/ab8500-codec.c7
-rw-r--r--sound/soc/codecs/ad1836.c2
-rw-r--r--sound/soc/codecs/adau1977.c2
-rw-r--r--sound/soc/codecs/ak4458.c66
-rw-r--r--sound/soc/codecs/ak4458.h1
-rw-r--r--sound/soc/codecs/ak5558.c122
-rw-r--r--sound/soc/codecs/arizona-jack.c1657
-rw-r--r--sound/soc/codecs/arizona.h46
-rw-r--r--sound/soc/codecs/cros_ec_codec.c2
-rw-r--r--sound/soc/codecs/cs35l35.c3
-rw-r--r--sound/soc/codecs/cs35l36.c2
-rw-r--r--sound/soc/codecs/cs4270.c1
-rw-r--r--sound/soc/codecs/cs42l42.c323
-rw-r--r--sound/soc/codecs/cs42l42.h28
-rw-r--r--sound/soc/codecs/cx2072x.c13
-rw-r--r--sound/soc/codecs/da7219-aad.c2
-rw-r--r--sound/soc/codecs/da7219.c5
-rw-r--r--sound/soc/codecs/da732x.c17
-rw-r--r--sound/soc/codecs/da732x.h12
-rw-r--r--sound/soc/codecs/hdac_hdmi.c14
-rw-r--r--sound/soc/codecs/hdac_hdmi.h2
-rw-r--r--sound/soc/codecs/hdmi-codec.c3
-rw-r--r--sound/soc/codecs/jz4760.c11
-rw-r--r--sound/soc/codecs/jz4770.c7
-rw-r--r--sound/soc/codecs/lm49453.c2
-rw-r--r--sound/soc/codecs/lpass-rx-macro.c7
-rw-r--r--sound/soc/codecs/lpass-tx-macro.c2
-rw-r--r--sound/soc/codecs/lpass-va-macro.c9
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.c15
-rw-r--r--sound/soc/codecs/madera.h2
-rw-r--r--sound/soc/codecs/max98090.c2
-rw-r--r--sound/soc/codecs/max98373.c14
-rw-r--r--sound/soc/codecs/max98373.h3
-rw-r--r--sound/soc/codecs/max98390.c62
-rw-r--r--sound/soc/codecs/max98390.h2
-rw-r--r--sound/soc/codecs/mt6358.c4
-rw-r--r--sound/soc/codecs/mt6359-accdet.c1080
-rw-r--r--sound/soc/codecs/mt6359-accdet.h128
-rw-r--r--sound/soc/codecs/mt6359.c4
-rw-r--r--sound/soc/codecs/mt6359.h1864
-rw-r--r--sound/soc/codecs/nau8825.c11
-rw-r--r--sound/soc/codecs/pcm1681.c2
-rw-r--r--sound/soc/codecs/rt1011.c49
-rw-r--r--sound/soc/codecs/rt1015.c27
-rw-r--r--sound/soc/codecs/rt1015.h10
-rw-r--r--sound/soc/codecs/rt1015p.c13
-rw-r--r--sound/soc/codecs/rt1016.c11
-rw-r--r--sound/soc/codecs/rt1019.c608
-rw-r--r--sound/soc/codecs/rt1019.h158
-rw-r--r--sound/soc/codecs/rt1305.c6
-rw-r--r--sound/soc/codecs/rt1308-sdw.c2
-rw-r--r--sound/soc/codecs/rt1308.c10
-rw-r--r--sound/soc/codecs/rt1316-sdw.c744
-rw-r--r--sound/soc/codecs/rt1316-sdw.h55
-rw-r--r--sound/soc/codecs/rt286.c29
-rw-r--r--sound/soc/codecs/rt298.c9
-rw-r--r--sound/soc/codecs/rt5631.c4
-rw-r--r--sound/soc/codecs/rt5640.c12
-rw-r--r--sound/soc/codecs/rt5645.c47
-rw-r--r--sound/soc/codecs/rt5645.h2
-rw-r--r--sound/soc/codecs/rt5651.c6
-rw-r--r--sound/soc/codecs/rt5659.c4
-rw-r--r--sound/soc/codecs/rt5660.c4
-rw-r--r--sound/soc/codecs/rt5663.c4
-rw-r--r--sound/soc/codecs/rt5665.c4
-rw-r--r--sound/soc/codecs/rt5668.c8
-rw-r--r--sound/soc/codecs/rt5670.c55
-rw-r--r--sound/soc/codecs/rt5670.h2
-rw-r--r--sound/soc/codecs/rt5677.c6
-rw-r--r--sound/soc/codecs/rt5682-i2c.c2
-rw-r--r--sound/soc/codecs/rt5682-sdw.c6
-rw-r--r--sound/soc/codecs/rt5682.c20
-rw-r--r--sound/soc/codecs/rt5682.h1
-rw-r--r--sound/soc/codecs/rt700-sdw.c2
-rw-r--r--sound/soc/codecs/rt700.c2
-rw-r--r--sound/soc/codecs/rt711-sdca-sdw.c425
-rw-r--r--sound/soc/codecs/rt711-sdca-sdw.h99
-rw-r--r--sound/soc/codecs/rt711-sdca.c1583
-rw-r--r--sound/soc/codecs/rt711-sdca.h240
-rw-r--r--sound/soc/codecs/rt711-sdw.c2
-rw-r--r--sound/soc/codecs/rt711.c2
-rw-r--r--sound/soc/codecs/rt715-sdca-sdw.c278
-rw-r--r--sound/soc/codecs/rt715-sdca-sdw.h170
-rw-r--r--sound/soc/codecs/rt715-sdca.c1075
-rw-r--r--sound/soc/codecs/rt715-sdca.h136
-rw-r--r--sound/soc/codecs/rt715-sdw.c2
-rw-r--r--sound/soc/codecs/rt715.c369
-rw-r--r--sound/soc/codecs/rt715.h3
-rw-r--r--sound/soc/codecs/sgtl5000.c6
-rw-r--r--sound/soc/codecs/sigmadsp-regmap.c2
-rw-r--r--sound/soc/codecs/sigmadsp.c18
-rw-r--r--sound/soc/codecs/sigmadsp.h2
-rw-r--r--sound/soc/codecs/sti-sas.c3
-rw-r--r--sound/soc/codecs/tas2562.c3
-rw-r--r--sound/soc/codecs/tas2764.c2
-rw-r--r--sound/soc/codecs/tas2770.c4
-rw-r--r--sound/soc/codecs/tlv320aic3x-i2c.c72
-rw-r--r--sound/soc/codecs/tlv320aic3x-spi.c78
-rw-r--r--sound/soc/codecs/tlv320aic3x.c111
-rw-r--r--sound/soc/codecs/tlv320aic3x.h13
-rw-r--r--sound/soc/codecs/tlv320dac33.c2
-rw-r--r--sound/soc/codecs/tscs454.c7
-rw-r--r--sound/soc/codecs/wcd-clsh-v2.h6
-rw-r--r--sound/soc/codecs/wcd9335.c4
-rw-r--r--sound/soc/codecs/wcd934x.c12
-rw-r--r--sound/soc/codecs/wm2200.c7
-rw-r--r--sound/soc/codecs/wm5102.c12
-rw-r--r--sound/soc/codecs/wm5110.c12
-rw-r--r--sound/soc/codecs/wm8524.c2
-rw-r--r--sound/soc/codecs/wm8903.c2
-rw-r--r--sound/soc/codecs/wm8958-dsp2.c16
-rw-r--r--sound/soc/codecs/wm8960.c12
-rw-r--r--sound/soc/codecs/wm8962.c23
-rw-r--r--sound/soc/codecs/wm8978.c2
-rw-r--r--sound/soc/codecs/wm8994.h2
-rw-r--r--sound/soc/codecs/wm8996.c2
-rw-r--r--sound/soc/codecs/wm8997.c14
-rw-r--r--sound/soc/codecs/wm8998.c9
-rw-r--r--sound/soc/codecs/wm_adsp.c2
-rw-r--r--sound/soc/codecs/wm_hubs.h2
-rw-r--r--sound/soc/codecs/wsa881x.c2
123 files changed, 11688 insertions, 712 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 1c87b42606c9..2a7b3e363069 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -161,6 +161,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RT1011
imply SND_SOC_RT1015
imply SND_SOC_RT1015P
+ imply SND_SOC_RT1019
imply SND_SOC_RT1305
imply SND_SOC_RT1308
imply SND_SOC_RT5514
@@ -180,8 +181,11 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RT5682_SDW
imply SND_SOC_RT700_SDW
imply SND_SOC_RT711_SDW
+ imply SND_SOC_RT711_SDCA_SDW
imply SND_SOC_RT715_SDW
+ imply SND_SOC_RT715_SDCA_SDW
imply SND_SOC_RT1308_SDW
+ imply SND_SOC_RT1316_SDW
imply SND_SOC_SGTL5000
imply SND_SOC_SI476X
imply SND_SOC_SIMPLE_AMPLIFIER
@@ -214,7 +218,8 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_TLV320AIC31XX
imply SND_SOC_TLV320AIC32X4_I2C
imply SND_SOC_TLV320AIC32X4_SPI
- imply SND_SOC_TLV320AIC3X
+ imply SND_SOC_TLV320AIC3X_I2C
+ imply SND_SOC_TLV320AIC3X_SPI
imply SND_SOC_TPA6130A2
imply SND_SOC_TLV320DAC33
imply SND_SOC_TSCS42XX
@@ -1076,6 +1081,7 @@ config SND_SOC_RL6231
default y if SND_SOC_RT1011=y
default y if SND_SOC_RT1015=y
default y if SND_SOC_RT1015P=y
+ default y if SND_SOC_RT1019=y
default y if SND_SOC_RT1305=y
default y if SND_SOC_RT1308=y
default m if SND_SOC_RT5514=m
@@ -1094,6 +1100,7 @@ config SND_SOC_RL6231
default m if SND_SOC_RT1011=m
default m if SND_SOC_RT1015=m
default m if SND_SOC_RT1015P=m
+ default m if SND_SOC_RT1019=m
default m if SND_SOC_RT1305=m
default m if SND_SOC_RT1308=m
@@ -1130,6 +1137,10 @@ config SND_SOC_RT1015P
tristate
depends on GPIOLIB
+config SND_SOC_RT1019
+ tristate
+ depends on I2C
+
config SND_SOC_RT1305
tristate
depends on I2C
@@ -1143,6 +1154,11 @@ config SND_SOC_RT1308_SDW
depends on I2C && SOUNDWIRE
select REGMAP_SOUNDWIRE
+config SND_SOC_RT1316_SDW
+ tristate "Realtek RT1316 Codec - SDW"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+
config SND_SOC_RT5514
tristate
depends on I2C
@@ -1241,6 +1257,12 @@ config SND_SOC_RT711_SDW
select SND_SOC_RT711
select REGMAP_SOUNDWIRE
+config SND_SOC_RT711_SDCA_SDW
+ tristate "Realtek RT711 SDCA Codec - SDW"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ select REGMAP_SOUNDWIRE_MBQ
+
config SND_SOC_RT715
tristate
@@ -1250,6 +1272,12 @@ config SND_SOC_RT715_SDW
select SND_SOC_RT715
select REGMAP_SOUNDWIRE
+config SND_SOC_RT715_SDCA_SDW
+ tristate "Realtek RT715 SDCA Codec - SDW"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ select REGMAP_SOUNDWIRE_MBQ
+
#Freescale sgtl5000 codec
config SND_SOC_SGTL5000
tristate "Freescale SGTL5000 CODEC"
@@ -1419,8 +1447,19 @@ config SND_SOC_TLV320AIC32X4_SPI
select SND_SOC_TLV320AIC32X4
config SND_SOC_TLV320AIC3X
- tristate "Texas Instruments TLV320AIC3x CODECs"
+ tristate
+
+config SND_SOC_TLV320AIC3X_I2C
+ tristate "Texas Instruments TLV320AIC3x audio CODECs - I2C"
depends on I2C
+ select SND_SOC_TLV320AIC3X
+ select REGMAP_I2C
+
+config SND_SOC_TLV320AIC3X_SPI
+ tristate "Texas Instruments TLV320AIC3x audio CODECs - SPI"
+ depends on SPI_MASTER
+ select SND_SOC_TLV320AIC3X
+ select REGMAP_SPI
config SND_SOC_TLV320DAC33
tristate
@@ -1785,6 +1824,14 @@ config SND_SOC_MT6359
Enable support for the platform which uses MT6359 as
external codec device.
+config SND_SOC_MT6359_ACCDET
+ tristate "MediaTek MT6359 ACCDET driver"
+ depends on MTK_PMIC_WRAP
+ help
+ ACCDET means Accessory Detection technology, MediaTek develop it
+ for ASoC codec soc-jack detection mechanism.
+ Select N if you don't have jack on board.
+
config SND_SOC_MT6660
tristate "Mediatek MT6660 Speaker Amplifier"
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 81357dc62ea0..0efdba609048 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -43,7 +43,7 @@ snd-soc-ak4642-objs := ak4642.o
snd-soc-ak4671-objs := ak4671.o
snd-soc-ak5386-objs := ak5386.o
snd-soc-ak5558-objs := ak5558.o
-snd-soc-arizona-objs := arizona.o
+snd-soc-arizona-objs := arizona.o arizona-jack.o
snd-soc-bd28623-objs := bd28623.o
snd-soc-bt-sco-objs := bt-sco.o
snd-soc-cpcap-objs := cpcap.o
@@ -136,6 +136,7 @@ snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
snd-soc-mt6351-objs := mt6351.o
snd-soc-mt6358-objs := mt6358.o
snd-soc-mt6359-objs := mt6359.o
+snd-soc-mt6359-accdet-objs := mt6359-accdet.o
snd-soc-mt6660-objs := mt6660.o
snd-soc-nau8315-objs := nau8315.o
snd-soc-nau8540-objs := nau8540.o
@@ -170,9 +171,11 @@ snd-soc-rl6347a-objs := rl6347a.o
snd-soc-rt1011-objs := rt1011.o
snd-soc-rt1015-objs := rt1015.o
snd-soc-rt1015p-objs := rt1015p.o
+snd-soc-rt1019-objs := rt1019.o
snd-soc-rt1305-objs := rt1305.o
snd-soc-rt1308-objs := rt1308.o
snd-soc-rt1308-sdw-objs := rt1308-sdw.o
+snd-soc-rt1316-sdw-objs := rt1316-sdw.o
snd-soc-rt274-objs := rt274.o
snd-soc-rt286-objs := rt286.o
snd-soc-rt298-objs := rt298.o
@@ -196,7 +199,9 @@ snd-soc-rt5682-sdw-objs := rt5682-sdw.o
snd-soc-rt5682-i2c-objs := rt5682-i2c.o
snd-soc-rt700-objs := rt700.o rt700-sdw.o
snd-soc-rt711-objs := rt711.o rt711-sdw.o
+snd-soc-rt711-sdca-objs := rt711-sdca.o rt711-sdca-sdw.o
snd-soc-rt715-objs := rt715.o rt715-sdw.o
+snd-soc-rt715-sdca-objs := rt715-sdca.o rt715-sdca-sdw.o
snd-soc-sgtl5000-objs := sgtl5000.o
snd-soc-alc5623-objs := alc5623.o
snd-soc-alc5632-objs := alc5632.o
@@ -233,6 +238,8 @@ snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o tlv320aic32x4-clk.o
snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o
snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
+snd-soc-tlv320aic3x-i2c-objs := tlv320aic3x-i2c.o
+snd-soc-tlv320aic3x-spi-objs := tlv320aic3x-spi.o
snd-soc-tlv320dac33-objs := tlv320dac33.o
snd-soc-tlv320adcx140-objs := tlv320adcx140.o
snd-soc-tscs42xx-objs := tscs42xx.o
@@ -450,6 +457,7 @@ obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o
obj-$(CONFIG_SND_SOC_MT6358) += snd-soc-mt6358.o
obj-$(CONFIG_SND_SOC_MT6359) += snd-soc-mt6359.o
+obj-$(CONFIG_SND_SOC_MT6359_ACCDET) += mt6359-accdet.o
obj-$(CONFIG_SND_SOC_MT6660) += snd-soc-mt6660.o
obj-$(CONFIG_SND_SOC_NAU8315) += snd-soc-nau8315.o
obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o
@@ -484,9 +492,11 @@ obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o
obj-$(CONFIG_SND_SOC_RT1015) += snd-soc-rt1015.o
obj-$(CONFIG_SND_SOC_RT1015P) += snd-soc-rt1015p.o
+obj-$(CONFIG_SND_SOC_RT1019) += snd-soc-rt1019.o
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_RT274) += snd-soc-rt274.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
@@ -511,7 +521,9 @@ obj-$(CONFIG_SND_SOC_RT5682_I2C) += snd-soc-rt5682-i2c.o
obj-$(CONFIG_SND_SOC_RT5682_SDW) += snd-soc-rt5682-sdw.o
obj-$(CONFIG_SND_SOC_RT700) += snd-soc-rt700.o
obj-$(CONFIG_SND_SOC_RT711) += snd-soc-rt711.o
+obj-$(CONFIG_SND_SOC_RT711_SDCA_SDW) += snd-soc-rt711-sdca.o
obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o
+obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o
@@ -548,6 +560,8 @@ obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o
obj-$(CONFIG_SND_SOC_TLV320AIC32X4_I2C) += snd-soc-tlv320aic32x4-i2c.o
obj-$(CONFIG_SND_SOC_TLV320AIC32X4_SPI) += snd-soc-tlv320aic32x4-spi.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
+obj-$(CONFIG_SND_SOC_TLV320AIC3X_I2C) += snd-soc-tlv320aic3x-i2c.o
+obj-$(CONFIG_SND_SOC_TLV320AIC3X_SPI) += snd-soc-tlv320aic3x-spi.o
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
obj-$(CONFIG_SND_SOC_TLV320ADCX140) += snd-soc-tlv320adcx140.o
obj-$(CONFIG_SND_SOC_TSCS42XX) += snd-soc-tscs42xx.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index c95f007cede1..5525e1ccab76 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -113,13 +113,6 @@ enum amic_idx {
AMIC_IDX_2
};
-struct ab8500_codec_drvdata_dbg {
- struct regulator *vaud;
- struct regulator *vamic1;
- struct regulator *vamic2;
- struct regulator *vdmic;
-};
-
/* Private data for AB8500 device-driver */
struct ab8500_codec_drvdata {
struct regmap *regmap;
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index a46152560294..08a5651bed9f 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -305,8 +305,6 @@ static int ad1836_probe(struct snd_soc_component *component)
return ret;
ret = snd_soc_dapm_add_routes(dapm, ad183x_adc_routes, num_adcs);
- if (ret)
- return ret;
return ret;
}
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
index 8260f49caa24..e347a48131d1 100644
--- a/sound/soc/codecs/adau1977.c
+++ b/sound/soc/codecs/adau1977.c
@@ -236,8 +236,6 @@ static int adau1977_reset(struct adau1977 *adau1977)
ret = regmap_write(adau1977->regmap, ADAU1977_REG_POWER,
ADAU1977_POWER_RESET);
regcache_cache_bypass(adau1977->regmap, false);
- if (ret)
- return ret;
return ret;
}
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index 85a1d00894a9..29eb78702bf3 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -306,6 +306,20 @@ static const struct snd_soc_dapm_route ak4497_intercon[] = {
};
+static int ak4458_get_tdm_mode(struct ak4458_priv *ak4458)
+{
+ switch (ak4458->slots * ak4458->slot_width) {
+ case 128:
+ return 1;
+ case 256:
+ return 2;
+ case 512:
+ return 3;
+ default:
+ return 0;
+ }
+}
+
static int ak4458_rstn_control(struct snd_soc_component *component, int bit)
{
int ret;
@@ -333,13 +347,16 @@ static int ak4458_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
int pcm_width = max(params_physical_width(params), ak4458->slot_width);
- u8 format, dsdsel0, dsdsel1;
- int nfs1, dsd_bclk;
+ u8 format, dsdsel0, dsdsel1, dchn;
+ int nfs1, dsd_bclk, ret, channels, channels_max;
nfs1 = params_rate(params);
ak4458->fs = nfs1;
/* calculate bit clock */
+ channels = params_channels(params);
+ channels_max = dai->driver->playback.channels_max;
+
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_DSD_U8:
case SNDRV_PCM_FORMAT_DSD_U16_LE:
@@ -419,8 +436,24 @@ static int ak4458_hw_params(struct snd_pcm_substream *substream,
snd_soc_component_update_bits(component, AK4458_00_CONTROL1,
AK4458_DIF_MASK, format);
- ak4458_rstn_control(component, 0);
- ak4458_rstn_control(component, 1);
+ /*
+ * Enable/disable Daisy Chain if in TDM mode and the number of played
+ * channels is bigger than the maximum supported number of channels
+ */
+ dchn = ak4458_get_tdm_mode(ak4458) &&
+ (ak4458->fmt == SND_SOC_DAIFMT_DSP_B) &&
+ (channels > channels_max) ? AK4458_DCHAIN_MASK : 0;
+
+ snd_soc_component_update_bits(component, AK4458_0B_CONTROL7,
+ AK4458_DCHAIN_MASK, dchn);
+
+ ret = ak4458_rstn_control(component, 0);
+ if (ret)
+ return ret;
+
+ ret = ak4458_rstn_control(component, 1);
+ if (ret)
+ return ret;
return 0;
}
@@ -429,6 +462,7 @@ static int ak4458_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+ int ret;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS: /* Slave Mode */
@@ -461,8 +495,13 @@ static int ak4458_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
ak4458->fmt == SND_SOC_DAIFMT_PDM ?
AK4458_DP_MASK : 0);
- ak4458_rstn_control(component, 0);
- ak4458_rstn_control(component, 1);
+ ret = ak4458_rstn_control(component, 0);
+ if (ret)
+ return ret;
+
+ ret = ak4458_rstn_control(component, 1);
+ if (ret)
+ return ret;
return 0;
}
@@ -508,20 +547,7 @@ static int ak4458_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
ak4458->slots = slots;
ak4458->slot_width = slot_width;
- switch (slots * slot_width) {
- case 128:
- mode = AK4458_MODE_TDM128;
- break;
- case 256:
- mode = AK4458_MODE_TDM256;
- break;
- case 512:
- mode = AK4458_MODE_TDM512;
- break;
- default:
- mode = AK4458_MODE_NORMAL;
- break;
- }
+ mode = ak4458_get_tdm_mode(ak4458) << AK4458_MODE_SHIFT;
snd_soc_component_update_bits(component, AK4458_0A_CONTROL6,
AK4458_MODE_MASK,
diff --git a/sound/soc/codecs/ak4458.h b/sound/soc/codecs/ak4458.h
index 9548c5d78621..9ad869575f8d 100644
--- a/sound/soc/codecs/ak4458.h
+++ b/sound/soc/codecs/ak4458.h
@@ -82,6 +82,7 @@
* */
#define AK4458_ATS_SHIFT 6
#define AK4458_ATS_MASK GENMASK(7, 6)
+#define AK4458_DCHAIN_MASK (0x1 << 1)
#define AK4458_DSDSEL_MASK (0x1 << 0)
#define AK4458_DP_MASK (0x1 << 7)
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c
index 85bdd0534180..34aed80db0eb 100644
--- a/sound/soc/codecs/ak5558.c
+++ b/sound/soc/codecs/ak5558.c
@@ -9,6 +9,7 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -23,6 +24,11 @@
#include "ak5558.h"
+enum ak555x_type {
+ AK5558,
+ AK5552,
+};
+
#define AK5558_NUM_SUPPLIES 2
static const char *ak5558_supply_names[AK5558_NUM_SUPPLIES] = {
"DVDD",
@@ -59,9 +65,18 @@ static const struct soc_enum ak5558_mono_enum[] = {
ARRAY_SIZE(mono_texts), mono_texts),
};
+static const char * const mono_5552_texts[] = {
+ "2 Slot", "1 Slot (Fixed)", "2 Slot", "1 Slot (Optimal)",
+};
+
+static const struct soc_enum ak5552_mono_enum[] = {
+ SOC_ENUM_SINGLE(AK5558_01_POWER_MANAGEMENT2, 1,
+ ARRAY_SIZE(mono_5552_texts), mono_5552_texts),
+};
+
static const char * const digfil_texts[] = {
- "Sharp Roll-Off", "Show Roll-Off",
- "Short Delay Sharp Roll-Off", "Short Delay Show Roll-Off",
+ "Sharp Roll-Off", "Slow Roll-Off",
+ "Short Delay Sharp Roll-Off", "Short Delay Slow Roll-Off",
};
static const struct soc_enum ak5558_adcset_enum[] = {
@@ -70,8 +85,13 @@ static const struct soc_enum ak5558_adcset_enum[] = {
};
static const struct snd_kcontrol_new ak5558_snd_controls[] = {
- SOC_ENUM("AK5558 Monaural Mode", ak5558_mono_enum[0]),
- SOC_ENUM("AK5558 Digital Filter", ak5558_adcset_enum[0]),
+ SOC_ENUM("Monaural Mode", ak5558_mono_enum[0]),
+ SOC_ENUM("Digital Filter", ak5558_adcset_enum[0]),
+};
+
+static const struct snd_kcontrol_new ak5552_snd_controls[] = {
+ SOC_ENUM("Monaural Mode", ak5552_mono_enum[0]),
+ SOC_ENUM("Digital Filter", ak5558_adcset_enum[0]),
};
static const struct snd_soc_dapm_widget ak5558_dapm_widgets[] = {
@@ -97,6 +117,17 @@ static const struct snd_soc_dapm_widget ak5558_dapm_widgets[] = {
SND_SOC_DAPM_AIF_OUT("SDTO", "Capture", 0, SND_SOC_NOPM, 0, 0),
};
+static const struct snd_soc_dapm_widget ak5552_dapm_widgets[] = {
+ /* Analog Input */
+ SND_SOC_DAPM_INPUT("AIN1"),
+ SND_SOC_DAPM_INPUT("AIN2"),
+
+ SND_SOC_DAPM_ADC("ADC Ch1", NULL, AK5558_00_POWER_MANAGEMENT1, 0, 0),
+ SND_SOC_DAPM_ADC("ADC Ch2", NULL, AK5558_00_POWER_MANAGEMENT1, 1, 0),
+
+ SND_SOC_DAPM_AIF_OUT("SDTO", "Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
static const struct snd_soc_dapm_route ak5558_intercon[] = {
{"ADC Ch1", NULL, "AIN1"},
{"SDTO", NULL, "ADC Ch1"},
@@ -123,6 +154,14 @@ static const struct snd_soc_dapm_route ak5558_intercon[] = {
{"SDTO", NULL, "ADC Ch8"},
};
+static const struct snd_soc_dapm_route ak5552_intercon[] = {
+ {"ADC Ch1", NULL, "AIN1"},
+ {"SDTO", NULL, "ADC Ch1"},
+
+ {"ADC Ch2", NULL, "AIN2"},
+ {"SDTO", NULL, "ADC Ch2"},
+};
+
static int ak5558_set_mcki(struct snd_soc_component *component)
{
return snd_soc_component_update_bits(component, AK5558_02_CONTROL1, AK5558_CKS,
@@ -267,21 +306,24 @@ static struct snd_soc_dai_driver ak5558_dai = {
.ops = &ak5558_dai_ops,
};
-static void ak5558_power_off(struct ak5558_priv *ak5558)
-{
- if (!ak5558->reset_gpiod)
- return;
-
- gpiod_set_value_cansleep(ak5558->reset_gpiod, 0);
- usleep_range(1000, 2000);
-}
+static struct snd_soc_dai_driver ak5552_dai = {
+ .name = "ak5558-aif",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = AK5558_FORMATS,
+ },
+ .ops = &ak5558_dai_ops,
+};
-static void ak5558_power_on(struct ak5558_priv *ak5558)
+static void ak5558_reset(struct ak5558_priv *ak5558, bool active)
{
if (!ak5558->reset_gpiod)
return;
- gpiod_set_value_cansleep(ak5558->reset_gpiod, 1);
+ gpiod_set_value_cansleep(ak5558->reset_gpiod, active);
usleep_range(1000, 2000);
}
@@ -289,7 +331,7 @@ static int ak5558_probe(struct snd_soc_component *component)
{
struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component);
- ak5558_power_on(ak5558);
+ ak5558_reset(ak5558, false);
return ak5558_set_mcki(component);
}
@@ -297,7 +339,7 @@ static void ak5558_remove(struct snd_soc_component *component)
{
struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component);
- ak5558_power_off(ak5558);
+ ak5558_reset(ak5558, true);
}
static int __maybe_unused ak5558_runtime_suspend(struct device *dev)
@@ -305,7 +347,7 @@ static int __maybe_unused ak5558_runtime_suspend(struct device *dev)
struct ak5558_priv *ak5558 = dev_get_drvdata(dev);
regcache_cache_only(ak5558->regmap, true);
- ak5558_power_off(ak5558);
+ ak5558_reset(ak5558, true);
regulator_bulk_disable(ARRAY_SIZE(ak5558->supplies),
ak5558->supplies);
@@ -324,8 +366,8 @@ static int __maybe_unused ak5558_runtime_resume(struct device *dev)
return ret;
}
- ak5558_power_off(ak5558);
- ak5558_power_on(ak5558);
+ ak5558_reset(ak5558, true);
+ ak5558_reset(ak5558, false);
regcache_cache_only(ak5558->regmap, false);
regcache_mark_dirty(ak5558->regmap);
@@ -354,6 +396,21 @@ static const struct snd_soc_component_driver soc_codec_dev_ak5558 = {
.non_legacy_dai_naming = 1,
};
+static const struct snd_soc_component_driver soc_codec_dev_ak5552 = {
+ .probe = ak5558_probe,
+ .remove = ak5558_remove,
+ .controls = ak5552_snd_controls,
+ .num_controls = ARRAY_SIZE(ak5552_snd_controls),
+ .dapm_widgets = ak5552_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ak5552_dapm_widgets),
+ .dapm_routes = ak5552_intercon,
+ .num_dapm_routes = ARRAY_SIZE(ak5552_intercon),
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
+};
+
static const struct regmap_config ak5558_regmap = {
.reg_bits = 8,
.val_bits = 8,
@@ -368,6 +425,7 @@ static int ak5558_i2c_probe(struct i2c_client *i2c)
{
struct ak5558_priv *ak5558;
int ret = 0;
+ int dev_id;
int i;
ak5558 = devm_kzalloc(&i2c->dev, sizeof(*ak5558), GFP_KERNEL);
@@ -396,11 +454,26 @@ static int ak5558_i2c_probe(struct i2c_client *i2c)
return ret;
}
- ret = devm_snd_soc_register_component(&i2c->dev,
- &soc_codec_dev_ak5558,
- &ak5558_dai, 1);
- if (ret)
+ dev_id = (uintptr_t)of_device_get_match_data(&i2c->dev);
+ switch (dev_id) {
+ case AK5552:
+ ret = devm_snd_soc_register_component(&i2c->dev,
+ &soc_codec_dev_ak5552,
+ &ak5552_dai, 1);
+ break;
+ case AK5558:
+ ret = devm_snd_soc_register_component(&i2c->dev,
+ &soc_codec_dev_ak5558,
+ &ak5558_dai, 1);
+ break;
+ default:
+ dev_err(&i2c->dev, "unexpected device type\n");
+ return -EINVAL;
+ }
+ if (ret < 0) {
+ dev_err(&i2c->dev, "failed to register component: %d\n", ret);
return ret;
+ }
pm_runtime_enable(&i2c->dev);
regcache_cache_only(ak5558->regmap, true);
@@ -416,7 +489,8 @@ static int ak5558_i2c_remove(struct i2c_client *i2c)
}
static const struct of_device_id ak5558_i2c_dt_ids[] __maybe_unused = {
- { .compatible = "asahi-kasei,ak5558"},
+ { .compatible = "asahi-kasei,ak5558", .data = (void *) AK5558 },
+ { .compatible = "asahi-kasei,ak5552", .data = (void *) AK5552 },
{ }
};
MODULE_DEVICE_TABLE(of, ak5558_i2c_dt_ids);
diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c
new file mode 100644
index 000000000000..9c15ddba6008
--- /dev/null
+++ b/sound/soc/codecs/arizona-jack.c
@@ -0,0 +1,1657 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * extcon-arizona.c - Extcon driver Wolfson Arizona devices
+ *
+ * Copyright (C) 2012-2014 Wolfson Microelectronics plc
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/jack.h>
+#include <sound/soc.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/pdata.h>
+#include <linux/mfd/arizona/registers.h>
+#include <dt-bindings/mfd/arizona.h>
+
+#include "arizona.h"
+
+#define ARIZONA_MAX_MICD_RANGE 8
+
+/*
+ * The hardware supports 8 ranges / buttons, but the snd-jack interface
+ * only supports 6 buttons (button 0-5).
+ */
+#define ARIZONA_MAX_MICD_BUTTONS 6
+
+#define ARIZONA_MICD_CLAMP_MODE_JDL 0x4
+#define ARIZONA_MICD_CLAMP_MODE_JDH 0x5
+#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
+#define ARIZONA_MICD_CLAMP_MODE_JDH_GP5H 0xb
+
+#define ARIZONA_TST_CAP_DEFAULT 0x3
+#define ARIZONA_TST_CAP_CLAMP 0x1
+
+#define ARIZONA_HPDET_MAX 10000
+
+#define HPDET_DEBOUNCE 500
+#define DEFAULT_MICD_TIMEOUT 2000
+
+#define ARIZONA_HPDET_WAIT_COUNT 15
+#define ARIZONA_HPDET_WAIT_DELAY_MS 20
+
+#define QUICK_HEADPHONE_MAX_OHM 3
+#define MICROPHONE_MIN_OHM 1257
+#define MICROPHONE_MAX_OHM 30000
+
+#define MICD_DBTIME_TWO_READINGS 2
+#define MICD_DBTIME_FOUR_READINGS 4
+
+#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
+ ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
+ ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
+ ARIZONA_MICD_LVL_7)
+
+#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
+
+#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
+
+static const struct arizona_micd_config micd_default_modes[] = {
+ { ARIZONA_ACCDET_SRC, 1, 0 },
+ { 0, 2, 1 },
+};
+
+static const struct arizona_micd_range micd_default_ranges[] = {
+ { .max = 11, .key = BTN_0 },
+ { .max = 28, .key = BTN_1 },
+ { .max = 54, .key = BTN_2 },
+ { .max = 100, .key = BTN_3 },
+ { .max = 186, .key = BTN_4 },
+ { .max = 430, .key = BTN_5 },
+};
+
+/* The number of levels in arizona_micd_levels valid for button thresholds */
+#define ARIZONA_NUM_MICD_BUTTON_LEVELS 64
+
+static const int arizona_micd_levels[] = {
+ 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
+ 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
+ 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
+ 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
+ 1257, 30000,
+};
+
+static void arizona_start_hpdet_acc_id(struct arizona_priv *info);
+
+static void arizona_extcon_hp_clamp(struct arizona_priv *info,
+ bool clamp)
+{
+ struct arizona *arizona = info->arizona;
+ unsigned int mask = 0, val = 0;
+ unsigned int cap_sel = 0;
+ int ret;
+
+ switch (arizona->type) {
+ case WM8998:
+ case WM1814:
+ mask = 0;
+ break;
+ case WM5110:
+ case WM8280:
+ mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
+ ARIZONA_HP1L_SHRTI;
+ if (clamp) {
+ val = ARIZONA_HP1L_SHRTO;
+ cap_sel = ARIZONA_TST_CAP_CLAMP;
+ } else {
+ val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
+ cap_sel = ARIZONA_TST_CAP_DEFAULT;
+ }
+
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_HP_TEST_CTRL_1,
+ ARIZONA_HP1_TST_CAP_SEL_MASK,
+ cap_sel);
+ if (ret)
+ dev_warn(arizona->dev, "Failed to set TST_CAP_SEL: %d\n", ret);
+ break;
+ default:
+ mask = ARIZONA_RMV_SHRT_HP1L;
+ if (clamp)
+ val = ARIZONA_RMV_SHRT_HP1L;
+ break;
+ }
+
+ snd_soc_dapm_mutex_lock(arizona->dapm);
+
+ arizona->hpdet_clamp = clamp;
+
+ /* Keep the HP output stages disabled while doing the clamp */
+ if (clamp) {
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_OUTPUT_ENABLES_1,
+ ARIZONA_OUT1L_ENA |
+ ARIZONA_OUT1R_ENA, 0);
+ if (ret)
+ dev_warn(arizona->dev, "Failed to disable headphone outputs: %d\n", ret);
+ }
+
+ if (mask) {
+ ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
+ mask, val);
+ if (ret)
+ dev_warn(arizona->dev, "Failed to do clamp: %d\n", ret);
+
+ ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R,
+ mask, val);
+ if (ret)
+ dev_warn(arizona->dev, "Failed to do clamp: %d\n", ret);
+ }
+
+ /* Restore the desired state while not doing the clamp */
+ if (!clamp) {
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_OUTPUT_ENABLES_1,
+ ARIZONA_OUT1L_ENA |
+ ARIZONA_OUT1R_ENA, arizona->hp_ena);
+ if (ret)
+ dev_warn(arizona->dev, "Failed to restore headphone outputs: %d\n", ret);
+ }
+
+ snd_soc_dapm_mutex_unlock(arizona->dapm);
+}
+
+static void arizona_extcon_set_mode(struct arizona_priv *info, int mode)
+{
+ struct arizona *arizona = info->arizona;
+
+ mode %= info->micd_num_modes;
+
+ gpiod_set_value_cansleep(info->micd_pol_gpio,
+ info->micd_modes[mode].gpio);
+
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_BIAS_SRC_MASK,
+ info->micd_modes[mode].bias <<
+ ARIZONA_MICD_BIAS_SRC_SHIFT);
+ regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
+
+ info->micd_mode = mode;
+
+ dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
+}
+
+static const char *arizona_extcon_get_micbias(struct arizona_priv *info)
+{
+ switch (info->micd_modes[0].bias) {
+ case 1:
+ return "MICBIAS1";
+ case 2:
+ return "MICBIAS2";
+ case 3:
+ return "MICBIAS3";
+ default:
+ return "MICVDD";
+ }
+}
+
+static void arizona_extcon_pulse_micbias(struct arizona_priv *info)
+{
+ struct arizona *arizona = info->arizona;
+ const char *widget = arizona_extcon_get_micbias(info);
+ struct snd_soc_dapm_context *dapm = arizona->dapm;
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ int ret;
+
+ ret = snd_soc_component_force_enable_pin(component, widget);
+ if (ret)
+ dev_warn(arizona->dev, "Failed to enable %s: %d\n", widget, ret);
+
+ snd_soc_dapm_sync(dapm);
+
+ if (!arizona->pdata.micd_force_micbias) {
+ ret = snd_soc_component_disable_pin(component, widget);
+ if (ret)
+ dev_warn(arizona->dev, "Failed to disable %s: %d\n", widget, ret);
+
+ snd_soc_dapm_sync(dapm);
+ }
+}
+
+static void arizona_start_mic(struct arizona_priv *info)
+{
+ struct arizona *arizona = info->arizona;
+ bool change;
+ int ret;
+ unsigned int mode;
+
+ /* Microphone detection can't use idle mode */
+ pm_runtime_get_sync(arizona->dev);
+
+ if (info->detecting) {
+ ret = regulator_allow_bypass(info->micvdd, false);
+ if (ret)
+ dev_err(arizona->dev, "Failed to regulate MICVDD: %d\n", ret);
+ }
+
+ ret = regulator_enable(info->micvdd);
+ if (ret)
+ dev_err(arizona->dev, "Failed to enable MICVDD: %d\n", ret);
+
+ if (info->micd_reva) {
+ const struct reg_sequence reva[] = {
+ { 0x80, 0x3 },
+ { 0x294, 0x0 },
+ { 0x80, 0x0 },
+ };
+
+ regmap_multi_reg_write(arizona->regmap, reva, ARRAY_SIZE(reva));
+ }
+
+ if (info->detecting && arizona->pdata.micd_software_compare)
+ mode = ARIZONA_ACCDET_MODE_ADC;
+ else
+ mode = ARIZONA_ACCDET_MODE_MIC;
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_MODE_MASK, mode);
+
+ arizona_extcon_pulse_micbias(info);
+
+ ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
+ &change);
+ if (ret < 0) {
+ dev_err(arizona->dev, "Failed to enable micd: %d\n", ret);
+ } else if (!change) {
+ regulator_disable(info->micvdd);
+ pm_runtime_put_autosuspend(arizona->dev);
+ }
+}
+
+static void arizona_stop_mic(struct arizona_priv *info)
+{
+ struct arizona *arizona = info->arizona;
+ const char *widget = arizona_extcon_get_micbias(info);
+ struct snd_soc_dapm_context *dapm = arizona->dapm;
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ bool change = false;
+ int ret;
+
+ ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_ENA, 0,
+ &change);
+ if (ret < 0)
+ dev_err(arizona->dev, "Failed to disable micd: %d\n", ret);
+
+ ret = snd_soc_component_disable_pin(component, widget);
+ if (ret)
+ dev_warn(arizona->dev, "Failed to disable %s: %d\n", widget, ret);
+
+ snd_soc_dapm_sync(dapm);
+
+ if (info->micd_reva) {
+ const struct reg_sequence reva[] = {
+ { 0x80, 0x3 },
+ { 0x294, 0x2 },
+ { 0x80, 0x0 },
+ };
+
+ regmap_multi_reg_write(arizona->regmap, reva, ARRAY_SIZE(reva));
+ }
+
+ ret = regulator_allow_bypass(info->micvdd, true);
+ if (ret)
+ dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", ret);
+
+ if (change) {
+ regulator_disable(info->micvdd);
+ pm_runtime_mark_last_busy(arizona->dev);
+ pm_runtime_put_autosuspend(arizona->dev);
+ }
+}
+
+static struct {
+ unsigned int threshold;
+ unsigned int factor_a;
+ unsigned int factor_b;
+} arizona_hpdet_b_ranges[] = {
+ { 100, 5528, 362464 },
+ { 169, 11084, 6186851 },
+ { 169, 11065, 65460395 },
+};
+
+#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
+
+static struct {
+ int min;
+ int max;
+} arizona_hpdet_c_ranges[] = {
+ { 0, 30 },
+ { 8, 100 },
+ { 100, 1000 },
+ { 1000, 10000 },
+};
+
+static int arizona_hpdet_read(struct arizona_priv *info)
+{
+ struct arizona *arizona = info->arizona;
+ unsigned int val, range;
+ int ret;
+
+ ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
+ if (ret) {
+ dev_err(arizona->dev, "Failed to read HPDET status: %d\n", ret);
+ return ret;
+ }
+
+ switch (info->hpdet_ip_version) {
+ case 0:
+ if (!(val & ARIZONA_HP_DONE)) {
+ dev_err(arizona->dev, "HPDET did not complete: %x\n", val);
+ return -EAGAIN;
+ }
+
+ val &= ARIZONA_HP_LVL_MASK;
+ break;
+
+ case 1:
+ if (!(val & ARIZONA_HP_DONE_B)) {
+ dev_err(arizona->dev, "HPDET did not complete: %x\n", val);
+ return -EAGAIN;
+ }
+
+ ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
+ if (ret) {
+ dev_err(arizona->dev, "Failed to read HP value: %d\n", ret);
+ return -EAGAIN;
+ }
+
+ regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
+ &range);
+ range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
+ >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
+
+ if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
+ (val < arizona_hpdet_b_ranges[range].threshold ||
+ val >= ARIZONA_HPDET_B_RANGE_MAX)) {
+ range++;
+ dev_dbg(arizona->dev, "Moving to HPDET range %d\n", range);
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_IMPEDANCE_RANGE_MASK,
+ range <<
+ ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
+ return -EAGAIN;
+ }
+
+ /* If we go out of range report top of range */
+ if (val < arizona_hpdet_b_ranges[range].threshold ||
+ val >= ARIZONA_HPDET_B_RANGE_MAX) {
+ dev_dbg(arizona->dev, "Measurement out of range\n");
+ return ARIZONA_HPDET_MAX;
+ }
+
+ dev_dbg(arizona->dev, "HPDET read %d in range %d\n", val, range);
+
+ val = arizona_hpdet_b_ranges[range].factor_b
+ / ((val * 100) -
+ arizona_hpdet_b_ranges[range].factor_a);
+ break;
+
+ case 2:
+ if (!(val & ARIZONA_HP_DONE_B)) {
+ dev_err(arizona->dev, "HPDET did not complete: %x\n", val);
+ return -EAGAIN;
+ }
+
+ val &= ARIZONA_HP_LVL_B_MASK;
+ /* Convert to ohms, the value is in 0.5 ohm increments */
+ val /= 2;
+
+ regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
+ &range);
+ range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
+ >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
+
+ /* Skip up a range, or report? */
+ if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
+ (val >= arizona_hpdet_c_ranges[range].max)) {
+ range++;
+ dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
+ arizona_hpdet_c_ranges[range].min,
+ arizona_hpdet_c_ranges[range].max);
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_IMPEDANCE_RANGE_MASK,
+ range <<
+ ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
+ return -EAGAIN;
+ }
+
+ if (range && (val < arizona_hpdet_c_ranges[range].min)) {
+ dev_dbg(arizona->dev, "Reporting range boundary %d\n",
+ arizona_hpdet_c_ranges[range].min);
+ val = arizona_hpdet_c_ranges[range].min;
+ }
+ break;
+
+ default:
+ dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n", info->hpdet_ip_version);
+ return -EINVAL;
+ }
+
+ dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
+ return val;
+}
+
+static int arizona_hpdet_do_id(struct arizona_priv *info, int *reading,
+ bool *mic)
+{
+ struct arizona *arizona = info->arizona;
+ int id_gpio = arizona->pdata.hpdet_id_gpio;
+
+ if (!arizona->pdata.hpdet_acc_id)
+ return 0;
+
+ /*
+ * If we're using HPDET for accessory identification we need
+ * to take multiple measurements, step through them in sequence.
+ */
+ info->hpdet_res[info->num_hpdet_res++] = *reading;
+
+ /* Only check the mic directly if we didn't already ID it */
+ if (id_gpio && info->num_hpdet_res == 1) {
+ dev_dbg(arizona->dev, "Measuring mic\n");
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_MODE_MASK |
+ ARIZONA_ACCDET_SRC,
+ ARIZONA_ACCDET_MODE_HPR |
+ info->micd_modes[0].src);
+
+ gpio_set_value_cansleep(id_gpio, 1);
+
+ regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+ return -EAGAIN;
+ }
+
+ /* OK, got both. Now, compare... */
+ dev_dbg(arizona->dev, "HPDET measured %d %d\n",
+ info->hpdet_res[0], info->hpdet_res[1]);
+
+ /* Take the headphone impedance for the main report */
+ *reading = info->hpdet_res[0];
+
+ /* Sometimes we get false readings due to slow insert */
+ if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
+ dev_dbg(arizona->dev, "Retrying high impedance\n");
+ info->num_hpdet_res = 0;
+ info->hpdet_retried = true;
+ arizona_start_hpdet_acc_id(info);
+ pm_runtime_put(arizona->dev);
+ return -EAGAIN;
+ }
+
+ /*
+ * If we measure the mic as high impedance
+ */
+ if (!id_gpio || info->hpdet_res[1] > 50) {
+ dev_dbg(arizona->dev, "Detected mic\n");
+ *mic = true;
+ info->detecting = true;
+ } else {
+ dev_dbg(arizona->dev, "Detected headphone\n");
+ }
+
+ /* Make sure everything is reset back to the real polarity */
+ regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_SRC, info->micd_modes[0].src);
+
+ return 0;
+}
+
+static irqreturn_t arizona_hpdet_irq(int irq, void *data)
+{
+ struct arizona_priv *info = data;
+ struct arizona *arizona = info->arizona;
+ int id_gpio = arizona->pdata.hpdet_id_gpio;
+ int ret, reading, state, report;
+ bool mic = false;
+
+ mutex_lock(&info->lock);
+
+ /* If we got a spurious IRQ for some reason then ignore it */
+ if (!info->hpdet_active) {
+ dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
+ mutex_unlock(&info->lock);
+ return IRQ_NONE;
+ }
+
+ /* If the cable was removed while measuring ignore the result */
+ state = info->jack->status & SND_JACK_MECHANICAL;
+ if (!state) {
+ dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
+ goto done;
+ }
+
+ ret = arizona_hpdet_read(info);
+ if (ret == -EAGAIN)
+ goto out;
+ else if (ret < 0)
+ goto done;
+ reading = ret;
+
+ /* Reset back to starting range */
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
+ 0);
+
+ ret = arizona_hpdet_do_id(info, &reading, &mic);
+ if (ret == -EAGAIN)
+ goto out;
+ else if (ret < 0)
+ goto done;
+
+ /* Report high impedence cables as line outputs */
+ if (reading >= 5000)
+ report = SND_JACK_LINEOUT;
+ else
+ report = SND_JACK_HEADPHONE;
+
+ snd_soc_jack_report(info->jack, report, SND_JACK_LINEOUT | SND_JACK_HEADPHONE);
+
+done:
+ /* Reset back to starting range */
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
+ 0);
+
+ arizona_extcon_hp_clamp(info, false);
+
+ if (id_gpio)
+ gpio_set_value_cansleep(id_gpio, 0);
+
+ /* If we have a mic then reenable MICDET */
+ if (state && (mic || info->mic))
+ arizona_start_mic(info);
+
+ if (info->hpdet_active) {
+ pm_runtime_put_autosuspend(arizona->dev);
+ info->hpdet_active = false;
+ }
+
+ /* Do not set hp_det done when the cable has been unplugged */
+ if (state)
+ info->hpdet_done = true;
+
+out:
+ mutex_unlock(&info->lock);
+
+ return IRQ_HANDLED;
+}
+
+static void arizona_identify_headphone(struct arizona_priv *info)
+{
+ struct arizona *arizona = info->arizona;
+ int ret;
+
+ if (info->hpdet_done)
+ return;
+
+ dev_dbg(arizona->dev, "Starting HPDET\n");
+
+ /* Make sure we keep the device enabled during the measurement */
+ pm_runtime_get_sync(arizona->dev);
+
+ info->hpdet_active = true;
+
+ arizona_stop_mic(info);
+
+ arizona_extcon_hp_clamp(info, true);
+
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_MODE_MASK,
+ arizona->pdata.hpdet_channel);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
+ goto err;
+ }
+
+ ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+ if (ret) {
+ dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", ret);
+ goto err;
+ }
+
+ return;
+
+err:
+ arizona_extcon_hp_clamp(info, false);
+ pm_runtime_put_autosuspend(arizona->dev);
+
+ /* Just report headphone */
+ snd_soc_jack_report(info->jack, SND_JACK_HEADPHONE,
+ SND_JACK_LINEOUT | SND_JACK_HEADPHONE);
+
+ if (info->mic)
+ arizona_start_mic(info);
+
+ info->hpdet_active = false;
+}
+
+static void arizona_start_hpdet_acc_id(struct arizona_priv *info)
+{
+ struct arizona *arizona = info->arizona;
+ int hp_reading = 32;
+ bool mic;
+ int ret;
+
+ dev_dbg(arizona->dev, "Starting identification via HPDET\n");
+
+ /* Make sure we keep the device enabled during the measurement */
+ pm_runtime_get_sync(arizona->dev);
+
+ info->hpdet_active = true;
+
+ arizona_extcon_hp_clamp(info, true);
+
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
+ info->micd_modes[0].src |
+ arizona->pdata.hpdet_channel);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
+ goto err;
+ }
+
+ if (arizona->pdata.hpdet_acc_id_line) {
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+ if (ret) {
+ dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", ret);
+ goto err;
+ }
+ } else {
+ arizona_hpdet_do_id(info, &hp_reading, &mic);
+ }
+
+ return;
+
+err:
+ /* Just report headphone */
+ snd_soc_jack_report(info->jack, SND_JACK_HEADPHONE,
+ SND_JACK_LINEOUT | SND_JACK_HEADPHONE);
+
+ info->hpdet_active = false;
+}
+
+static void arizona_micd_timeout_work(struct work_struct *work)
+{
+ struct arizona_priv *info = container_of(work,
+ struct arizona_priv,
+ micd_timeout_work.work);
+
+ mutex_lock(&info->lock);
+
+ dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
+
+ info->detecting = false;
+
+ arizona_identify_headphone(info);
+
+ mutex_unlock(&info->lock);
+}
+
+static int arizona_micd_adc_read(struct arizona_priv *info)
+{
+ struct arizona *arizona = info->arizona;
+ unsigned int val;
+ int ret;
+
+ /* Must disable MICD before we read the ADCVAL */
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_ENA, 0);
+
+ ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
+ if (ret) {
+ dev_err(arizona->dev, "Failed to read MICDET_ADCVAL: %d\n", ret);
+ return ret;
+ }
+
+ dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
+
+ val &= ARIZONA_MICDET_ADCVAL_MASK;
+ if (val < ARRAY_SIZE(arizona_micd_levels))
+ val = arizona_micd_levels[val];
+ else
+ val = INT_MAX;
+
+ if (val <= QUICK_HEADPHONE_MAX_OHM)
+ val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
+ else if (val <= MICROPHONE_MIN_OHM)
+ val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
+ else if (val <= MICROPHONE_MAX_OHM)
+ val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
+ else
+ val = ARIZONA_MICD_LVL_8;
+
+ return val;
+}
+
+static int arizona_micd_read(struct arizona_priv *info)
+{
+ struct arizona *arizona = info->arizona;
+ unsigned int val = 0;
+ int ret, i;
+
+ for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
+ ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
+ if (ret) {
+ dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
+ return ret;
+ }
+
+ dev_dbg(arizona->dev, "MICDET: %x\n", val);
+
+ if (!(val & ARIZONA_MICD_VALID)) {
+ dev_warn(arizona->dev, "Microphone detection state invalid\n");
+ return -EINVAL;
+ }
+ }
+
+ if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
+ dev_err(arizona->dev, "Failed to get valid MICDET value\n");
+ return -EINVAL;
+ }
+
+ return val;
+}
+
+static int arizona_micdet_reading(void *priv)
+{
+ struct arizona_priv *info = priv;
+ struct arizona *arizona = info->arizona;
+ int ret, val;
+
+ if (info->detecting && arizona->pdata.micd_software_compare)
+ ret = arizona_micd_adc_read(info);
+ else
+ ret = arizona_micd_read(info);
+ if (ret < 0)
+ return ret;
+
+ val = ret;
+
+ /* Due to jack detect this should never happen */
+ if (!(val & ARIZONA_MICD_STS)) {
+ dev_warn(arizona->dev, "Detected open circuit\n");
+ info->mic = false;
+ info->detecting = false;
+ arizona_identify_headphone(info);
+ return 0;
+ }
+
+ /* If we got a high impedence we should have a headset, report it. */
+ if (val & ARIZONA_MICD_LVL_8) {
+ info->mic = true;
+ info->detecting = false;
+
+ arizona_identify_headphone(info);
+
+ snd_soc_jack_report(info->jack, SND_JACK_MICROPHONE, SND_JACK_MICROPHONE);
+
+ /* Don't need to regulate for button detection */
+ ret = regulator_allow_bypass(info->micvdd, true);
+ if (ret)
+ dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", ret);
+
+ return 0;
+ }
+
+ /* If we detected a lower impedence during initial startup
+ * then we probably have the wrong polarity, flip it. Don't
+ * do this for the lowest impedences to speed up detection of
+ * plain headphones. If both polarities report a low
+ * impedence then give up and report headphones.
+ */
+ if (val & MICD_LVL_1_TO_7) {
+ if (info->jack_flips >= info->micd_num_modes * 10) {
+ dev_dbg(arizona->dev, "Detected HP/line\n");
+
+ info->detecting = false;
+
+ arizona_identify_headphone(info);
+ } else {
+ info->micd_mode++;
+ if (info->micd_mode == info->micd_num_modes)
+ info->micd_mode = 0;
+ arizona_extcon_set_mode(info, info->micd_mode);
+
+ info->jack_flips++;
+
+ if (arizona->pdata.micd_software_compare)
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_ENA,
+ ARIZONA_MICD_ENA);
+
+ queue_delayed_work(system_power_efficient_wq,
+ &info->micd_timeout_work,
+ msecs_to_jiffies(arizona->pdata.micd_timeout));
+ }
+
+ return 0;
+ }
+
+ /*
+ * If we're still detecting and we detect a short then we've
+ * got a headphone.
+ */
+ dev_dbg(arizona->dev, "Headphone detected\n");
+ info->detecting = false;
+
+ arizona_identify_headphone(info);
+
+ return 0;
+}
+
+static int arizona_button_reading(void *priv)
+{
+ struct arizona_priv *info = priv;
+ struct arizona *arizona = info->arizona;
+ int val, key, lvl;
+
+ val = arizona_micd_read(info);
+ if (val < 0)
+ return val;
+
+ /*
+ * If we're still detecting and we detect a short then we've
+ * got a headphone. Otherwise it's a button press.
+ */
+ if (val & MICD_LVL_0_TO_7) {
+ if (info->mic) {
+ dev_dbg(arizona->dev, "Mic button detected\n");
+
+ lvl = val & ARIZONA_MICD_LVL_MASK;
+ lvl >>= ARIZONA_MICD_LVL_SHIFT;
+
+ if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
+ key = ffs(lvl) - 1;
+ snd_soc_jack_report(info->jack,
+ SND_JACK_BTN_0 >> key,
+ info->micd_button_mask);
+ } else {
+ dev_err(arizona->dev, "Button out of range\n");
+ }
+ } else {
+ dev_warn(arizona->dev, "Button with no mic: %x\n", val);
+ }
+ } else {
+ dev_dbg(arizona->dev, "Mic button released\n");
+ snd_soc_jack_report(info->jack, 0, info->micd_button_mask);
+ arizona_extcon_pulse_micbias(info);
+ }
+
+ return 0;
+}
+
+static void arizona_micd_detect(struct work_struct *work)
+{
+ struct arizona_priv *info = container_of(work,
+ struct arizona_priv,
+ micd_detect_work.work);
+ struct arizona *arizona = info->arizona;
+
+ cancel_delayed_work_sync(&info->micd_timeout_work);
+
+ mutex_lock(&info->lock);
+
+ /* If the cable was removed while measuring ignore the result */
+ if (!(info->jack->status & SND_JACK_MECHANICAL)) {
+ dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
+ mutex_unlock(&info->lock);
+ return;
+ }
+
+ if (info->detecting)
+ arizona_micdet_reading(info);
+ else
+ arizona_button_reading(info);
+
+ pm_runtime_mark_last_busy(arizona->dev);
+ mutex_unlock(&info->lock);
+}
+
+static irqreturn_t arizona_micdet(int irq, void *data)
+{
+ struct arizona_priv *info = data;
+ struct arizona *arizona = info->arizona;
+ int debounce = arizona->pdata.micd_detect_debounce;
+
+ cancel_delayed_work_sync(&info->micd_detect_work);
+ cancel_delayed_work_sync(&info->micd_timeout_work);
+
+ mutex_lock(&info->lock);
+ if (!info->detecting)
+ debounce = 0;
+ mutex_unlock(&info->lock);
+
+ if (debounce)
+ queue_delayed_work(system_power_efficient_wq,
+ &info->micd_detect_work,
+ msecs_to_jiffies(debounce));
+ else
+ arizona_micd_detect(&info->micd_detect_work.work);
+
+ return IRQ_HANDLED;
+}
+
+static void arizona_hpdet_work(struct work_struct *work)
+{
+ struct arizona_priv *info = container_of(work,
+ struct arizona_priv,
+ hpdet_work.work);
+
+ mutex_lock(&info->lock);
+ arizona_start_hpdet_acc_id(info);
+ mutex_unlock(&info->lock);
+}
+
+static int arizona_hpdet_wait(struct arizona_priv *info)
+{
+ struct arizona *arizona = info->arizona;
+ unsigned int val;
+ int i, ret;
+
+ for (i = 0; i < ARIZONA_HPDET_WAIT_COUNT; i++) {
+ ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2,
+ &val);
+ if (ret) {
+ dev_err(arizona->dev, "Failed to read HPDET state: %d\n", ret);
+ return ret;
+ }
+
+ switch (info->hpdet_ip_version) {
+ case 0:
+ if (val & ARIZONA_HP_DONE)
+ return 0;
+ break;
+ default:
+ if (val & ARIZONA_HP_DONE_B)
+ return 0;
+ break;
+ }
+
+ msleep(ARIZONA_HPDET_WAIT_DELAY_MS);
+ }
+
+ dev_warn(arizona->dev, "HPDET did not appear to complete\n");
+
+ return -ETIMEDOUT;
+}
+
+static irqreturn_t arizona_jackdet(int irq, void *data)
+{
+ struct arizona_priv *info = data;
+ struct arizona *arizona = info->arizona;
+ unsigned int val, present, mask;
+ bool cancelled_hp, cancelled_mic;
+ int ret, i;
+
+ cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
+ cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
+
+ pm_runtime_get_sync(arizona->dev);
+
+ mutex_lock(&info->lock);
+
+ if (info->micd_clamp) {
+ mask = ARIZONA_MICD_CLAMP_STS;
+ present = 0;
+ } else {
+ mask = ARIZONA_JD1_STS;
+ if (arizona->pdata.jd_invert)
+ present = 0;
+ else
+ present = ARIZONA_JD1_STS;
+ }
+
+ ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
+ if (ret) {
+ dev_err(arizona->dev, "Failed to read jackdet status: %d\n", ret);
+ mutex_unlock(&info->lock);
+ pm_runtime_put_autosuspend(arizona->dev);
+ return IRQ_NONE;
+ }
+
+ val &= mask;
+ if (val == info->last_jackdet) {
+ dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
+ if (cancelled_hp)
+ queue_delayed_work(system_power_efficient_wq,
+ &info->hpdet_work,
+ msecs_to_jiffies(HPDET_DEBOUNCE));
+
+ if (cancelled_mic) {
+ int micd_timeout = arizona->pdata.micd_timeout;
+
+ queue_delayed_work(system_power_efficient_wq,
+ &info->micd_timeout_work,
+ msecs_to_jiffies(micd_timeout));
+ }
+
+ goto out;
+ }
+ info->last_jackdet = val;
+
+ if (info->last_jackdet == present) {
+ dev_dbg(arizona->dev, "Detected jack\n");
+ snd_soc_jack_report(info->jack, SND_JACK_MECHANICAL, SND_JACK_MECHANICAL);
+
+ info->detecting = true;
+ info->mic = false;
+ info->jack_flips = 0;
+
+ if (!arizona->pdata.hpdet_acc_id) {
+ arizona_start_mic(info);
+ } else {
+ queue_delayed_work(system_power_efficient_wq,
+ &info->hpdet_work,
+ msecs_to_jiffies(HPDET_DEBOUNCE));
+ }
+
+ if (info->micd_clamp || !arizona->pdata.jd_invert)
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_JACK_DETECT_DEBOUNCE,
+ ARIZONA_MICD_CLAMP_DB |
+ ARIZONA_JD1_DB, 0);
+ } else {
+ dev_dbg(arizona->dev, "Detected jack removal\n");
+
+ arizona_stop_mic(info);
+
+ info->num_hpdet_res = 0;
+ for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
+ info->hpdet_res[i] = 0;
+ info->mic = false;
+ info->hpdet_done = false;
+ info->hpdet_retried = false;
+
+ snd_soc_jack_report(info->jack, 0, ARIZONA_JACK_MASK | info->micd_button_mask);
+
+ /*
+ * If the jack was removed during a headphone detection we
+ * need to wait for the headphone detection to finish, as
+ * it can not be aborted. We don't want to be able to start
+ * a new headphone detection from a fresh insert until this
+ * one is finished.
+ */
+ arizona_hpdet_wait(info);
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_JACK_DETECT_DEBOUNCE,
+ ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
+ ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
+ }
+
+out:
+ /* Clear trig_sts to make sure DCVDD is not forced up */
+ regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
+ ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
+ ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
+ ARIZONA_JD1_FALL_TRIG_STS |
+ ARIZONA_JD1_RISE_TRIG_STS);
+
+ mutex_unlock(&info->lock);
+
+ pm_runtime_mark_last_busy(arizona->dev);
+ pm_runtime_put_autosuspend(arizona->dev);
+
+ return IRQ_HANDLED;
+}
+
+/* Map a level onto a slot in the register bank */
+static void arizona_micd_set_level(struct arizona *arizona, int index,
+ unsigned int level)
+{
+ int reg;
+ unsigned int mask;
+
+ reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
+
+ if (!(index % 2)) {
+ mask = 0x3f00;
+ level <<= 8;
+ } else {
+ mask = 0x3f;
+ }
+
+ /* Program the level itself */
+ regmap_update_bits(arizona->regmap, reg, mask, level);
+}
+
+static int arizona_extcon_get_micd_configs(struct device *dev,
+ struct arizona *arizona)
+{
+ const char * const prop = "wlf,micd-configs";
+ const int entries_per_config = 3;
+ struct arizona_micd_config *micd_configs;
+ int nconfs, ret;
+ int i, j;
+ u32 *vals;
+
+ nconfs = device_property_count_u32(arizona->dev, prop);
+ if (nconfs <= 0)
+ return 0;
+
+ vals = kcalloc(nconfs, sizeof(u32), GFP_KERNEL);
+ if (!vals)
+ return -ENOMEM;
+
+ ret = device_property_read_u32_array(arizona->dev, prop, vals, nconfs);
+ if (ret < 0)
+ goto out;
+
+ nconfs /= entries_per_config;
+ micd_configs = devm_kcalloc(dev, nconfs, sizeof(*micd_configs),
+ GFP_KERNEL);
+ if (!micd_configs) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0, j = 0; i < nconfs; ++i) {
+ micd_configs[i].src = vals[j++] ? ARIZONA_ACCDET_SRC : 0;
+ micd_configs[i].bias = vals[j++];
+ micd_configs[i].gpio = vals[j++];
+ }
+
+ arizona->pdata.micd_configs = micd_configs;
+ arizona->pdata.num_micd_configs = nconfs;
+
+out:
+ kfree(vals);
+ return ret;
+}
+
+static int arizona_extcon_device_get_pdata(struct device *dev,
+ struct arizona *arizona)
+{
+ struct arizona_pdata *pdata = &arizona->pdata;
+ unsigned int val = ARIZONA_ACCDET_MODE_HPL;
+ int ret;
+
+ device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
+ switch (val) {
+ case ARIZONA_ACCDET_MODE_HPL:
+ case ARIZONA_ACCDET_MODE_HPR:
+ pdata->hpdet_channel = val;
+ break;
+ default:
+ dev_err(arizona->dev, "Wrong wlf,hpdet-channel DT value %d\n", val);
+ pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
+ }
+
+ device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce",
+ &pdata->micd_detect_debounce);
+
+ device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time",
+ &pdata->micd_bias_start_time);
+
+ device_property_read_u32(arizona->dev, "wlf,micd-rate",
+ &pdata->micd_rate);
+
+ device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
+ &pdata->micd_dbtime);
+
+ device_property_read_u32(arizona->dev, "wlf,micd-timeout-ms",
+ &pdata->micd_timeout);
+
+ pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
+ "wlf,micd-force-micbias");
+
+ pdata->micd_software_compare = device_property_read_bool(arizona->dev,
+ "wlf,micd-software-compare");
+
+ pdata->jd_invert = device_property_read_bool(arizona->dev,
+ "wlf,jd-invert");
+
+ device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw);
+
+ pdata->jd_gpio5 = device_property_read_bool(arizona->dev,
+ "wlf,use-jd2");
+ pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev,
+ "wlf,use-jd2-nopull");
+
+ ret = arizona_extcon_get_micd_configs(dev, arizona);
+ if (ret < 0)
+ dev_err(arizona->dev, "Failed to read micd configs: %d\n", ret);
+
+ return 0;
+}
+
+int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev)
+{
+ struct arizona *arizona = info->arizona;
+ struct arizona_pdata *pdata = &arizona->pdata;
+ int ret, mode;
+
+ if (!dev_get_platdata(arizona->dev))
+ arizona_extcon_device_get_pdata(dev, arizona);
+
+ info->micvdd = devm_regulator_get(dev, "MICVDD");
+ if (IS_ERR(info->micvdd))
+ return dev_err_probe(arizona->dev, PTR_ERR(info->micvdd), "getting MICVDD\n");
+
+ mutex_init(&info->lock);
+ info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
+ INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
+ INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
+ INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
+
+ switch (arizona->type) {
+ case WM5102:
+ switch (arizona->rev) {
+ case 0:
+ info->micd_reva = true;
+ break;
+ default:
+ info->micd_clamp = true;
+ info->hpdet_ip_version = 1;
+ break;
+ }
+ break;
+ case WM5110:
+ case WM8280:
+ switch (arizona->rev) {
+ case 0 ... 2:
+ break;
+ default:
+ info->micd_clamp = true;
+ info->hpdet_ip_version = 2;
+ break;
+ }
+ break;
+ case WM8998:
+ case WM1814:
+ info->micd_clamp = true;
+ info->hpdet_ip_version = 2;
+ break;
+ default:
+ break;
+ }
+
+ if (!pdata->micd_timeout)
+ pdata->micd_timeout = DEFAULT_MICD_TIMEOUT;
+
+ if (pdata->num_micd_configs) {
+ info->micd_modes = pdata->micd_configs;
+ info->micd_num_modes = pdata->num_micd_configs;
+ } else {
+ info->micd_modes = micd_default_modes;
+ info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
+ }
+
+ if (arizona->pdata.gpsw > 0)
+ regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
+ ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);
+
+ if (pdata->micd_pol_gpio > 0) {
+ if (info->micd_modes[0].gpio)
+ mode = GPIOF_OUT_INIT_HIGH;
+ else
+ mode = GPIOF_OUT_INIT_LOW;
+
+ ret = devm_gpio_request_one(dev, pdata->micd_pol_gpio,
+ mode, "MICD polarity");
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
+ pdata->micd_pol_gpio, ret);
+ return ret;
+ }
+
+ info->micd_pol_gpio = gpio_to_desc(pdata->micd_pol_gpio);
+ } else {
+ if (info->micd_modes[0].gpio)
+ mode = GPIOD_OUT_HIGH;
+ else
+ mode = GPIOD_OUT_LOW;
+
+ /* We can't use devm here because we need to do the get
+ * against the MFD device, as that is where the of_node
+ * will reside, but if we devm against that the GPIO
+ * will not be freed if the extcon driver is unloaded.
+ */
+ info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
+ "wlf,micd-pol",
+ mode);
+ if (IS_ERR(info->micd_pol_gpio)) {
+ ret = PTR_ERR(info->micd_pol_gpio);
+ dev_err_probe(arizona->dev, ret, "getting microphone polarity GPIO\n");
+ return ret;
+ }
+ }
+
+ if (arizona->pdata.hpdet_id_gpio > 0) {
+ ret = devm_gpio_request_one(dev, arizona->pdata.hpdet_id_gpio,
+ GPIOF_OUT_INIT_LOW,
+ "HPDET");
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
+ arizona->pdata.hpdet_id_gpio, ret);
+ gpiod_put(info->micd_pol_gpio);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_jack_codec_dev_probe);
+
+int arizona_jack_codec_dev_remove(struct arizona_priv *info)
+{
+ gpiod_put(info->micd_pol_gpio);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_jack_codec_dev_remove);
+
+static int arizona_jack_enable_jack_detect(struct arizona_priv *info,
+ struct snd_soc_jack *jack)
+{
+ struct arizona *arizona = info->arizona;
+ struct arizona_pdata *pdata = &arizona->pdata;
+ unsigned int val;
+ unsigned int clamp_mode;
+ int jack_irq_fall, jack_irq_rise;
+ int ret, i, j;
+
+ if (arizona->pdata.micd_bias_start_time)
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_BIAS_STARTTIME_MASK,
+ arizona->pdata.micd_bias_start_time
+ << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
+
+ if (arizona->pdata.micd_rate)
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_RATE_MASK,
+ arizona->pdata.micd_rate
+ << ARIZONA_MICD_RATE_SHIFT);
+
+ switch (arizona->pdata.micd_dbtime) {
+ case MICD_DBTIME_FOUR_READINGS:
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_DBTIME_MASK,
+ ARIZONA_MICD_DBTIME);
+ break;
+ case MICD_DBTIME_TWO_READINGS:
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_DBTIME_MASK, 0);
+ break;
+ default:
+ break;
+ }
+
+ BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) <
+ ARIZONA_NUM_MICD_BUTTON_LEVELS);
+
+ if (arizona->pdata.num_micd_ranges) {
+ info->micd_ranges = pdata->micd_ranges;
+ info->num_micd_ranges = pdata->num_micd_ranges;
+ } else {
+ info->micd_ranges = micd_default_ranges;
+ info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
+ }
+
+ if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_BUTTONS) {
+ dev_err(arizona->dev, "Too many MICD ranges: %d > %d\n",
+ arizona->pdata.num_micd_ranges, ARIZONA_MAX_MICD_BUTTONS);
+ return -EINVAL;
+ }
+
+ if (info->num_micd_ranges > 1) {
+ for (i = 1; i < info->num_micd_ranges; i++) {
+ if (info->micd_ranges[i - 1].max >
+ info->micd_ranges[i].max) {
+ dev_err(arizona->dev, "MICD ranges must be sorted\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ /* Disable all buttons by default */
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
+ ARIZONA_MICD_LVL_SEL_MASK, 0x81);
+
+ /* Set up all the buttons the user specified */
+ for (i = 0; i < info->num_micd_ranges; i++) {
+ for (j = 0; j < ARIZONA_NUM_MICD_BUTTON_LEVELS; j++)
+ if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
+ break;
+
+ if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
+ dev_err(arizona->dev, "Unsupported MICD level %d\n",
+ info->micd_ranges[i].max);
+ return -EINVAL;
+ }
+
+ dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
+ arizona_micd_levels[j], i);
+
+ arizona_micd_set_level(arizona, i, j);
+
+ /* SND_JACK_BTN_# masks start with the most significant bit */
+ info->micd_button_mask |= SND_JACK_BTN_0 >> i;
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0 >> i,
+ info->micd_ranges[i].key);
+
+ /* Enable reporting of that range */
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
+ 1 << i, 1 << i);
+ }
+
+ /* Set all the remaining keys to a maximum */
+ for (; i < ARIZONA_MAX_MICD_RANGE; i++)
+ arizona_micd_set_level(arizona, i, 0x3f);
+
+ /*
+ * If we have a clamp use it, activating in conjunction with
+ * GPIO5 if that is connected for jack detect operation.
+ */
+ if (info->micd_clamp) {
+ if (arizona->pdata.jd_gpio5) {
+ /* Put the GPIO into input mode with optional pull */
+ val = 0xc101;
+ if (arizona->pdata.jd_gpio5_nopull)
+ val &= ~ARIZONA_GPN_PU;
+
+ regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
+ val);
+
+ if (arizona->pdata.jd_invert)
+ clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
+ else
+ clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
+ } else {
+ if (arizona->pdata.jd_invert)
+ clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
+ else
+ clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
+ }
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_MICD_CLAMP_CONTROL,
+ ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_JACK_DETECT_DEBOUNCE,
+ ARIZONA_MICD_CLAMP_DB,
+ ARIZONA_MICD_CLAMP_DB);
+ }
+
+ arizona_extcon_set_mode(info, 0);
+
+ info->jack = jack;
+
+ pm_runtime_get_sync(arizona->dev);
+
+ if (info->micd_clamp) {
+ jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
+ jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
+ } else {
+ jack_irq_rise = ARIZONA_IRQ_JD_RISE;
+ jack_irq_fall = ARIZONA_IRQ_JD_FALL;
+ }
+
+ ret = arizona_request_irq(arizona, jack_irq_rise,
+ "JACKDET rise", arizona_jackdet, info);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to get JACKDET rise IRQ: %d\n", ret);
+ goto err_pm;
+ }
+
+ ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to set JD rise IRQ wake: %d\n", ret);
+ goto err_rise;
+ }
+
+ ret = arizona_request_irq(arizona, jack_irq_fall,
+ "JACKDET fall", arizona_jackdet, info);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to get JD fall IRQ: %d\n", ret);
+ goto err_rise_wake;
+ }
+
+ ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to set JD fall IRQ wake: %d\n", ret);
+ goto err_fall;
+ }
+
+ ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
+ "MICDET", arizona_micdet, info);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to get MICDET IRQ: %d\n", ret);
+ goto err_fall_wake;
+ }
+
+ ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
+ "HPDET", arizona_hpdet_irq, info);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to get HPDET IRQ: %d\n", ret);
+ goto err_micdet;
+ }
+
+ arizona_clk32k_enable(arizona);
+ regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
+ ARIZONA_JD1_DB, ARIZONA_JD1_DB);
+ regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
+ ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
+
+ ret = regulator_allow_bypass(info->micvdd, true);
+ if (ret != 0)
+ dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n", ret);
+
+ pm_runtime_put(arizona->dev);
+
+ return 0;
+
+err_micdet:
+ arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
+err_fall_wake:
+ arizona_set_irq_wake(arizona, jack_irq_fall, 0);
+err_fall:
+ arizona_free_irq(arizona, jack_irq_fall, info);
+err_rise_wake:
+ arizona_set_irq_wake(arizona, jack_irq_rise, 0);
+err_rise:
+ arizona_free_irq(arizona, jack_irq_rise, info);
+err_pm:
+ pm_runtime_put(arizona->dev);
+ info->jack = NULL;
+ return ret;
+}
+
+static int arizona_jack_disable_jack_detect(struct arizona_priv *info)
+{
+ struct arizona *arizona = info->arizona;
+ int jack_irq_rise, jack_irq_fall;
+ bool change;
+ int ret;
+
+ if (!info->jack)
+ return 0;
+
+ if (info->micd_clamp) {
+ jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
+ jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
+ } else {
+ jack_irq_rise = ARIZONA_IRQ_JD_RISE;
+ jack_irq_fall = ARIZONA_IRQ_JD_FALL;
+ }
+
+ arizona_set_irq_wake(arizona, jack_irq_rise, 0);
+ arizona_set_irq_wake(arizona, jack_irq_fall, 0);
+ arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
+ arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
+ arizona_free_irq(arizona, jack_irq_rise, info);
+ arizona_free_irq(arizona, jack_irq_fall, info);
+ cancel_delayed_work_sync(&info->hpdet_work);
+ cancel_delayed_work_sync(&info->micd_detect_work);
+ cancel_delayed_work_sync(&info->micd_timeout_work);
+
+ ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_ENA, 0,
+ &change);
+ if (ret < 0) {
+ dev_err(arizona->dev, "Failed to disable micd on remove: %d\n", ret);
+ } else if (change) {
+ regulator_disable(info->micvdd);
+ pm_runtime_put(arizona->dev);
+ }
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_MICD_CLAMP_CONTROL,
+ ARIZONA_MICD_CLAMP_MODE_MASK, 0);
+ regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
+ ARIZONA_JD1_ENA, 0);
+ arizona_clk32k_disable(arizona);
+ info->jack = NULL;
+
+ return 0;
+}
+
+int arizona_jack_set_jack(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *data)
+{
+ struct arizona_priv *info = snd_soc_component_get_drvdata(component);
+
+ if (jack)
+ return arizona_jack_enable_jack_detect(info, jack);
+ else
+ return arizona_jack_disable_jack_detect(info);
+}
+EXPORT_SYMBOL_GPL(arizona_jack_set_jack);
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index b893d3e4c97c..ecd8890eefc1 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -91,6 +91,41 @@ struct arizona_priv {
unsigned int dvfs_reqs;
struct mutex dvfs_lock;
bool dvfs_cached;
+
+ /* Variables used by arizona-jack.c code */
+ struct mutex lock;
+ struct delayed_work hpdet_work;
+ struct delayed_work micd_detect_work;
+ struct delayed_work micd_timeout_work;
+ struct snd_soc_jack *jack;
+ struct regulator *micvdd;
+ struct gpio_desc *micd_pol_gpio;
+
+ u16 last_jackdet;
+
+ int micd_mode;
+ const struct arizona_micd_config *micd_modes;
+ int micd_num_modes;
+
+ int micd_button_mask;
+ const struct arizona_micd_range *micd_ranges;
+ int num_micd_ranges;
+
+ bool micd_reva;
+ bool micd_clamp;
+
+ bool hpdet_active;
+ bool hpdet_done;
+ bool hpdet_retried;
+
+ bool mic;
+ bool detecting;
+
+ int num_hpdet_res;
+ unsigned int hpdet_res[3];
+
+ int jack_flips;
+ int hpdet_ip_version;
};
struct arizona_voice_trigger_info {
@@ -222,6 +257,9 @@ extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
#define ARIZONA_RATE_ENUM_SIZE 4
#define ARIZONA_SAMPLE_RATE_ENUM_SIZE 14
+/* SND_JACK_* mask for supported cable/switch types */
+#define ARIZONA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_MECHANICAL)
+
extern const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
extern const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
extern const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE];
@@ -317,7 +355,7 @@ int arizona_init_vol_limit(struct arizona *arizona);
int arizona_init_spk_irqs(struct arizona *arizona);
int arizona_free_spk_irqs(struct arizona *arizona);
-int arizona_init_dai(struct arizona_priv *priv, int dai);
+int arizona_init_dai(struct arizona_priv *priv, int id);
int arizona_set_output_mode(struct snd_soc_component *component, int output,
bool diff);
@@ -351,4 +389,10 @@ static inline int arizona_unregister_notifier(struct snd_soc_component *componen
int arizona_of_get_audio_pdata(struct arizona *arizona);
+int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev);
+int arizona_jack_codec_dev_remove(struct arizona_priv *info);
+
+int arizona_jack_set_jack(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *data);
+
#endif
diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c
index c4772f82485a..a201d652aca2 100644
--- a/sound/soc/codecs/cros_ec_codec.c
+++ b/sound/soc/codecs/cros_ec_codec.c
@@ -94,7 +94,7 @@ static int send_ec_host_command(struct cros_ec_device *ec_dev, uint32_t cmd,
if (ret < 0)
goto error;
- if (insize)
+ if (in && insize)
memcpy(in, msg->data, insize);
ret = 0;
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
index 55d529aa0011..f20ed838b958 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -9,7 +9,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
@@ -1488,7 +1487,7 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client,
if (IS_ERR(cs35l35->regmap)) {
ret = PTR_ERR(cs35l35->regmap);
dev_err(dev, "regmap_init() failed: %d\n", ret);
- goto err;
+ return ret;
}
for (i = 0; i < ARRAY_SIZE(cs35l35_supplies); i++)
diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c
index 4451ca9f4916..a038bcec2d17 100644
--- a/sound/soc/codecs/cs35l36.c
+++ b/sound/soc/codecs/cs35l36.c
@@ -1721,7 +1721,7 @@ static int cs35l36_i2c_probe(struct i2c_client *i2c_client,
if (IS_ERR(cs35l36->regmap)) {
ret = PTR_ERR(cs35l36->regmap);
dev_err(dev, "regmap_init() failed: %d\n", ret);
- goto err;
+ return ret;
}
cs35l36->num_supplies = ARRAY_SIZE(cs35l36_supplies);
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index ddd95c8269ed..2d239e983a83 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -400,6 +400,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
* cs4270_dai_mute - enable/disable the CS4270 external mute
* @dai: the SOC DAI
* @mute: 0 = disable mute, 1 = enable mute
+ * @direction: (ignored)
*
* This function toggles the mute bits in the MUTE register. The CS4270's
* mute capability is intended for external muting circuitry, so if the
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 811b7b1c9732..bf982e145e94 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -25,6 +25,7 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -461,64 +462,78 @@ static const struct snd_kcontrol_new cs42l42_snd_controls[] = {
0x3f, 1, mixer_tlv)
};
-static int cs42l42_hpdrv_evt(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_PMU) {
- /* Enable the channels */
- snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_EN,
- CS42L42_ASP_RX0_CH_EN_MASK,
- (CS42L42_ASP_RX0_CH1_EN |
- CS42L42_ASP_RX0_CH2_EN) <<
- CS42L42_ASP_RX0_CH_EN_SHIFT);
-
- /* Power up */
- snd_soc_component_update_bits(component, CS42L42_PWR_CTL1,
- CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
- CS42L42_HP_PDN_MASK, 0);
- } else if (event & SND_SOC_DAPM_PRE_PMD) {
- /* Disable the channels */
- snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_EN,
- CS42L42_ASP_RX0_CH_EN_MASK, 0);
-
- /* Power down */
- snd_soc_component_update_bits(component, CS42L42_PWR_CTL1,
- CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
- CS42L42_HP_PDN_MASK,
- CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
- CS42L42_HP_PDN_MASK);
- } else {
- dev_err(component->dev, "Invalid event 0x%x\n", event);
- }
- return 0;
-}
-
static const struct snd_soc_dapm_widget cs42l42_dapm_widgets[] = {
+ /* Playback Path */
SND_SOC_DAPM_OUTPUT("HP"),
- SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0, CS42L42_ASP_CLK_CFG,
- CS42L42_ASP_SCLK_EN_SHIFT, false),
- SND_SOC_DAPM_OUT_DRV_E("HPDRV", SND_SOC_NOPM, 0,
- 0, NULL, 0, cs42l42_hpdrv_evt,
- SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD)
+ SND_SOC_DAPM_DAC("DAC", NULL, CS42L42_PWR_CTL1, CS42L42_HP_PDN_SHIFT, 1),
+ SND_SOC_DAPM_MIXER("MIXER", CS42L42_PWR_CTL1, CS42L42_MIXER_PDN_SHIFT, 1, NULL, 0),
+ SND_SOC_DAPM_AIF_IN("SDIN1", NULL, 0, CS42L42_ASP_RX_DAI0_EN, CS42L42_ASP_RX0_CH1_SHIFT, 0),
+ SND_SOC_DAPM_AIF_IN("SDIN2", NULL, 1, CS42L42_ASP_RX_DAI0_EN, CS42L42_ASP_RX0_CH2_SHIFT, 0),
+
+ /* Playback Requirements */
+ SND_SOC_DAPM_SUPPLY("ASP DAI0", CS42L42_PWR_CTL1, CS42L42_ASP_DAI_PDN_SHIFT, 1, NULL, 0),
+
+ /* Capture Path */
+ SND_SOC_DAPM_INPUT("HS"),
+ SND_SOC_DAPM_ADC("ADC", NULL, CS42L42_PWR_CTL1, CS42L42_ADC_PDN_SHIFT, 1),
+ SND_SOC_DAPM_AIF_OUT("SDOUT1", NULL, 0, CS42L42_ASP_TX_CH_EN, CS42L42_ASP_TX0_CH1_SHIFT, 0),
+ SND_SOC_DAPM_AIF_OUT("SDOUT2", NULL, 1, CS42L42_ASP_TX_CH_EN, CS42L42_ASP_TX0_CH2_SHIFT, 0),
+
+ /* Capture Requirements */
+ SND_SOC_DAPM_SUPPLY("ASP DAO0", CS42L42_PWR_CTL1, CS42L42_ASP_DAO_PDN_SHIFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ASP TX EN", CS42L42_ASP_TX_SZ_EN, CS42L42_ASP_TX_EN_SHIFT, 0, NULL, 0),
+
+ /* Playback/Capture Requirements */
+ SND_SOC_DAPM_SUPPLY("SCLK", CS42L42_ASP_CLK_CFG, CS42L42_ASP_SCLK_EN_SHIFT, 0, NULL, 0),
};
static const struct snd_soc_dapm_route cs42l42_audio_map[] = {
- {"SDIN", NULL, "Playback"},
- {"HPDRV", NULL, "SDIN"},
- {"HP", NULL, "HPDRV"}
+ /* Playback Path */
+ {"HP", NULL, "DAC"},
+ {"DAC", NULL, "MIXER"},
+ {"MIXER", NULL, "SDIN1"},
+ {"MIXER", NULL, "SDIN2"},
+ {"SDIN1", NULL, "Playback"},
+ {"SDIN2", NULL, "Playback"},
+
+ /* Playback Requirements */
+ {"SDIN1", NULL, "ASP DAI0"},
+ {"SDIN2", NULL, "ASP DAI0"},
+ {"SDIN1", NULL, "SCLK"},
+ {"SDIN2", NULL, "SCLK"},
+
+ /* Capture Path */
+ {"ADC", NULL, "HS"},
+ { "SDOUT1", NULL, "ADC" },
+ { "SDOUT2", NULL, "ADC" },
+ { "Capture", NULL, "SDOUT1" },
+ { "Capture", NULL, "SDOUT2" },
+
+ /* Capture Requirements */
+ { "SDOUT1", NULL, "ASP DAO0" },
+ { "SDOUT2", NULL, "ASP DAO0" },
+ { "SDOUT1", NULL, "SCLK" },
+ { "SDOUT2", NULL, "SCLK" },
+ { "SDOUT1", NULL, "ASP TX EN" },
+ { "SDOUT2", NULL, "ASP TX EN" },
};
static int cs42l42_component_probe(struct snd_soc_component *component)
{
struct cs42l42_private *cs42l42 =
(struct cs42l42_private *)snd_soc_component_get_drvdata(component);
+ struct snd_soc_card *crd = component->card;
+ int ret = 0;
cs42l42->component = component;
- return 0;
+ ret = snd_soc_card_jack_new(crd, "CS42L42 Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &cs42l42->jack, NULL, 0);
+ if (ret < 0)
+ dev_err(component->dev, "Cannot create CS42L42 Headset: %d\n", ret);
+
+ return ret;
}
static const struct snd_soc_component_driver soc_component_dev_cs42l42 = {
@@ -534,6 +549,24 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l42 = {
.non_legacy_dai_naming = 1,
};
+/* Switch to SCLK. Atomic delay after the write to allow the switch to complete. */
+static const struct reg_sequence cs42l42_to_sclk_seq[] = {
+ {
+ .reg = CS42L42_OSC_SWITCH,
+ .def = CS42L42_SCLK_PRESENT_MASK,
+ .delay_us = CS42L42_CLOCK_SWITCH_DELAY_US,
+ },
+};
+
+/* Switch to OSC. Atomic delay after the write to allow the switch to complete. */
+static const struct reg_sequence cs42l42_to_osc_seq[] = {
+ {
+ .reg = CS42L42_OSC_SWITCH,
+ .def = 0,
+ .delay_us = CS42L42_CLOCK_SWITCH_DELAY_US,
+ },
+};
+
struct cs42l42_pll_params {
u32 sclk;
u8 mclk_div;
@@ -573,10 +606,16 @@ static int cs42l42_pll_config(struct snd_soc_component *component)
{
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
int i;
+ u32 clk;
u32 fsync;
+ if (!cs42l42->sclk)
+ clk = cs42l42->bclk;
+ else
+ clk = cs42l42->sclk;
+
for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
- if (pll_ratio_table[i].sclk == cs42l42->sclk) {
+ if (pll_ratio_table[i].sclk == clk) {
/* Configure the internal sample rate */
snd_soc_component_update_bits(component, CS42L42_MCLK_CTL,
CS42L42_INTERNAL_FS_MASK,
@@ -596,12 +635,12 @@ static int cs42l42_pll_config(struct snd_soc_component *component)
(pll_ratio_table[i].mclk_div <<
CS42L42_MCLKDIV_SHIFT));
/* Set up the LRCLK */
- fsync = cs42l42->sclk / cs42l42->srate;
- if (((fsync * cs42l42->srate) != cs42l42->sclk)
+ fsync = clk / cs42l42->srate;
+ if (((fsync * cs42l42->srate) != clk)
|| ((fsync % 2) != 0)) {
dev_err(component->dev,
"Unsupported sclk %d/sample rate %d\n",
- cs42l42->sclk,
+ clk,
cs42l42->srate);
return -EINVAL;
}
@@ -768,12 +807,25 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
+ unsigned int channels = params_channels(params);
unsigned int width = (params_width(params) / 8) - 1;
unsigned int val = 0;
cs42l42->srate = params_rate(params);
+ cs42l42->bclk = snd_soc_params_to_bclk(params);
switch(substream->stream) {
+ case SNDRV_PCM_STREAM_CAPTURE:
+ if (channels == 2) {
+ val |= CS42L42_ASP_TX_CH2_AP_MASK;
+ val |= width << CS42L42_ASP_TX_CH2_RES_SHIFT;
+ }
+ val |= width << CS42L42_ASP_TX_CH1_RES_SHIFT;
+
+ snd_soc_component_update_bits(component, CS42L42_ASP_TX_CH_AP_RES,
+ CS42L42_ASP_TX_CH1_AP_MASK | CS42L42_ASP_TX_CH2_AP_MASK |
+ CS42L42_ASP_TX_CH2_RES_MASK | CS42L42_ASP_TX_CH1_RES_MASK, val);
+ break;
case SNDRV_PCM_STREAM_PLAYBACK:
val |= width << CS42L42_ASP_RX_CH_RES_SHIFT;
/* channel 1 on low LRCLK */
@@ -804,52 +856,73 @@ static int cs42l42_set_sysclk(struct snd_soc_dai *dai,
return 0;
}
-static int cs42l42_mute(struct snd_soc_dai *dai, int mute, int direction)
+static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
{
struct snd_soc_component *component = dai->component;
+ struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
unsigned int regval;
u8 fullScaleVol;
+ int ret;
if (mute) {
- /* Mark SCLK as not present to turn on the internal
- * oscillator.
- */
- snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH,
- CS42L42_SCLK_PRESENT_MASK, 0);
-
- snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
- CS42L42_PLL_START_MASK,
- 0 << CS42L42_PLL_START_SHIFT);
-
/* Mute the headphone */
- snd_soc_component_update_bits(component, CS42L42_HP_CTL,
- CS42L42_HP_ANA_AMUTE_MASK |
- CS42L42_HP_ANA_BMUTE_MASK,
- CS42L42_HP_ANA_AMUTE_MASK |
- CS42L42_HP_ANA_BMUTE_MASK);
- } else {
- snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
- CS42L42_PLL_START_MASK,
- 1 << CS42L42_PLL_START_SHIFT);
- /* Read the headphone load */
- regval = snd_soc_component_read(component, CS42L42_LOAD_DET_RCSTAT);
- if (((regval & CS42L42_RLA_STAT_MASK) >>
- CS42L42_RLA_STAT_SHIFT) == CS42L42_RLA_STAT_15_OHM) {
- fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK;
- } else {
- fullScaleVol = 0;
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_component_update_bits(component, CS42L42_HP_CTL,
+ CS42L42_HP_ANA_AMUTE_MASK |
+ CS42L42_HP_ANA_BMUTE_MASK,
+ CS42L42_HP_ANA_AMUTE_MASK |
+ CS42L42_HP_ANA_BMUTE_MASK);
+
+ cs42l42->stream_use &= ~(1 << stream);
+ if(!cs42l42->stream_use) {
+ /*
+ * Switch to the internal oscillator.
+ * SCLK must remain running until after this clock switch.
+ * Without a source of clock the I2C bus doesn't work.
+ */
+ regmap_multi_reg_write(cs42l42->regmap, cs42l42_to_osc_seq,
+ ARRAY_SIZE(cs42l42_to_osc_seq));
+ snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
+ CS42L42_PLL_START_MASK, 0);
}
+ } else {
+ if (!cs42l42->stream_use) {
+ /* SCLK must be running before codec unmute */
+ if ((cs42l42->bclk < 11289600) && (cs42l42->sclk < 11289600)) {
+ snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
+ CS42L42_PLL_START_MASK, 1);
+ ret = regmap_read_poll_timeout(cs42l42->regmap,
+ CS42L42_PLL_LOCK_STATUS,
+ regval,
+ (regval & 1),
+ CS42L42_PLL_LOCK_POLL_US,
+ CS42L42_PLL_LOCK_TIMEOUT_US);
+ if (ret < 0)
+ dev_warn(component->dev, "PLL failed to lock: %d\n", ret);
+ }
- /* Un-mute the headphone, set the full scale volume flag */
- snd_soc_component_update_bits(component, CS42L42_HP_CTL,
- CS42L42_HP_ANA_AMUTE_MASK |
- CS42L42_HP_ANA_BMUTE_MASK |
- CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol);
+ /* Mark SCLK as present, turn off internal oscillator */
+ regmap_multi_reg_write(cs42l42->regmap, cs42l42_to_sclk_seq,
+ ARRAY_SIZE(cs42l42_to_sclk_seq));
+ }
+ cs42l42->stream_use |= 1 << stream;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* Read the headphone load */
+ regval = snd_soc_component_read(component, CS42L42_LOAD_DET_RCSTAT);
+ if (((regval & CS42L42_RLA_STAT_MASK) >> CS42L42_RLA_STAT_SHIFT) ==
+ CS42L42_RLA_STAT_15_OHM) {
+ fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK;
+ } else {
+ fullScaleVol = 0;
+ }
- /* Mark SCLK as present, turn off internal oscillator */
- snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH,
- CS42L42_SCLK_PRESENT_MASK,
- CS42L42_SCLK_PRESENT_MASK);
+ /* Un-mute the headphone, set the full scale volume flag */
+ snd_soc_component_update_bits(component, CS42L42_HP_CTL,
+ CS42L42_HP_ANA_AMUTE_MASK |
+ CS42L42_HP_ANA_BMUTE_MASK |
+ CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol);
+ }
}
return 0;
@@ -864,8 +937,7 @@ static const struct snd_soc_dai_ops cs42l42_ops = {
.hw_params = cs42l42_pcm_hw_params,
.set_fmt = cs42l42_set_dai_fmt,
.set_sysclk = cs42l42_set_sysclk,
- .mute_stream = cs42l42_mute,
- .no_capture_mute = 1,
+ .mute_stream = cs42l42_mute_stream,
};
static struct snd_soc_dai_driver cs42l42_dai = {
@@ -884,6 +956,8 @@ static struct snd_soc_dai_driver cs42l42_dai = {
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = CS42L42_FORMATS,
},
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
.ops = &cs42l42_ops,
};
@@ -1169,7 +1243,7 @@ static void cs42l42_cancel_hs_type_detect(struct cs42l42_private *cs42l42)
(3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
}
-static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42)
+static int cs42l42_handle_button_press(struct cs42l42_private *cs42l42)
{
int bias_level;
unsigned int detect_status;
@@ -1212,17 +1286,24 @@ static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42)
switch (bias_level) {
case 1: /* Function C button press */
+ bias_level = SND_JACK_BTN_2;
dev_dbg(cs42l42->component->dev, "Function C button press\n");
break;
case 2: /* Function B button press */
+ bias_level = SND_JACK_BTN_1;
dev_dbg(cs42l42->component->dev, "Function B button press\n");
break;
case 3: /* Function D button press */
+ bias_level = SND_JACK_BTN_3;
dev_dbg(cs42l42->component->dev, "Function D button press\n");
break;
case 4: /* Function A button press */
+ bias_level = SND_JACK_BTN_0;
dev_dbg(cs42l42->component->dev, "Function A button press\n");
break;
+ default:
+ bias_level = 0;
+ break;
}
/* Set button detect level sensitivity back to default */
@@ -1252,6 +1333,8 @@ static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42)
(0 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
(1 << CS42L42_M_SHORT_RLS_SHIFT) |
(1 << CS42L42_M_SHORT_DET_SHIFT));
+
+ return bias_level;
}
struct cs42l42_irq_params {
@@ -1296,6 +1379,8 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
unsigned int current_plug_status;
unsigned int current_button_status;
unsigned int i;
+ int report = 0;
+
/* Read sticky registers to clear interurpt */
for (i = 0; i < ARRAY_SIZE(stickies); i++) {
@@ -1322,9 +1407,20 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
if ((~masks[5]) & irq_params_table[5].mask) {
if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) {
cs42l42_process_hs_type_detect(cs42l42);
- dev_dbg(component->dev,
- "Auto detect done (%d)\n",
- cs42l42->hs_type);
+ switch(cs42l42->hs_type){
+ case CS42L42_PLUG_CTIA:
+ case CS42L42_PLUG_OMTP:
+ snd_soc_jack_report(&cs42l42->jack, SND_JACK_HEADSET,
+ SND_JACK_HEADSET);
+ break;
+ case CS42L42_PLUG_HEADPHONE:
+ snd_soc_jack_report(&cs42l42->jack, SND_JACK_HEADPHONE,
+ SND_JACK_HEADPHONE);
+ break;
+ default:
+ break;
+ }
+ dev_dbg(component->dev, "Auto detect done (%d)\n", cs42l42->hs_type);
}
}
@@ -1342,8 +1438,19 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
if (cs42l42->plug_state != CS42L42_TS_UNPLUG) {
cs42l42->plug_state = CS42L42_TS_UNPLUG;
cs42l42_cancel_hs_type_detect(cs42l42);
- dev_dbg(component->dev,
- "Unplug event\n");
+
+ switch(cs42l42->hs_type){
+ case CS42L42_PLUG_CTIA:
+ case CS42L42_PLUG_OMTP:
+ snd_soc_jack_report(&cs42l42->jack, 0, SND_JACK_HEADSET);
+ break;
+ case CS42L42_PLUG_HEADPHONE:
+ snd_soc_jack_report(&cs42l42->jack, 0, SND_JACK_HEADPHONE);
+ break;
+ default:
+ break;
+ }
+ dev_dbg(component->dev, "Unplug event\n");
}
break;
@@ -1358,14 +1465,15 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
if (!(current_button_status &
CS42L42_M_HSBIAS_HIZ_MASK)) {
- if (current_button_status &
- CS42L42_M_DETECT_TF_MASK) {
- dev_dbg(component->dev,
- "Button released\n");
- } else if (current_button_status &
- CS42L42_M_DETECT_FT_MASK) {
- cs42l42_handle_button_press(cs42l42);
+ if (current_button_status & CS42L42_M_DETECT_TF_MASK) {
+ dev_dbg(component->dev, "Button released\n");
+ report = 0;
+ } else if (current_button_status & CS42L42_M_DETECT_FT_MASK) {
+ report = cs42l42_handle_button_press(cs42l42);
+
}
+ snd_soc_jack_report(&cs42l42->jack, report, SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
}
}
@@ -1749,8 +1857,10 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
/* Reset the Device */
cs42l42->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
"reset", GPIOD_OUT_LOW);
- if (IS_ERR(cs42l42->reset_gpio))
- return PTR_ERR(cs42l42->reset_gpio);
+ if (IS_ERR(cs42l42->reset_gpio)) {
+ ret = PTR_ERR(cs42l42->reset_gpio);
+ goto err_disable;
+ }
if (cs42l42->reset_gpio) {
dev_dbg(&i2c_client->dev, "Found reset GPIO\n");
@@ -1784,13 +1894,13 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
dev_err(&i2c_client->dev,
"CS42L42 Device ID (%X). Expected %X\n",
devid, CS42L42_CHIP_ID);
- return ret;
+ goto err_disable;
}
ret = regmap_read(cs42l42->regmap, CS42L42_REVID, &reg);
if (ret < 0) {
dev_err(&i2c_client->dev, "Get Revision ID failed\n");
- return ret;
+ goto err_disable;
}
dev_info(&i2c_client->dev,
@@ -1816,7 +1926,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
if (i2c_client->dev.of_node) {
ret = cs42l42_handle_device_data(i2c_client, cs42l42);
if (ret != 0)
- return ret;
+ goto err_disable;
}
/* Setup headset detection */
@@ -1842,8 +1952,9 @@ static int cs42l42_i2c_remove(struct i2c_client *i2c_client)
{
struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client);
- /* Hold down reset */
- gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
+ devm_free_irq(&i2c_client->dev, i2c_client->irq, cs42l42);
+ pm_runtime_suspend(&i2c_client->dev);
+ pm_runtime_disable(&i2c_client->dev);
return 0;
}
diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h
index 866d7c873e3c..36b763f0d1a0 100644
--- a/sound/soc/codecs/cs42l42.h
+++ b/sound/soc/codecs/cs42l42.h
@@ -12,6 +12,8 @@
#ifndef __CS42L42_H__
#define __CS42L42_H__
+#include <sound/jack.h>
+
#define CS42L42_PAGE_REGISTER 0x00 /* Page Select Register */
#define CS42L42_WIN_START 0x00
#define CS42L42_WIN_LEN 0x100
@@ -683,8 +685,20 @@
/* Page 0x29 Serial Port TX Registers */
#define CS42L42_ASP_TX_SZ_EN (CS42L42_PAGE_29 + 0x01)
+#define CS42L42_ASP_TX_EN_SHIFT 0
#define CS42L42_ASP_TX_CH_EN (CS42L42_PAGE_29 + 0x02)
+#define CS42L42_ASP_TX0_CH2_SHIFT 1
+#define CS42L42_ASP_TX0_CH1_SHIFT 0
+
#define CS42L42_ASP_TX_CH_AP_RES (CS42L42_PAGE_29 + 0x03)
+#define CS42L42_ASP_TX_CH1_AP_SHIFT 7
+#define CS42L42_ASP_TX_CH1_AP_MASK (1 << CS42L42_ASP_TX_CH1_AP_SHIFT)
+#define CS42L42_ASP_TX_CH2_AP_SHIFT 6
+#define CS42L42_ASP_TX_CH2_AP_MASK (1 << CS42L42_ASP_TX_CH2_AP_SHIFT)
+#define CS42L42_ASP_TX_CH2_RES_SHIFT 2
+#define CS42L42_ASP_TX_CH2_RES_MASK (3 << CS42L42_ASP_TX_CH2_RES_SHIFT)
+#define CS42L42_ASP_TX_CH1_RES_SHIFT 0
+#define CS42L42_ASP_TX_CH1_RES_MASK (3 << CS42L42_ASP_TX_CH1_RES_SHIFT)
#define CS42L42_ASP_TX_CH1_BIT_MSB (CS42L42_PAGE_29 + 0x04)
#define CS42L42_ASP_TX_CH1_BIT_LSB (CS42L42_PAGE_29 + 0x05)
#define CS42L42_ASP_TX_HIZ_DLY_CFG (CS42L42_PAGE_29 + 0x06)
@@ -695,10 +709,10 @@
#define CS42L42_ASP_RX_DAI0_EN (CS42L42_PAGE_2A + 0x01)
#define CS42L42_ASP_RX0_CH_EN_SHIFT 2
#define CS42L42_ASP_RX0_CH_EN_MASK (0xf << CS42L42_ASP_RX0_CH_EN_SHIFT)
-#define CS42L42_ASP_RX0_CH1_EN 1
-#define CS42L42_ASP_RX0_CH2_EN 2
-#define CS42L42_ASP_RX0_CH3_EN 4
-#define CS42L42_ASP_RX0_CH4_EN 8
+#define CS42L42_ASP_RX0_CH1_SHIFT 2
+#define CS42L42_ASP_RX0_CH2_SHIFT 3
+#define CS42L42_ASP_RX0_CH3_SHIFT 4
+#define CS42L42_ASP_RX0_CH4_SHIFT 5
#define CS42L42_ASP_RX_DAI0_CH1_AP_RES (CS42L42_PAGE_2A + 0x02)
#define CS42L42_ASP_RX_DAI0_CH1_BIT_MSB (CS42L42_PAGE_2A + 0x03)
@@ -741,6 +755,9 @@
#define CS42L42_NUM_SUPPLIES 5
#define CS42L42_BOOT_TIME_US 3000
+#define CS42L42_CLOCK_SWITCH_DELAY_US 150
+#define CS42L42_PLL_LOCK_POLL_US 250
+#define CS42L42_PLL_LOCK_TIMEOUT_US 1250
static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = {
"VA",
@@ -756,6 +773,8 @@ struct cs42l42_private {
struct regulator_bulk_data supplies[CS42L42_NUM_SUPPLIES];
struct gpio_desc *reset_gpio;
struct completion pdn_done;
+ struct snd_soc_jack jack;
+ int bclk;
u32 sclk;
u32 srate;
u8 plug_state;
@@ -768,6 +787,7 @@ struct cs42l42_private {
u8 bias_thresholds[CS42L42_NUM_BIASES];
u8 hs_bias_ramp_rate;
u8 hs_bias_ramp_time;
+ u8 stream_use;
};
#endif /* __CS42L42_H__ */
diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c
index 8ab22815c2c9..1f5c57fab1d8 100644
--- a/sound/soc/codecs/cx2072x.c
+++ b/sound/soc/codecs/cx2072x.c
@@ -827,9 +827,6 @@ static int cx2072x_config_i2spcm(struct cx2072x_priv *cx2072x)
}
regdbt2.r.i2s_bclk_invert = is_bclk_inv;
- reg1.r.rx_data_one_line = 1;
- reg1.r.tx_data_one_line = 1;
-
/* Configures the BCLK output */
bclk_rate = cx2072x->sample_rate * frame_len;
reg5.r.i2s_pcm_clk_div_chan_en = 0;
@@ -1433,11 +1430,11 @@ static int cx2072x_jack_status_check(void *data)
state |= SND_JACK_HEADSET;
if (type & 0x2)
state |= SND_JACK_BTN_0;
- } else if (type & 0x4) {
- /* Nokia headset */
- state |= SND_JACK_HEADPHONE;
} else {
- /* Headphone */
+ /*
+ * Nokia headset (type & 0x4) and
+ * regular Headphone
+ */
state |= SND_JACK_HEADPHONE;
}
}
@@ -1535,7 +1532,7 @@ static const struct snd_soc_component_driver soc_codec_driver_cx2072x = {
/*
* DAI ops
*/
-static struct snd_soc_dai_ops cx2072x_dai_ops = {
+static const struct snd_soc_dai_ops cx2072x_dai_ops = {
.set_sysclk = cx2072x_set_dai_sysclk,
.set_fmt = cx2072x_set_dai_fmt,
.hw_params = cx2072x_hw_params,
diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c
index 48081d71c22c..7998fdd3b378 100644
--- a/sound/soc/codecs/da7219-aad.c
+++ b/sound/soc/codecs/da7219-aad.c
@@ -115,7 +115,7 @@ static void da7219_aad_hptest_work(struct work_struct *work)
__le16 tonegen_freq_hptest;
u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8;
- int report = 0, ret = 0;
+ int report = 0, ret;
/* Lock DAPM, Kcontrols affected by this test and the PLL */
snd_soc_dapm_mutex_lock(dapm);
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 13009d08b09a..bd3c523a8617 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -2181,7 +2181,10 @@ static int da7219_register_dai_clks(struct snd_soc_component *component)
ret);
goto err;
}
- da7219->dai_clks[i] = dai_clk_hw->clk;
+
+ da7219->dai_clks[i] = devm_clk_hw_get_clk(dev, dai_clk_hw, NULL);
+ if (IS_ERR(da7219->dai_clks[i]))
+ return PTR_ERR(da7219->dai_clks[i]);
/* For DT setup onecell data, otherwise create lookup */
if (np) {
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index d43ee7159ae0..42d6a3fc3af5 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -168,30 +168,25 @@ static const struct reg_default da732x_reg_cache[] = {
static inline int da732x_get_input_div(struct snd_soc_component *component, int sysclk)
{
int val;
- int ret;
if (sysclk < DA732X_MCLK_10MHZ) {
- val = DA732X_MCLK_RET_0_10MHZ;
- ret = DA732X_MCLK_VAL_0_10MHZ;
+ val = DA732X_MCLK_VAL_0_10MHZ;
} else if ((sysclk >= DA732X_MCLK_10MHZ) &&
(sysclk < DA732X_MCLK_20MHZ)) {
- val = DA732X_MCLK_RET_10_20MHZ;
- ret = DA732X_MCLK_VAL_10_20MHZ;
+ val = DA732X_MCLK_VAL_10_20MHZ;
} else if ((sysclk >= DA732X_MCLK_20MHZ) &&
(sysclk < DA732X_MCLK_40MHZ)) {
- val = DA732X_MCLK_RET_20_40MHZ;
- ret = DA732X_MCLK_VAL_20_40MHZ;
+ val = DA732X_MCLK_VAL_20_40MHZ;
} else if ((sysclk >= DA732X_MCLK_40MHZ) &&
(sysclk <= DA732X_MCLK_54MHZ)) {
- val = DA732X_MCLK_RET_40_54MHZ;
- ret = DA732X_MCLK_VAL_40_54MHZ;
+ val = DA732X_MCLK_VAL_40_54MHZ;
} else {
return -EINVAL;
}
snd_soc_component_write(component, DA732X_REG_PLL_CTRL, val);
- return ret;
+ return val;
}
static void da732x_set_charge_pump(struct snd_soc_component *component, int state)
@@ -1158,7 +1153,7 @@ static int da732x_set_dai_pll(struct snd_soc_component *component, int pll_id,
if (indiv < 0)
return indiv;
- fref = (da732x->sysclk / indiv);
+ fref = da732x->sysclk / BIT(indiv);
div_hi = freq_out / fref;
frac_div = (u64)(freq_out % fref) * 8192ULL;
do_div(frac_div, fref);
diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h
index c5af17ee1516..c2f784c3f359 100644
--- a/sound/soc/codecs/da732x.h
+++ b/sound/soc/codecs/da732x.h
@@ -48,14 +48,10 @@
#define DA732X_MCLK_20MHZ 20000000
#define DA732X_MCLK_40MHZ 40000000
#define DA732X_MCLK_54MHZ 54000000
-#define DA732X_MCLK_RET_0_10MHZ 0
-#define DA732X_MCLK_VAL_0_10MHZ 1
-#define DA732X_MCLK_RET_10_20MHZ 1
-#define DA732X_MCLK_VAL_10_20MHZ 2
-#define DA732X_MCLK_RET_20_40MHZ 2
-#define DA732X_MCLK_VAL_20_40MHZ 4
-#define DA732X_MCLK_RET_40_54MHZ 3
-#define DA732X_MCLK_VAL_40_54MHZ 8
+#define DA732X_MCLK_VAL_0_10MHZ 0
+#define DA732X_MCLK_VAL_10_20MHZ 1
+#define DA732X_MCLK_VAL_20_40MHZ 2
+#define DA732X_MCLK_VAL_40_54MHZ 3
#define DA732X_DAI_ID1 0
#define DA732X_DAI_ID2 1
#define DA732X_SRCCLK_PLL 0
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 2c1305bf0572..66408a98298b 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -523,7 +523,7 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
struct hdac_hdmi_cvt *cvt)
{
struct hdac_hdmi_pcm *pcm;
- struct hdac_hdmi_port *port = NULL;
+ struct hdac_hdmi_port *port;
int ret, i;
list_for_each_entry(pcm, &hdmi->pcm_list, head) {
@@ -713,7 +713,7 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_device *hdev,
struct hdac_hdmi_port *port)
{
struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
- struct hdac_hdmi_pcm *pcm = NULL;
+ struct hdac_hdmi_pcm *pcm;
struct hdac_hdmi_port *p;
list_for_each_entry(pcm, &hdmi->pcm_list, head) {
@@ -900,7 +900,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
struct hdac_hdmi_port *port = w->priv;
struct hdac_device *hdev = dev_to_hdac_dev(dapm->dev);
struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
- struct hdac_hdmi_pcm *pcm = NULL;
+ struct hdac_hdmi_pcm *pcm;
const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0]];
ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
@@ -1693,7 +1693,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
{
struct hdac_device *hdev = aptr;
struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
- struct hdac_hdmi_pin *pin = NULL;
+ struct hdac_hdmi_pin *pin;
struct hdac_hdmi_port *hport = NULL;
struct snd_soc_component *component = hdmi->component;
int i;
@@ -1958,7 +1958,7 @@ static int hdmi_codec_probe(struct snd_soc_component *component)
struct hdac_device *hdev = hdmi->hdev;
struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(component);
- struct hdac_ext_link *hlink = NULL;
+ struct hdac_ext_link *hlink;
int ret;
hdmi->component = component;
@@ -2227,7 +2227,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
{
struct hdac_device *hdev = dev_to_hdac_dev(dev);
struct hdac_bus *bus = hdev->bus;
- struct hdac_ext_link *hlink = NULL;
+ struct hdac_ext_link *hlink;
dev_dbg(dev, "Enter: %s\n", __func__);
@@ -2263,7 +2263,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
{
struct hdac_device *hdev = dev_to_hdac_dev(dev);
struct hdac_bus *bus = hdev->bus;
- struct hdac_ext_link *hlink = NULL;
+ struct hdac_ext_link *hlink;
dev_dbg(dev, "Enter: %s\n", __func__);
diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h
index 4fa2fc9ee893..493fa3b4ef75 100644
--- a/sound/soc/codecs/hdac_hdmi.h
+++ b/sound/soc/codecs/hdac_hdmi.h
@@ -2,7 +2,7 @@
#ifndef __HDAC_HDMI_H__
#define __HDAC_HDMI_H__
-int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm,
+int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
struct snd_soc_jack *jack);
int hdac_hdmi_jack_port_init(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 422539f933de..1567ba196ab9 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -22,7 +22,6 @@
struct hdmi_codec_channel_map_table {
unsigned char map; /* ALSA API channel map position */
- unsigned long spk_mask; /* speaker position bit mask */
};
/*
@@ -735,7 +734,7 @@ static int hdmi_codec_set_jack(struct snd_soc_component *component,
static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai)
{
- struct hdmi_codec_daifmt *cf = dai->playback_dma_data;
+ struct hdmi_codec_daifmt *cf;
int ret;
ret = hdmi_dai_probe(dai);
diff --git a/sound/soc/codecs/jz4760.c b/sound/soc/codecs/jz4760.c
index e8f28ccc145a..d96a4f6c9183 100644
--- a/sound/soc/codecs/jz4760.c
+++ b/sound/soc/codecs/jz4760.c
@@ -198,7 +198,7 @@ static int jz4760_codec_startup(struct snd_pcm_substream *substream,
{
struct snd_soc_component *codec = dai->component;
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
- int ret;
+ int ret = 0;
/*
* SYSCLK output from the codec to the AIC is required to keep the
@@ -207,7 +207,7 @@ static int jz4760_codec_startup(struct snd_pcm_substream *substream,
*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
ret = snd_soc_dapm_force_enable_pin(dapm, "SYSCLK");
- return 0;
+ return ret;
}
static void jz4760_codec_shutdown(struct snd_pcm_substream *substream,
@@ -841,11 +841,8 @@ static int jz4760_codec_probe(struct platform_device *pdev)
codec->dev = dev;
codec->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(codec->base)) {
- ret = PTR_ERR(codec->base);
- dev_err(dev, "Failed to ioremap mmio memory: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(codec->base))
+ return PTR_ERR(codec->base);
codec->regmap = devm_regmap_init(dev, NULL, codec,
&jz4760_codec_regmap_config);
diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c
index c9fe7f72bfcb..6b60120f59a6 100644
--- a/sound/soc/codecs/jz4770.c
+++ b/sound/soc/codecs/jz4770.c
@@ -893,11 +893,8 @@ static int jz4770_codec_probe(struct platform_device *pdev)
codec->dev = dev;
codec->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(codec->base)) {
- ret = PTR_ERR(codec->base);
- dev_err(dev, "Failed to ioremap mmio memory: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(codec->base))
+ return PTR_ERR(codec->base);
codec->regmap = devm_regmap_init(dev, NULL, codec,
&jz4770_codec_regmap_config);
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index eb3dd0bd80d9..fb0fb23537e7 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -1206,8 +1206,6 @@ static int lm49453_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
break;
case 48000:
case 32576:
- /* fll clk slection */
- pll_clk = BIT(4);
return 0;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
index 7878da89d8e0..b0ebfc8d180c 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -1620,8 +1620,6 @@ static int rx_macro_set_interpolator_rate(struct snd_soc_dai *dai,
return ret;
ret = rx_macro_set_mix_interpolator_rate(dai, rate_val, sample_rate);
- if (ret)
- return ret;
return ret;
}
@@ -1767,7 +1765,7 @@ static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
-static struct snd_soc_dai_ops rx_macro_dai_ops = {
+static const struct snd_soc_dai_ops rx_macro_dai_ops = {
.hw_params = rx_macro_hw_params,
.get_channel_map = rx_macro_get_channel_map,
.mute_stream = rx_macro_digital_mute,
@@ -2038,7 +2036,7 @@ static int rx_macro_load_compander_coeff(struct snd_soc_component *component,
{
u16 comp_coeff_lsb_reg, comp_coeff_msb_reg;
int i;
- int hph_pwr_mode = HPH_LOHIFI;
+ int hph_pwr_mode;
if (!rx->comp_enabled[comp])
return 0;
@@ -3585,7 +3583,6 @@ static const struct of_device_id rx_macro_dt_match[] = {
static struct platform_driver rx_macro_driver = {
.driver = {
.name = "rx_macro",
- .owner = THIS_MODULE,
.of_match_table = rx_macro_dt_match,
.suppress_bind_attrs = true,
},
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
index e8c6c738bbaa..acd2fbc0ca7c 100644
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -1124,7 +1124,7 @@ static int tx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
-static struct snd_soc_dai_ops tx_macro_dai_ops = {
+static const struct snd_soc_dai_ops tx_macro_dai_ops = {
.hw_params = tx_macro_hw_params,
.get_channel_map = tx_macro_get_channel_map,
.mute_stream = tx_macro_digital_mute,
diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c
index 3d6976a3d9e4..56c93f4465c9 100644
--- a/sound/soc/codecs/lpass-va-macro.c
+++ b/sound/soc/codecs/lpass-va-macro.c
@@ -894,7 +894,7 @@ static int va_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
-static struct snd_soc_dai_ops va_macro_dai_ops = {
+static const struct snd_soc_dai_ops va_macro_dai_ops = {
.hw_params = va_macro_hw_params,
.get_channel_map = va_macro_get_channel_map,
.mute_stream = va_macro_digital_mute,
@@ -1343,7 +1343,7 @@ static int va_macro_register_fsgen_output(struct va_macro *va)
if (ret)
return ret;
- return of_clk_add_provider(np, of_clk_src_simple_get, va->hw.clk);
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &va->hw);
}
static int va_macro_validate_dmic_sample_rate(u32 dmic_sample_rate,
@@ -1452,12 +1452,10 @@ static int va_macro_probe(struct platform_device *pdev)
va_macro_dais,
ARRAY_SIZE(va_macro_dais));
if (ret)
- goto soc_err;
+ goto err;
return ret;
-soc_err:
- of_clk_del_provider(pdev->dev.of_node);
err:
clk_bulk_disable_unprepare(VA_NUM_CLKS_MAX, va->clks);
@@ -1468,7 +1466,6 @@ static int va_macro_remove(struct platform_device *pdev)
{
struct va_macro *va = dev_get_drvdata(&pdev->dev);
- of_clk_del_provider(pdev->dev.of_node);
clk_bulk_disable_unprepare(VA_NUM_CLKS_MAX, va->clks);
return 0;
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index 9ca49a165f69..1a7fa5492f28 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -944,6 +944,8 @@ static int wsa_macro_set_interpolator_rate(struct snd_soc_dai *dai,
goto prim_rate;
ret = wsa_macro_set_mix_interpolator_rate(dai, (u8) rate_val, sample_rate);
+ if (ret < 0)
+ return ret;
prim_rate:
/* set primary path sample rate */
for (i = 0; i < ARRAY_SIZE(int_prim_sample_rate_val); i++) {
@@ -1029,7 +1031,7 @@ static int wsa_macro_get_channel_map(struct snd_soc_dai *dai,
return 0;
}
-static struct snd_soc_dai_ops wsa_macro_dai_ops = {
+static const struct snd_soc_dai_ops wsa_macro_dai_ops = {
.hw_params = wsa_macro_hw_params,
.get_channel_map = wsa_macro_get_channel_map,
};
@@ -2335,10 +2337,9 @@ static const struct clk_ops swclk_gate_ops = {
.recalc_rate = swclk_recalc_rate,
};
-static struct clk *wsa_macro_register_mclk_output(struct wsa_macro *wsa)
+static int wsa_macro_register_mclk_output(struct wsa_macro *wsa)
{
struct device *dev = wsa->dev;
- struct device_node *np = dev->of_node;
const char *parent_clk_name;
const char *clk_name = "mclk";
struct clk_hw *hw;
@@ -2356,11 +2357,9 @@ static struct clk *wsa_macro_register_mclk_output(struct wsa_macro *wsa)
hw = &wsa->hw;
ret = clk_hw_register(wsa->dev, hw);
if (ret)
- return ERR_PTR(ret);
-
- of_clk_add_provider(np, of_clk_src_simple_get, hw->clk);
+ return ret;
- return NULL;
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
}
static const struct snd_soc_component_driver wsa_macro_component_drv = {
@@ -2436,8 +2435,6 @@ static int wsa_macro_remove(struct platform_device *pdev)
{
struct wsa_macro *wsa = dev_get_drvdata(&pdev->dev);
- of_clk_del_provider(pdev->dev.of_node);
-
clk_bulk_disable_unprepare(WSA_NUM_CLKS_MAX, wsa->clks);
return 0;
diff --git a/sound/soc/codecs/madera.h b/sound/soc/codecs/madera.h
index e0c0be59e2ef..09ad6e9bce4b 100644
--- a/sound/soc/codecs/madera.h
+++ b/sound/soc/codecs/madera.h
@@ -430,7 +430,7 @@ int madera_init_bus_error_irq(struct madera_priv *priv, int dsp_num,
irq_handler_t handler);
void madera_free_bus_error_irq(struct madera_priv *priv, int dsp_num);
-int madera_init_dai(struct madera_priv *priv, int dai);
+int madera_init_dai(struct madera_priv *priv, int id);
int madera_set_output_mode(struct snd_soc_component *component, int output,
bool differential);
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 06276ff5f8a3..bc30a1dc7530 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -1832,7 +1832,7 @@ static const struct dmic_table dmic_table[] = { /* One for each pclk freq. */
static int max98090_find_divisor(int target_freq, int pclk)
{
int current_diff = INT_MAX;
- int test_diff = INT_MAX;
+ int test_diff;
int divisor_index = 0;
int i;
diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c
index 1346a98ce8a1..e14fe98349a5 100644
--- a/sound/soc/codecs/max98373.c
+++ b/sound/soc/codecs/max98373.c
@@ -204,6 +204,15 @@ SOC_SINGLE("Ramp Up Switch", MAX98373_R203F_AMP_DSP_CFG,
MAX98373_AMP_DSP_CFG_RMP_UP_SHIFT, 1, 0),
SOC_SINGLE("Ramp Down Switch", MAX98373_R203F_AMP_DSP_CFG,
MAX98373_AMP_DSP_CFG_RMP_DN_SHIFT, 1, 0),
+/* Speaker Amplifier Overcurrent Automatic Restart Enable */
+SOC_SINGLE("OVC Autorestart Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
+ MAX98373_OVC_AUTORESTART_SHIFT, 1, 0),
+/* Thermal Shutdown Automatic Restart Enable */
+SOC_SINGLE("THERM Autorestart Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
+ MAX98373_THERM_AUTORESTART_SHIFT, 1, 0),
+/* Clock Monitor Automatic Restart Enable */
+SOC_SINGLE("CMON Autorestart Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
+ MAX98373_CMON_AUTORESTART_SHIFT, 1, 0),
SOC_SINGLE("CLK Monitor Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
MAX98373_CLOCK_MON_SHIFT, 1, 0),
SOC_SINGLE("Dither Switch", MAX98373_R203F_AMP_DSP_CFG,
@@ -392,6 +401,11 @@ static int max98373_probe(struct snd_soc_component *component)
MAX98373_R2021_PCM_TX_HIZ_EN_2,
1 << (max98373->i_slot - 8), 0);
+ /* enable auto restart function by default */
+ regmap_write(max98373->regmap,
+ MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
+ 0xF);
+
/* speaker feedback slot configuration */
regmap_write(max98373->regmap,
MAX98373_R2023_PCM_TX_SRC_2,
diff --git a/sound/soc/codecs/max98373.h b/sound/soc/codecs/max98373.h
index 71f5a5228f34..73a2cf69d84a 100644
--- a/sound/soc/codecs/max98373.h
+++ b/sound/soc/codecs/max98373.h
@@ -195,6 +195,9 @@
#define MAX98373_LIMITER_EN_SHIFT (0)
/* MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG */
+#define MAX98373_OVC_AUTORESTART_SHIFT (3)
+#define MAX98373_THERM_AUTORESTART_SHIFT (2)
+#define MAX98373_CMON_AUTORESTART_SHIFT (1)
#define MAX98373_CLOCK_MON_SHIFT (0)
/* MAX98373_R20FF_GLOBAL_SHDN */
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
index bb736c44e68a..94773ccee9d5 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -856,6 +856,48 @@ static void max98390_init_regs(struct snd_soc_component *component)
regmap_write(max98390->regmap, MAX98390_ENV_TRACK_VOUT_HEADROOM, 0x0e);
regmap_write(max98390->regmap, MAX98390_BOOST_BYPASS1, 0x46);
regmap_write(max98390->regmap, MAX98390_FET_SCALING3, 0x03);
+
+ /* voltage, current slot configuration */
+ regmap_write(max98390->regmap,
+ MAX98390_PCM_CH_SRC_2,
+ (max98390->i_l_slot << 4 |
+ max98390->v_l_slot)&0xFF);
+
+ if (max98390->v_l_slot < 8) {
+ regmap_update_bits(max98390->regmap,
+ MAX98390_PCM_TX_HIZ_CTRL_A,
+ 1 << max98390->v_l_slot, 0);
+ regmap_update_bits(max98390->regmap,
+ MAX98390_PCM_TX_EN_A,
+ 1 << max98390->v_l_slot,
+ 1 << max98390->v_l_slot);
+ } else {
+ regmap_update_bits(max98390->regmap,
+ MAX98390_PCM_TX_HIZ_CTRL_B,
+ 1 << (max98390->v_l_slot - 8), 0);
+ regmap_update_bits(max98390->regmap,
+ MAX98390_PCM_TX_EN_B,
+ 1 << (max98390->v_l_slot - 8),
+ 1 << (max98390->v_l_slot - 8));
+ }
+
+ if (max98390->i_l_slot < 8) {
+ regmap_update_bits(max98390->regmap,
+ MAX98390_PCM_TX_HIZ_CTRL_A,
+ 1 << max98390->i_l_slot, 0);
+ regmap_update_bits(max98390->regmap,
+ MAX98390_PCM_TX_EN_A,
+ 1 << max98390->i_l_slot,
+ 1 << max98390->i_l_slot);
+ } else {
+ regmap_update_bits(max98390->regmap,
+ MAX98390_PCM_TX_HIZ_CTRL_B,
+ 1 << (max98390->i_l_slot - 8), 0);
+ regmap_update_bits(max98390->regmap,
+ MAX98390_PCM_TX_EN_B,
+ 1 << (max98390->i_l_slot - 8),
+ 1 << (max98390->i_l_slot - 8));
+ }
}
static int max98390_probe(struct snd_soc_component *component)
@@ -946,6 +988,23 @@ static const struct regmap_config max98390_regmap = {
.cache_type = REGCACHE_RBTREE,
};
+static void max98390_slot_config(struct i2c_client *i2c,
+ struct max98390_priv *max98390)
+{
+ int value;
+ struct device *dev = &i2c->dev;
+
+ if (!device_property_read_u32(dev, "maxim,vmon-slot-no", &value))
+ max98390->v_l_slot = value & 0xF;
+ else
+ max98390->v_l_slot = 0;
+
+ if (!device_property_read_u32(dev, "maxim,imon-slot-no", &value))
+ max98390->i_l_slot = value & 0xF;
+ else
+ max98390->i_l_slot = 1;
+}
+
static int max98390_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -988,6 +1047,9 @@ static int max98390_i2c_probe(struct i2c_client *i2c,
__func__, max98390->ref_rdc_value,
max98390->ambient_temp_value);
+ /* voltage/current slot configuration */
+ max98390_slot_config(i2c, max98390);
+
/* regmap initialization */
max98390->regmap = devm_regmap_init_i2c(i2c, &max98390_regmap);
if (IS_ERR(max98390->regmap)) {
diff --git a/sound/soc/codecs/max98390.h b/sound/soc/codecs/max98390.h
index dff884f68e3e..e31516717d3b 100644
--- a/sound/soc/codecs/max98390.h
+++ b/sound/soc/codecs/max98390.h
@@ -658,6 +658,8 @@ struct max98390_priv {
unsigned int sysclk;
unsigned int master;
unsigned int tdm_mode;
+ unsigned int v_l_slot;
+ unsigned int i_l_slot;
unsigned int ref_rdc_value;
unsigned int ambient_temp_value;
};
diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c
index 1f39d5998cf6..9b263a9a669d 100644
--- a/sound/soc/codecs/mt6358.c
+++ b/sound/soc/codecs/mt6358.c
@@ -331,7 +331,7 @@ static void hp_zcd_disable(struct mt6358_priv *priv)
static void hp_main_output_ramp(struct mt6358_priv *priv, bool up)
{
- int i = 0, stage = 0;
+ int i, stage;
int target = 7;
/* Enable/Reduce HPL/R main output stage step by step */
@@ -347,7 +347,7 @@ static void hp_main_output_ramp(struct mt6358_priv *priv, bool up)
static void hp_aux_feedback_loop_gain_ramp(struct mt6358_priv *priv, bool up)
{
- int i = 0, stage = 0;
+ int i, stage;
/* Reduce HP aux feedback loop gain step by step */
for (i = 0; i <= 0xf; i++) {
diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c
new file mode 100644
index 000000000000..4222aed013f1
--- /dev/null
+++ b/sound/soc/codecs/mt6359-accdet.c
@@ -0,0 +1,1080 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt6359-accdet.c -- ALSA SoC mt6359 accdet driver
+//
+// Copyright (C) 2021 MediaTek Inc.
+// Author: Argus Lin <argus.lin@mediatek.com>
+//
+
+#include <linux/of_gpio.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/input.h>
+#include <linux/kthread.h>
+#include <linux/io.h>
+#include <linux/sched/clock.h>
+#include <linux/workqueue.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <linux/mfd/mt6397/core.h>
+
+#include "mt6359-accdet.h"
+#include "mt6359.h"
+
+/* global variable definitions */
+#define REGISTER_VAL(x) ((x) - 1)
+
+/* mt6359 accdet capability */
+#define ACCDET_PMIC_EINT_IRQ BIT(0)
+#define ACCDET_AP_GPIO_EINT BIT(1)
+
+#define ACCDET_PMIC_EINT0 BIT(2)
+#define ACCDET_PMIC_EINT1 BIT(3)
+#define ACCDET_PMIC_BI_EINT BIT(4)
+
+#define ACCDET_PMIC_GPIO_TRIG_EINT BIT(5)
+#define ACCDET_PMIC_INVERTER_TRIG_EINT BIT(6)
+#define ACCDET_PMIC_RSV_EINT BIT(7)
+
+#define ACCDET_THREE_KEY BIT(8)
+#define ACCDET_FOUR_KEY BIT(9)
+#define ACCDET_TRI_KEY_CDD BIT(10)
+#define ACCDET_RSV_KEY BIT(11)
+
+#define ACCDET_ANALOG_FASTDISCHARGE BIT(12)
+#define ACCDET_DIGITAL_FASTDISCHARGE BIT(13)
+#define ACCDET_AD_FASTDISCHRAGE BIT(14)
+
+static struct platform_driver mt6359_accdet_driver;
+static const struct snd_soc_component_driver mt6359_accdet_soc_driver;
+
+/* local function declaration */
+static void accdet_set_debounce(struct mt6359_accdet *priv, int state,
+ unsigned int debounce);
+static unsigned int adjust_eint_analog_setting(struct mt6359_accdet *priv);
+static void config_digital_init_by_mode(struct mt6359_accdet *priv);
+static void config_eint_init_by_mode(struct mt6359_accdet *priv);
+static inline void mt6359_accdet_init(struct mt6359_accdet *priv);
+static unsigned int mt6359_accdet_jd_setting(struct mt6359_accdet *priv);
+static void mt6359_accdet_recover_jd_setting(struct mt6359_accdet *priv);
+static void mt6359_accdet_jack_report(struct mt6359_accdet *priv);
+static void recover_eint_analog_setting(struct mt6359_accdet *priv);
+static void recover_eint_digital_setting(struct mt6359_accdet *priv);
+static void recover_eint_setting(struct mt6359_accdet *priv);
+
+static unsigned int adjust_eint_analog_setting(struct mt6359_accdet *priv)
+{
+ if (priv->data->eint_detect_mode == 0x3 ||
+ priv->data->eint_detect_mode == 0x4) {
+ /* ESD switches off */
+ regmap_update_bits(priv->regmap,
+ RG_ACCDETSPARE_ADDR, 1 << 8, 0);
+ }
+ if (priv->data->eint_detect_mode == 0x4) {
+ if (priv->caps & ACCDET_PMIC_EINT0) {
+ /* enable RG_EINT0CONFIGACCDET */
+ regmap_update_bits(priv->regmap,
+ RG_EINT0CONFIGACCDET_ADDR,
+ RG_EINT0CONFIGACCDET_MASK_SFT,
+ BIT(RG_EINT0CONFIGACCDET_SFT));
+ } else if (priv->caps & ACCDET_PMIC_EINT1) {
+ /* enable RG_EINT1CONFIGACCDET */
+ regmap_update_bits(priv->regmap,
+ RG_EINT1CONFIGACCDET_ADDR,
+ RG_EINT1CONFIGACCDET_MASK_SFT,
+ BIT(RG_EINT1CONFIGACCDET_SFT));
+ }
+ if (priv->data->eint_use_ext_res == 0x3 ||
+ priv->data->eint_use_ext_res == 0x4) {
+ /*select 500k, use internal resistor */
+ regmap_update_bits(priv->regmap,
+ RG_EINT0HIRENB_ADDR,
+ RG_EINT0HIRENB_MASK_SFT,
+ BIT(RG_EINT0HIRENB_SFT));
+ }
+ }
+ return 0;
+}
+
+static unsigned int adjust_eint_digital_setting(struct mt6359_accdet *priv)
+{
+ if (priv->caps & ACCDET_PMIC_EINT0) {
+ /* disable inverter */
+ regmap_update_bits(priv->regmap,
+ ACCDET_EINT0_INVERTER_SW_EN_ADDR,
+ ACCDET_EINT0_INVERTER_SW_EN_MASK_SFT, 0);
+ } else if (priv->caps & ACCDET_PMIC_EINT1) {
+ /* disable inverter */
+ regmap_update_bits(priv->regmap,
+ ACCDET_EINT1_INVERTER_SW_EN_ADDR,
+ ACCDET_EINT1_INVERTER_SW_EN_MASK_SFT, 0);
+ }
+
+ if (priv->data->eint_detect_mode == 0x4) {
+ if (priv->caps & ACCDET_PMIC_EINT0) {
+ /* set DA stable signal */
+ regmap_update_bits(priv->regmap,
+ ACCDET_DA_STABLE_ADDR,
+ ACCDET_EINT0_CEN_STABLE_MASK_SFT, 0);
+ } else if (priv->caps & ACCDET_PMIC_EINT1) {
+ /* set DA stable signal */
+ regmap_update_bits(priv->regmap,
+ ACCDET_DA_STABLE_ADDR,
+ ACCDET_EINT1_CEN_STABLE_MASK_SFT, 0);
+ }
+ }
+ return 0;
+}
+
+static unsigned int mt6359_accdet_jd_setting(struct mt6359_accdet *priv)
+{
+ if (priv->jd_sts == M_PLUG_IN) {
+ /* adjust digital setting */
+ adjust_eint_digital_setting(priv);
+ /* adjust analog setting */
+ adjust_eint_analog_setting(priv);
+ } else if (priv->jd_sts == M_PLUG_OUT) {
+ /* set debounce to 1ms */
+ accdet_set_debounce(priv, eint_state000,
+ priv->data->pwm_deb->eint_debounce0);
+ } else {
+ dev_dbg(priv->dev, "should not be here %s()\n", __func__);
+ }
+
+ return 0;
+}
+
+static void recover_eint_analog_setting(struct mt6359_accdet *priv)
+{
+ if (priv->data->eint_detect_mode == 0x3 ||
+ priv->data->eint_detect_mode == 0x4) {
+ /* ESD switches on */
+ regmap_update_bits(priv->regmap, RG_ACCDETSPARE_ADDR,
+ 1 << 8, 1 << 8);
+ }
+ if (priv->data->eint_detect_mode == 0x4) {
+ if (priv->caps & ACCDET_PMIC_EINT0) {
+ /* disable RG_EINT0CONFIGACCDET */
+ regmap_update_bits(priv->regmap,
+ RG_EINT0CONFIGACCDET_ADDR,
+ RG_EINT0CONFIGACCDET_MASK_SFT, 0);
+ } else if (priv->caps & ACCDET_PMIC_EINT1) {
+ /* disable RG_EINT1CONFIGACCDET */
+ regmap_update_bits(priv->regmap,
+ RG_EINT1CONFIGACCDET_ADDR,
+ RG_EINT1CONFIGACCDET_MASK_SFT, 0);
+ }
+ regmap_update_bits(priv->regmap, RG_EINT0HIRENB_ADDR,
+ RG_EINT0HIRENB_MASK_SFT, 0);
+ }
+}
+
+static void recover_eint_digital_setting(struct mt6359_accdet *priv)
+{
+ if (priv->caps & ACCDET_PMIC_EINT0) {
+ regmap_update_bits(priv->regmap,
+ ACCDET_EINT0_M_SW_EN_ADDR,
+ ACCDET_EINT0_M_SW_EN_MASK_SFT, 0);
+ } else if (priv->caps & ACCDET_PMIC_EINT1) {
+ regmap_update_bits(priv->regmap,
+ ACCDET_EINT1_M_SW_EN_ADDR,
+ ACCDET_EINT1_M_SW_EN_MASK_SFT, 0);
+ }
+ if (priv->data->eint_detect_mode == 0x4) {
+ /* enable eint0cen */
+ if (priv->caps & ACCDET_PMIC_EINT0) {
+ /* enable eint0cen */
+ regmap_update_bits(priv->regmap,
+ ACCDET_DA_STABLE_ADDR,
+ ACCDET_EINT0_CEN_STABLE_MASK_SFT,
+ BIT(ACCDET_EINT0_CEN_STABLE_SFT));
+ } else if (priv->caps & ACCDET_PMIC_EINT1) {
+ /* enable eint1cen */
+ regmap_update_bits(priv->regmap,
+ ACCDET_DA_STABLE_ADDR,
+ ACCDET_EINT1_CEN_STABLE_MASK_SFT,
+ BIT(ACCDET_EINT1_CEN_STABLE_SFT));
+ }
+ }
+
+ if (priv->data->eint_detect_mode != 0x1) {
+ if (priv->caps & ACCDET_PMIC_EINT0) {
+ /* enable inverter */
+ regmap_update_bits(priv->regmap,
+ ACCDET_EINT0_INVERTER_SW_EN_ADDR,
+ ACCDET_EINT0_INVERTER_SW_EN_MASK_SFT,
+ BIT(ACCDET_EINT0_INVERTER_SW_EN_SFT));
+ } else if (priv->caps & ACCDET_PMIC_EINT1) {
+ /* enable inverter */
+ regmap_update_bits(priv->regmap,
+ ACCDET_EINT1_INVERTER_SW_EN_ADDR,
+ ACCDET_EINT1_INVERTER_SW_EN_MASK_SFT,
+ BIT(ACCDET_EINT1_INVERTER_SW_EN_SFT));
+ }
+ }
+}
+
+static void recover_eint_setting(struct mt6359_accdet *priv)
+{
+ if (priv->jd_sts == M_PLUG_OUT) {
+ recover_eint_analog_setting(priv);
+ recover_eint_digital_setting(priv);
+ }
+}
+
+static void mt6359_accdet_recover_jd_setting(struct mt6359_accdet *priv)
+{
+ int ret = 0;
+ unsigned int value = 0;
+
+ regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
+ ACCDET_IRQ_CLR_MASK_SFT, BIT(ACCDET_IRQ_CLR_SFT));
+ usleep_range(200, 300);
+ ret = regmap_read_poll_timeout(priv->regmap,
+ ACCDET_IRQ_ADDR,
+ value,
+ (value & ACCDET_IRQ_MASK_SFT) == 0,
+ 0,
+ 1000);
+ if (ret)
+ dev_warn(priv->dev, "%s(), ret %d\n", __func__, ret);
+ /* clear accdet int, modify for fix interrupt trigger twice error */
+ regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
+ ACCDET_IRQ_CLR_MASK_SFT, 0);
+ regmap_update_bits(priv->regmap, RG_INT_STATUS_ACCDET_ADDR,
+ RG_INT_STATUS_ACCDET_MASK_SFT,
+ BIT(RG_INT_STATUS_ACCDET_SFT));
+
+ /* recover accdet debounce0,3 */
+ accdet_set_debounce(priv, accdet_state000,
+ priv->data->pwm_deb->debounce0);
+ accdet_set_debounce(priv, accdet_state001,
+ priv->data->pwm_deb->debounce1);
+ accdet_set_debounce(priv, accdet_state011,
+ priv->data->pwm_deb->debounce3);
+
+ priv->jack_type = 0;
+ priv->btn_type = 0;
+ priv->accdet_status = 0x3;
+ mt6359_accdet_jack_report(priv);
+}
+
+static void accdet_set_debounce(struct mt6359_accdet *priv, int state,
+ unsigned int debounce)
+{
+ switch (state) {
+ case accdet_state000:
+ regmap_write(priv->regmap, ACCDET_DEBOUNCE0_ADDR, debounce);
+ break;
+ case accdet_state001:
+ regmap_write(priv->regmap, ACCDET_DEBOUNCE1_ADDR, debounce);
+ break;
+ case accdet_state010:
+ regmap_write(priv->regmap, ACCDET_DEBOUNCE2_ADDR, debounce);
+ break;
+ case accdet_state011:
+ regmap_write(priv->regmap, ACCDET_DEBOUNCE3_ADDR, debounce);
+ break;
+ case accdet_auxadc:
+ regmap_write(priv->regmap,
+ ACCDET_CONNECT_AUXADC_TIME_DIG_ADDR, debounce);
+ break;
+ case eint_state000:
+ regmap_update_bits(priv->regmap, ACCDET_EINT_DEBOUNCE0_ADDR,
+ 0xF << ACCDET_EINT_DEBOUNCE0_SFT,
+ debounce << ACCDET_EINT_DEBOUNCE0_SFT);
+ break;
+ case eint_state001:
+ regmap_update_bits(priv->regmap, ACCDET_EINT_DEBOUNCE1_ADDR,
+ 0xF << ACCDET_EINT_DEBOUNCE1_SFT,
+ debounce << ACCDET_EINT_DEBOUNCE1_SFT);
+ break;
+ case eint_state010:
+ regmap_update_bits(priv->regmap, ACCDET_EINT_DEBOUNCE2_ADDR,
+ 0xF << ACCDET_EINT_DEBOUNCE2_SFT,
+ debounce << ACCDET_EINT_DEBOUNCE2_SFT);
+ break;
+ case eint_state011:
+ regmap_update_bits(priv->regmap, ACCDET_EINT_DEBOUNCE3_ADDR,
+ 0xF << ACCDET_EINT_DEBOUNCE3_SFT,
+ debounce << ACCDET_EINT_DEBOUNCE3_SFT);
+ break;
+ case eint_inverter_state000:
+ regmap_write(priv->regmap, ACCDET_EINT_INVERTER_DEBOUNCE_ADDR,
+ debounce);
+ break;
+ default:
+ dev_warn(priv->dev, "Error: %s error state (%d)\n", __func__,
+ state);
+ break;
+ }
+}
+
+static void mt6359_accdet_jack_report(struct mt6359_accdet *priv)
+{
+ int report = 0;
+
+ if (!priv->jack)
+ return;
+
+ report = priv->jack_type | priv->btn_type;
+ snd_soc_jack_report(priv->jack, report, MT6359_ACCDET_JACK_MASK);
+}
+
+static unsigned int check_button(struct mt6359_accdet *priv, unsigned int v)
+{
+ if (priv->caps & ACCDET_FOUR_KEY) {
+ if (v < priv->data->four_key.down &&
+ v >= priv->data->four_key.up)
+ priv->btn_type = SND_JACK_BTN_1;
+ if (v < priv->data->four_key.up &&
+ v >= priv->data->four_key.voice)
+ priv->btn_type = SND_JACK_BTN_2;
+ if (v < priv->data->four_key.voice &&
+ v >= priv->data->four_key.mid)
+ priv->btn_type = SND_JACK_BTN_3;
+ if (v < priv->data->four_key.mid)
+ priv->btn_type = SND_JACK_BTN_0;
+ } else {
+ if (v < priv->data->three_key.down &&
+ v >= priv->data->three_key.up)
+ priv->btn_type = SND_JACK_BTN_1;
+ if (v < priv->data->three_key.up &&
+ v >= priv->data->three_key.mid)
+ priv->btn_type = SND_JACK_BTN_2;
+ if (v < priv->data->three_key.mid)
+ priv->btn_type = SND_JACK_BTN_0;
+ }
+ return 0;
+}
+
+static void is_key_pressed(struct mt6359_accdet *priv, bool pressed)
+{
+ priv->btn_type = priv->jack_type & ~MT6359_ACCDET_BTN_MASK;
+
+ if (pressed)
+ check_button(priv, priv->cali_voltage);
+}
+
+static inline void check_jack_btn_type(struct mt6359_accdet *priv)
+{
+ unsigned int val = 0;
+
+ regmap_read(priv->regmap, ACCDET_MEM_IN_ADDR, &val);
+
+ priv->accdet_status =
+ (val >> ACCDET_STATE_MEM_IN_OFFSET) & ACCDET_STATE_AB_MASK;
+
+ switch (priv->accdet_status) {
+ case 0:
+ if (priv->jack_type == SND_JACK_HEADSET)
+ is_key_pressed(priv, true);
+ else
+ priv->jack_type = SND_JACK_HEADPHONE;
+ break;
+ case 1:
+ if (priv->jack_type == SND_JACK_HEADSET) {
+ is_key_pressed(priv, false);
+ } else {
+ priv->jack_type = SND_JACK_HEADSET;
+ accdet_set_debounce(priv, eint_state011, 0x1);
+ }
+ break;
+ case 3:
+ default:
+ priv->jack_type = 0;
+ break;
+ }
+}
+
+static void mt6359_accdet_work(struct work_struct *work)
+{
+ struct mt6359_accdet *priv =
+ container_of(work, struct mt6359_accdet, accdet_work);
+
+ mutex_lock(&priv->res_lock);
+ priv->pre_accdet_status = priv->accdet_status;
+ check_jack_btn_type(priv);
+
+ if (priv->jack_plugged &&
+ priv->pre_accdet_status != priv->accdet_status)
+ mt6359_accdet_jack_report(priv);
+ mutex_unlock(&priv->res_lock);
+}
+
+static void mt6359_accdet_jd_work(struct work_struct *work)
+{
+ int ret = 0;
+ unsigned int value = 0;
+
+ struct mt6359_accdet *priv =
+ container_of(work, struct mt6359_accdet, jd_work);
+
+ mutex_lock(&priv->res_lock);
+ if (priv->jd_sts == M_PLUG_IN) {
+ priv->jack_plugged = true;
+
+ /* set and clear initial bit every eint interrupt */
+ regmap_update_bits(priv->regmap, ACCDET_SEQ_INIT_ADDR,
+ ACCDET_SEQ_INIT_MASK_SFT,
+ BIT(ACCDET_SEQ_INIT_SFT));
+ regmap_update_bits(priv->regmap, ACCDET_SEQ_INIT_ADDR,
+ ACCDET_SEQ_INIT_MASK_SFT, 0);
+ ret = regmap_read_poll_timeout(priv->regmap,
+ ACCDET_SEQ_INIT_ADDR,
+ value,
+ (value & ACCDET_SEQ_INIT_MASK_SFT) == 0,
+ 0,
+ 1000);
+ if (ret)
+ dev_err(priv->dev, "%s(), ret %d\n", __func__, ret);
+
+ /* enable ACCDET unit */
+ regmap_update_bits(priv->regmap, ACCDET_SW_EN_ADDR,
+ ACCDET_SW_EN_MASK_SFT, BIT(ACCDET_SW_EN_SFT));
+ } else if (priv->jd_sts == M_PLUG_OUT) {
+ priv->jack_plugged = false;
+
+ accdet_set_debounce(priv, accdet_state011,
+ priv->data->pwm_deb->debounce3);
+ regmap_update_bits(priv->regmap, ACCDET_SW_EN_ADDR,
+ ACCDET_SW_EN_MASK_SFT, 0);
+ mt6359_accdet_recover_jd_setting(priv);
+ }
+
+ if (priv->caps & ACCDET_PMIC_EINT_IRQ)
+ recover_eint_setting(priv);
+ mutex_unlock(&priv->res_lock);
+}
+
+static irqreturn_t mt6359_accdet_irq(int irq, void *data)
+{
+ struct mt6359_accdet *priv = data;
+ unsigned int irq_val = 0, val = 0, value = 0;
+ int ret = 0;
+
+ mutex_lock(&priv->res_lock);
+ regmap_read(priv->regmap, ACCDET_IRQ_ADDR, &irq_val);
+
+ if (irq_val & ACCDET_IRQ_MASK_SFT) {
+ regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
+ ACCDET_IRQ_CLR_MASK_SFT,
+ BIT(ACCDET_IRQ_CLR_SFT));
+ ret = regmap_read_poll_timeout(priv->regmap,
+ ACCDET_IRQ_ADDR,
+ value,
+ (value & ACCDET_IRQ_MASK_SFT) == 0,
+ 0,
+ 1000);
+ if (ret) {
+ dev_err(priv->dev, "%s(), ret %d\n", __func__, ret);
+ mutex_unlock(&priv->res_lock);
+ return IRQ_NONE;
+ }
+ regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
+ ACCDET_IRQ_CLR_MASK_SFT, 0);
+ regmap_update_bits(priv->regmap, RG_INT_STATUS_ACCDET_ADDR,
+ RG_INT_STATUS_ACCDET_MASK_SFT,
+ BIT(RG_INT_STATUS_ACCDET_SFT));
+
+ queue_work(priv->accdet_workqueue, &priv->accdet_work);
+ } else {
+ if (irq_val & ACCDET_EINT0_IRQ_MASK_SFT) {
+ regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
+ ACCDET_EINT0_IRQ_CLR_MASK_SFT,
+ BIT(ACCDET_EINT0_IRQ_CLR_SFT));
+ ret = regmap_read_poll_timeout(priv->regmap,
+ ACCDET_IRQ_ADDR,
+ value,
+ (value & ACCDET_EINT0_IRQ_MASK_SFT) == 0,
+ 0,
+ 1000);
+ if (ret) {
+ dev_err(priv->dev, "%s(), ret %d\n", __func__,
+ ret);
+ mutex_unlock(&priv->res_lock);
+ return IRQ_NONE;
+ }
+ regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
+ ACCDET_EINT0_IRQ_CLR_MASK_SFT, 0);
+ regmap_update_bits(priv->regmap,
+ RG_INT_STATUS_ACCDET_ADDR,
+ RG_INT_STATUS_ACCDET_EINT0_MASK_SFT,
+ BIT(RG_INT_STATUS_ACCDET_EINT0_SFT));
+ }
+ if (irq_val & ACCDET_EINT1_IRQ_MASK_SFT) {
+ regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
+ ACCDET_EINT1_IRQ_CLR_MASK_SFT,
+ BIT(ACCDET_EINT1_IRQ_CLR_SFT));
+ ret = regmap_read_poll_timeout(priv->regmap,
+ ACCDET_IRQ_ADDR,
+ value,
+ (value & ACCDET_EINT1_IRQ_MASK_SFT) == 0,
+ 0,
+ 1000);
+ if (ret) {
+ dev_err(priv->dev, "%s(), ret %d\n", __func__,
+ ret);
+ mutex_unlock(&priv->res_lock);
+ return IRQ_NONE;
+ }
+ regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
+ ACCDET_EINT1_IRQ_CLR_MASK_SFT, 0);
+ regmap_update_bits(priv->regmap,
+ RG_INT_STATUS_ACCDET_ADDR,
+ RG_INT_STATUS_ACCDET_EINT1_MASK_SFT,
+ BIT(RG_INT_STATUS_ACCDET_EINT1_SFT));
+ }
+ /* get jack detection status */
+ regmap_read(priv->regmap, ACCDET_EINT0_MEM_IN_ADDR, &val);
+ priv->jd_sts = ((val >> ACCDET_EINT0_MEM_IN_SFT) &
+ ACCDET_EINT0_MEM_IN_MASK);
+ /* adjust eint digital/analog setting */
+ mt6359_accdet_jd_setting(priv);
+
+ queue_work(priv->jd_workqueue, &priv->jd_work);
+ }
+ mutex_unlock(&priv->res_lock);
+
+ return IRQ_HANDLED;
+}
+
+static int mt6359_accdet_parse_dt(struct mt6359_accdet *priv)
+{
+ int ret = 0;
+ struct device *dev = priv->dev;
+ struct device_node *node = NULL;
+ int pwm_deb[15] = {0};
+ unsigned int tmp = 0;
+
+ node = of_get_child_by_name(dev->parent->of_node, "accdet");
+ if (!node)
+ return -EINVAL;
+
+ ret = of_property_read_u32(node, "mediatek,mic-vol",
+ &priv->data->mic_vol);
+ if (ret)
+ priv->data->mic_vol = 8;
+
+ ret = of_property_read_u32(node, "mediatek,plugout-debounce",
+ &priv->data->plugout_deb);
+ if (ret)
+ priv->data->plugout_deb = 1;
+
+ ret = of_property_read_u32(node, "mediatek,mic-mode",
+ &priv->data->mic_mode);
+ if (ret)
+ priv->data->mic_mode = 2;
+
+ ret = of_property_read_u32_array(node, "mediatek,pwm-deb-setting",
+ pwm_deb, ARRAY_SIZE(pwm_deb));
+ /* debounce8(auxadc debounce) is default, needn't get from dts */
+ if (!ret)
+ memcpy(priv->data->pwm_deb, pwm_deb, sizeof(pwm_deb));
+
+ ret = of_property_read_u32(node, "mediatek,eint-level-pol",
+ &priv->data->eint_pol);
+ if (ret)
+ priv->data->eint_pol = 8;
+
+ ret = of_property_read_u32(node, "mediatek,eint-use-ap", &tmp);
+ if (ret)
+ tmp = 0;
+ if (tmp == 0)
+ priv->caps |= ACCDET_PMIC_EINT_IRQ;
+ else if (tmp == 1)
+ priv->caps |= ACCDET_AP_GPIO_EINT;
+
+ ret = of_property_read_u32(node, "mediatek,eint-detect-mode",
+ &priv->data->eint_detect_mode);
+ if (ret) {
+ /* eint detection mode equals to EINT HW Mode */
+ priv->data->eint_detect_mode = 0x4;
+ }
+
+ ret = of_property_read_u32(node, "mediatek,eint-num", &tmp);
+ if (ret)
+ tmp = 0;
+ if (tmp == 0)
+ priv->caps |= ACCDET_PMIC_EINT0;
+ else if (tmp == 1)
+ priv->caps |= ACCDET_PMIC_EINT1;
+ else if (tmp == 2)
+ priv->caps |= ACCDET_PMIC_BI_EINT;
+
+ ret = of_property_read_u32(node, "mediatek,eint-trig-mode",
+ &tmp);
+ if (ret)
+ tmp = 0;
+ if (tmp == 0)
+ priv->caps |= ACCDET_PMIC_GPIO_TRIG_EINT;
+ else if (tmp == 1)
+ priv->caps |= ACCDET_PMIC_INVERTER_TRIG_EINT;
+
+ ret = of_property_read_u32(node, "mediatek,eint-use-ext-res",
+ &priv->data->eint_use_ext_res);
+ if (ret) {
+ /* eint use internal resister */
+ priv->data->eint_use_ext_res = 0x0;
+ }
+
+ ret = of_property_read_u32(node, "mediatek,eint-comp-vth",
+ &priv->data->eint_comp_vth);
+ if (ret)
+ priv->data->eint_comp_vth = 0x0;
+
+ ret = of_property_read_u32(node, "mediatek,key-mode", &tmp);
+ if (ret)
+ tmp = 0;
+ if (tmp == 0) {
+ int three_key[4];
+
+ priv->caps |= ACCDET_THREE_KEY;
+ ret = of_property_read_u32_array(node,
+ "mediatek,three-key-thr",
+ three_key,
+ ARRAY_SIZE(three_key));
+ if (!ret)
+ memcpy(&priv->data->three_key, three_key + 1,
+ sizeof(struct three_key_threshold));
+ } else if (tmp == 1) {
+ int four_key[5];
+
+ priv->caps |= ACCDET_FOUR_KEY;
+ ret = of_property_read_u32_array(node,
+ "mediatek,four-key-thr",
+ four_key,
+ ARRAY_SIZE(four_key));
+ if (!ret) {
+ memcpy(&priv->data->four_key, four_key + 1,
+ sizeof(struct four_key_threshold));
+ } else {
+ dev_warn(priv->dev,
+ "accdet no 4-key-thrsh dts, use efuse\n");
+ }
+ } else if (tmp == 2) {
+ int three_key[4];
+
+ priv->caps |= ACCDET_TRI_KEY_CDD;
+ ret = of_property_read_u32_array(node,
+ "mediatek,tri-key-cdd-thr",
+ three_key,
+ ARRAY_SIZE(three_key));
+ if (!ret)
+ memcpy(&priv->data->three_key, three_key + 1,
+ sizeof(struct three_key_threshold));
+ }
+
+ dev_warn(priv->dev, "accdet caps=%x\n", priv->caps);
+
+ return 0;
+}
+
+static void config_digital_init_by_mode(struct mt6359_accdet *priv)
+{
+ /* enable eint cmpmem pwm */
+ regmap_write(priv->regmap, ACCDET_EINT_CMPMEN_PWM_THRESH_ADDR,
+ (priv->data->pwm_deb->eint_pwm_width << 4 |
+ priv->data->pwm_deb->eint_pwm_thresh));
+ /* DA signal stable */
+ if (priv->caps & ACCDET_PMIC_EINT0) {
+ regmap_write(priv->regmap, ACCDET_DA_STABLE_ADDR,
+ ACCDET_EINT0_STABLE_VAL);
+ } else if (priv->caps & ACCDET_PMIC_EINT1) {
+ regmap_write(priv->regmap, ACCDET_DA_STABLE_ADDR,
+ ACCDET_EINT1_STABLE_VAL);
+ }
+ /* after receive n+1 number, interrupt issued. */
+ regmap_update_bits(priv->regmap, ACCDET_EINT_M_PLUG_IN_NUM_ADDR,
+ ACCDET_EINT_M_PLUG_IN_NUM_MASK_SFT,
+ BIT(ACCDET_EINT_M_PLUG_IN_NUM_SFT));
+ /* setting HW mode, enable digital fast discharge
+ * if use EINT0 & EINT1 detection, please modify
+ * ACCDET_HWMODE_EN_ADDR[2:1]
+ */
+ regmap_write(priv->regmap, ACCDET_HWMODE_EN_ADDR, 0x100);
+
+ regmap_update_bits(priv->regmap, ACCDET_EINT_M_DETECT_EN_ADDR,
+ ACCDET_EINT_M_DETECT_EN_MASK_SFT, 0);
+
+ /* enable PWM */
+ regmap_write(priv->regmap, ACCDET_CMP_PWM_EN_ADDR, 0x67);
+ /* enable inverter detection */
+ if (priv->data->eint_detect_mode == 0x1) {
+ /* disable inverter detection */
+ if (priv->caps & ACCDET_PMIC_EINT0) {
+ regmap_update_bits(priv->regmap,
+ ACCDET_EINT0_INVERTER_SW_EN_ADDR,
+ ACCDET_EINT0_INVERTER_SW_EN_MASK_SFT,
+ 0);
+ } else if (priv->caps & ACCDET_PMIC_EINT1) {
+ regmap_update_bits(priv->regmap,
+ ACCDET_EINT1_INVERTER_SW_EN_ADDR,
+ ACCDET_EINT1_INVERTER_SW_EN_MASK_SFT,
+ 0);
+ }
+ } else {
+ if (priv->caps & ACCDET_PMIC_EINT0) {
+ regmap_update_bits(priv->regmap,
+ ACCDET_EINT0_INVERTER_SW_EN_ADDR,
+ ACCDET_EINT0_INVERTER_SW_EN_MASK_SFT,
+ BIT(ACCDET_EINT0_INVERTER_SW_EN_SFT));
+ } else if (priv->caps & ACCDET_PMIC_EINT1) {
+ regmap_update_bits(priv->regmap,
+ ACCDET_EINT1_INVERTER_SW_EN_ADDR,
+ ACCDET_EINT1_INVERTER_SW_EN_MASK_SFT,
+ BIT(ACCDET_EINT1_INVERTER_SW_EN_SFT));
+ }
+ }
+}
+
+static void config_eint_init_by_mode(struct mt6359_accdet *priv)
+{
+ unsigned int val = 0;
+
+ if (priv->caps & ACCDET_PMIC_EINT0) {
+ regmap_update_bits(priv->regmap, RG_EINT0EN_ADDR,
+ RG_EINT0EN_MASK_SFT, BIT(RG_EINT0EN_SFT));
+ } else if (priv->caps & ACCDET_PMIC_EINT1) {
+ regmap_update_bits(priv->regmap, RG_EINT1EN_ADDR,
+ RG_EINT1EN_MASK_SFT, BIT(RG_EINT1EN_SFT));
+ }
+ /* ESD switches on */
+ regmap_update_bits(priv->regmap, RG_ACCDETSPARE_ADDR,
+ 1 << 8, 1 << 8);
+ /* before playback, set NCP pull low before nagative voltage */
+ regmap_update_bits(priv->regmap, RG_NCP_PDDIS_EN_ADDR,
+ RG_NCP_PDDIS_EN_MASK_SFT, BIT(RG_NCP_PDDIS_EN_SFT));
+
+ if (priv->data->eint_detect_mode == 0x1 ||
+ priv->data->eint_detect_mode == 0x2 ||
+ priv->data->eint_detect_mode == 0x3) {
+ if (priv->data->eint_use_ext_res == 0x1) {
+ if (priv->caps & ACCDET_PMIC_EINT0) {
+ regmap_update_bits(priv->regmap,
+ RG_EINT0CONFIGACCDET_ADDR,
+ RG_EINT0CONFIGACCDET_MASK_SFT,
+ 0);
+ } else if (priv->caps & ACCDET_PMIC_EINT1) {
+ regmap_update_bits(priv->regmap,
+ RG_EINT1CONFIGACCDET_ADDR,
+ RG_EINT1CONFIGACCDET_MASK_SFT,
+ 0);
+ }
+ } else {
+ if (priv->caps & ACCDET_PMIC_EINT0) {
+ regmap_update_bits(priv->regmap,
+ RG_EINT0CONFIGACCDET_ADDR,
+ RG_EINT0CONFIGACCDET_MASK_SFT,
+ BIT(RG_EINT0CONFIGACCDET_SFT));
+ } else if (priv->caps & ACCDET_PMIC_EINT1) {
+ regmap_update_bits(priv->regmap,
+ RG_EINT1CONFIGACCDET_ADDR,
+ RG_EINT1CONFIGACCDET_MASK_SFT,
+ BIT(RG_EINT1CONFIGACCDET_SFT));
+ }
+ }
+ }
+
+ if (priv->data->eint_detect_mode != 0x1) {
+ /* current detect set 0.25uA */
+ regmap_update_bits(priv->regmap, RG_ACCDETSPARE_ADDR,
+ 0x3 << RG_ACCDETSPARE_SFT,
+ 0x3 << RG_ACCDETSPARE_SFT);
+ }
+ regmap_write(priv->regmap, RG_EINTCOMPVTH_ADDR,
+ val | priv->data->eint_comp_vth << RG_EINTCOMPVTH_SFT);
+}
+
+static void mt6359_accdet_init(struct mt6359_accdet *priv)
+{
+ unsigned int reg = 0;
+
+ regmap_update_bits(priv->regmap, ACCDET_SEQ_INIT_ADDR,
+ ACCDET_SEQ_INIT_MASK_SFT, BIT(ACCDET_SEQ_INIT_SFT));
+ mdelay(2);
+ regmap_update_bits(priv->regmap, ACCDET_SEQ_INIT_ADDR,
+ ACCDET_SEQ_INIT_MASK_SFT, 0);
+ mdelay(1);
+ /* init the debounce time (debounce/32768)sec */
+ accdet_set_debounce(priv, accdet_state000,
+ priv->data->pwm_deb->debounce0);
+ accdet_set_debounce(priv, accdet_state001,
+ priv->data->pwm_deb->debounce1);
+ accdet_set_debounce(priv, accdet_state011,
+ priv->data->pwm_deb->debounce3);
+ accdet_set_debounce(priv, accdet_auxadc,
+ priv->data->pwm_deb->debounce4);
+
+ accdet_set_debounce(priv, eint_state000,
+ priv->data->pwm_deb->eint_debounce0);
+ accdet_set_debounce(priv, eint_state001,
+ priv->data->pwm_deb->eint_debounce1);
+ accdet_set_debounce(priv, eint_state011,
+ priv->data->pwm_deb->eint_debounce3);
+ accdet_set_debounce(priv, eint_inverter_state000,
+ priv->data->pwm_deb->eint_inverter_debounce);
+
+ regmap_update_bits(priv->regmap, RG_ACCDET_RST_ADDR,
+ RG_ACCDET_RST_MASK_SFT, BIT(RG_ACCDET_RST_SFT));
+ regmap_update_bits(priv->regmap, RG_ACCDET_RST_ADDR,
+ RG_ACCDET_RST_MASK_SFT, 0);
+
+ /* clear high micbias1 voltage setting */
+ regmap_update_bits(priv->regmap, RG_AUDPWDBMICBIAS1_ADDR,
+ 0x3 << RG_AUDMICBIAS1HVEN_SFT, 0);
+ regmap_update_bits(priv->regmap, RG_AUDPWDBMICBIAS1_ADDR,
+ 0x7 << RG_AUDMICBIAS1VREF_SFT, 0);
+
+ /* init pwm frequency, duty & rise/falling delay */
+ regmap_write(priv->regmap, ACCDET_PWM_WIDTH_ADDR,
+ REGISTER_VAL(priv->data->pwm_deb->pwm_width));
+ regmap_write(priv->regmap, ACCDET_PWM_THRESH_ADDR,
+ REGISTER_VAL(priv->data->pwm_deb->pwm_thresh));
+ regmap_write(priv->regmap, ACCDET_RISE_DELAY_ADDR,
+ (priv->data->pwm_deb->fall_delay << 15 |
+ priv->data->pwm_deb->rise_delay));
+
+ regmap_read(priv->regmap, RG_AUDPWDBMICBIAS1_ADDR, &reg);
+ if (priv->data->mic_vol <= 7) {
+ /* micbias1 <= 2.7V */
+ regmap_write(priv->regmap, RG_AUDPWDBMICBIAS1_ADDR,
+ reg | (priv->data->mic_vol << RG_AUDMICBIAS1VREF_SFT) |
+ RG_AUDMICBIAS1LOWPEN_MASK_SFT);
+ } else if (priv->data->mic_vol == 8) {
+ /* micbias1 = 2.8v */
+ regmap_write(priv->regmap, RG_AUDPWDBMICBIAS1_ADDR,
+ reg | (3 << RG_AUDMICBIAS1HVEN_SFT) |
+ RG_AUDMICBIAS1LOWPEN_MASK_SFT);
+ } else if (priv->data->mic_vol == 9) {
+ /* micbias1 = 2.85v */
+ regmap_write(priv->regmap, RG_AUDPWDBMICBIAS1_ADDR,
+ reg | (1 << RG_AUDMICBIAS1HVEN_SFT) |
+ RG_AUDMICBIAS1LOWPEN_MASK_SFT);
+ }
+ /* mic mode setting */
+ regmap_read(priv->regmap, RG_AUDACCDETMICBIAS0PULLLOW_ADDR, &reg);
+ if (priv->data->mic_mode == HEADSET_MODE_1) {
+ /* ACC mode*/
+ regmap_write(priv->regmap, RG_AUDACCDETMICBIAS0PULLLOW_ADDR,
+ reg | RG_ACCDET_MODE_ANA11_MODE1);
+ /* enable analog fast discharge */
+ regmap_update_bits(priv->regmap, RG_ANALOGFDEN_ADDR,
+ RG_ANALOGFDEN_MASK_SFT,
+ BIT(RG_ANALOGFDEN_SFT));
+ regmap_update_bits(priv->regmap, RG_ACCDETSPARE_ADDR,
+ 0x3 << 11, 0x3 << 11);
+ } else if (priv->data->mic_mode == HEADSET_MODE_2) {
+ /* DCC mode Low cost mode without internal bias */
+ regmap_write(priv->regmap, RG_AUDACCDETMICBIAS0PULLLOW_ADDR,
+ reg | RG_ACCDET_MODE_ANA11_MODE2);
+ /* enable analog fast discharge */
+ regmap_update_bits(priv->regmap, RG_ANALOGFDEN_ADDR,
+ 0x3 << RG_ANALOGFDEN_SFT,
+ 0x3 << RG_ANALOGFDEN_SFT);
+ } else if (priv->data->mic_mode == HEADSET_MODE_6) {
+ /* DCC mode Low cost mode with internal bias,
+ * bit8 = 1 to use internal bias
+ */
+ regmap_write(priv->regmap, RG_AUDACCDETMICBIAS0PULLLOW_ADDR,
+ reg | RG_ACCDET_MODE_ANA11_MODE6);
+ regmap_update_bits(priv->regmap, RG_AUDPWDBMICBIAS1_ADDR,
+ RG_AUDMICBIAS1DCSW1PEN_MASK_SFT,
+ BIT(RG_AUDMICBIAS1DCSW1PEN_SFT));
+ /* enable analog fast discharge */
+ regmap_update_bits(priv->regmap, RG_ANALOGFDEN_ADDR,
+ 0x3 << RG_ANALOGFDEN_SFT,
+ 0x3 << RG_ANALOGFDEN_SFT);
+ }
+
+ if (priv->caps & ACCDET_PMIC_EINT_IRQ) {
+ config_eint_init_by_mode(priv);
+ config_digital_init_by_mode(priv);
+ }
+}
+
+int mt6359_accdet_enable_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *jack)
+{
+ struct mt6359_accdet *priv =
+ snd_soc_component_get_drvdata(component);
+
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEDOWN);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+
+ priv->jack = jack;
+
+ mt6359_accdet_jack_report(priv);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt6359_accdet_enable_jack_detect);
+
+static int mt6359_accdet_probe(struct platform_device *pdev)
+{
+ struct mt6359_accdet *priv;
+ struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
+ int ret = 0;
+
+ dev_dbg(&pdev->dev, "%s(), dev name %s\n",
+ __func__, dev_name(&pdev->dev));
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct mt6359_accdet),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->data = devm_kzalloc(&pdev->dev, sizeof(struct dts_data),
+ GFP_KERNEL);
+ if (!priv->data)
+ return -ENOMEM;
+
+ priv->data->pwm_deb = devm_kzalloc(&pdev->dev,
+ sizeof(struct pwm_deb_settings),
+ GFP_KERNEL);
+ if (!priv->data->pwm_deb)
+ return -ENOMEM;
+
+ priv->regmap = mt6397->regmap;
+ if (IS_ERR(priv->regmap)) {
+ ret = PTR_ERR(priv->regmap);
+ dev_err(&pdev->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+ priv->dev = &pdev->dev;
+
+ ret = mt6359_accdet_parse_dt(priv);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to parse dts\n");
+ return ret;
+ }
+ mutex_init(&priv->res_lock);
+
+ priv->accdet_irq = platform_get_irq(pdev, 0);
+ if (priv->accdet_irq) {
+ ret = devm_request_threaded_irq(&pdev->dev, priv->accdet_irq,
+ NULL, mt6359_accdet_irq,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ "ACCDET_IRQ", priv);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to request IRQ: (%d)\n", ret);
+ return ret;
+ }
+ }
+
+ if (priv->caps & ACCDET_PMIC_EINT0) {
+ priv->accdet_eint0 = platform_get_irq(pdev, 1);
+ if (priv->accdet_eint0) {
+ ret = devm_request_threaded_irq(&pdev->dev,
+ priv->accdet_eint0,
+ NULL, mt6359_accdet_irq,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ "ACCDET_EINT0", priv);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to request eint0 IRQ (%d)\n",
+ ret);
+ return ret;
+ }
+ }
+ } else if (priv->caps & ACCDET_PMIC_EINT1) {
+ priv->accdet_eint1 = platform_get_irq(pdev, 2);
+ if (priv->accdet_eint1) {
+ ret = devm_request_threaded_irq(&pdev->dev,
+ priv->accdet_eint1,
+ NULL, mt6359_accdet_irq,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ "ACCDET_EINT1", priv);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to request eint1 IRQ (%d)\n",
+ ret);
+ return ret;
+ }
+ }
+ }
+
+ priv->accdet_workqueue = create_singlethread_workqueue("accdet");
+ INIT_WORK(&priv->accdet_work, mt6359_accdet_work);
+ if (!priv->accdet_workqueue) {
+ dev_err(&pdev->dev, "Failed to create accdet workqueue\n");
+ ret = -1;
+ goto err_accdet_wq;
+ }
+
+ priv->jd_workqueue = create_singlethread_workqueue("mt6359_accdet_jd");
+ INIT_WORK(&priv->jd_work, mt6359_accdet_jd_work);
+ if (!priv->jd_workqueue) {
+ dev_err(&pdev->dev, "Failed to create jack detect workqueue\n");
+ ret = -1;
+ goto err_eint_wq;
+ }
+
+ platform_set_drvdata(pdev, priv);
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &mt6359_accdet_soc_driver,
+ NULL, 0);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register component\n");
+ return ret;
+ }
+
+ priv->jd_sts = M_PLUG_OUT;
+ priv->jack_type = 0;
+ priv->btn_type = 0;
+ priv->accdet_status = 0x3;
+ mt6359_accdet_init(priv);
+
+ mt6359_accdet_jack_report(priv);
+
+ return 0;
+
+err_eint_wq:
+ destroy_workqueue(priv->accdet_workqueue);
+err_accdet_wq:
+ dev_err(&pdev->dev, "%s error. now exit.!\n", __func__);
+ return ret;
+}
+
+static struct platform_driver mt6359_accdet_driver = {
+ .driver = {
+ .name = "pmic-codec-accdet",
+ },
+ .probe = mt6359_accdet_probe,
+};
+
+static int __init mt6359_accdet_driver_init(void)
+{
+ int ret = 0;
+
+ ret = platform_driver_register(&mt6359_accdet_driver);
+ if (ret)
+ return -ENODEV;
+ return 0;
+}
+
+static void __exit mt6359_accdet_driver_exit(void)
+{
+ platform_driver_unregister(&mt6359_accdet_driver);
+}
+module_init(mt6359_accdet_driver_init);
+module_exit(mt6359_accdet_driver_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MT6359 ALSA SoC codec jack driver");
+MODULE_AUTHOR("Argus Lin <argus.lin@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/mt6359-accdet.h b/sound/soc/codecs/mt6359-accdet.h
new file mode 100644
index 000000000000..c234f2f4276a
--- /dev/null
+++ b/sound/soc/codecs/mt6359-accdet.h
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 MediaTek Inc.
+ * Author: Argus Lin <argus.lin@mediatek.com>
+ */
+
+#ifndef _ACCDET_H_
+#define _ACCDET_H_
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+
+#define ACCDET_DEVNAME "accdet"
+
+#define HEADSET_MODE_1 (1)
+#define HEADSET_MODE_2 (2)
+#define HEADSET_MODE_6 (6)
+
+#define MT6359_ACCDET_NUM_BUTTONS 4
+#define MT6359_ACCDET_JACK_MASK (SND_JACK_HEADPHONE | \
+ SND_JACK_HEADSET | \
+ SND_JACK_BTN_0 | \
+ SND_JACK_BTN_1 | \
+ SND_JACK_BTN_2 | \
+ SND_JACK_BTN_3)
+#define MT6359_ACCDET_BTN_MASK (SND_JACK_BTN_0 | \
+ SND_JACK_BTN_1 | \
+ SND_JACK_BTN_2 | \
+ SND_JACK_BTN_3)
+
+enum eint_moisture_status {
+ M_PLUG_IN = 0,
+ M_WATER_IN = 1,
+ M_HP_PLUG_IN = 2,
+ M_PLUG_OUT = 3,
+ M_NO_ACT = 4,
+ M_UNKNOWN = 5,
+};
+
+enum {
+ accdet_state000 = 0,
+ accdet_state001,
+ accdet_state010,
+ accdet_state011,
+ accdet_auxadc,
+ eint_state000,
+ eint_state001,
+ eint_state010,
+ eint_state011,
+ eint_inverter_state000,
+};
+
+struct three_key_threshold {
+ unsigned int mid;
+ unsigned int up;
+ unsigned int down;
+};
+
+struct four_key_threshold {
+ unsigned int mid;
+ unsigned int voice;
+ unsigned int up;
+ unsigned int down;
+};
+
+struct pwm_deb_settings {
+ unsigned int pwm_width;
+ unsigned int pwm_thresh;
+ unsigned int fall_delay;
+ unsigned int rise_delay;
+ unsigned int debounce0;
+ unsigned int debounce1;
+ unsigned int debounce3;
+ unsigned int debounce4;
+ unsigned int eint_pwm_width;
+ unsigned int eint_pwm_thresh;
+ unsigned int eint_debounce0;
+ unsigned int eint_debounce1;
+ unsigned int eint_debounce2;
+ unsigned int eint_debounce3;
+ unsigned int eint_inverter_debounce;
+
+};
+
+struct dts_data {
+ unsigned int mic_vol;
+ unsigned int mic_mode;
+ unsigned int plugout_deb;
+ unsigned int eint_pol;
+ struct pwm_deb_settings *pwm_deb;
+ struct three_key_threshold three_key;
+ struct four_key_threshold four_key;
+ unsigned int moisture_detect_enable;
+ unsigned int eint_detect_mode;
+ unsigned int eint_use_ext_res;
+ unsigned int eint_comp_vth;
+ unsigned int moisture_detect_mode;
+ unsigned int moisture_comp_vth;
+ unsigned int moisture_comp_vref2;
+ unsigned int moisture_use_ext_res;
+};
+
+struct mt6359_accdet {
+ struct snd_soc_jack *jack;
+ struct device *dev;
+ struct regmap *regmap;
+ struct dts_data *data;
+ unsigned int caps;
+ int accdet_irq;
+ int accdet_eint0;
+ int accdet_eint1;
+ struct mutex res_lock; /* lock protection */
+ bool jack_plugged;
+ unsigned int jack_type;
+ unsigned int btn_type;
+ unsigned int accdet_status;
+ unsigned int pre_accdet_status;
+ unsigned int cali_voltage;
+ unsigned int jd_sts;
+ struct work_struct accdet_work;
+ struct workqueue_struct *accdet_workqueue;
+ struct work_struct jd_work;
+ struct workqueue_struct *jd_workqueue;
+};
+
+int mt6359_accdet_enable_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *jack);
+#endif
diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c
index 6f4b1da52082..b909b36582b7 100644
--- a/sound/soc/codecs/mt6359.c
+++ b/sound/soc/codecs/mt6359.c
@@ -239,7 +239,7 @@ static void zcd_disable(struct mt6359_priv *priv)
static void hp_main_output_ramp(struct mt6359_priv *priv, bool up)
{
- int i = 0, stage = 0;
+ int i, stage;
int target = 7;
/* Enable/Reduce HPL/R main output stage step by step */
@@ -257,7 +257,7 @@ static void hp_main_output_ramp(struct mt6359_priv *priv, bool up)
static void hp_aux_feedback_loop_gain_ramp(struct mt6359_priv *priv, bool up)
{
- int i = 0, stage = 0;
+ int i, stage;
int target = 0xf;
/* Enable/Reduce HP aux feedback loop gain step by step */
diff --git a/sound/soc/codecs/mt6359.h b/sound/soc/codecs/mt6359.h
index 35f806b7396d..296ffa7f50b5 100644
--- a/sound/soc/codecs/mt6359.h
+++ b/sound/soc/codecs/mt6359.h
@@ -8,129 +8,1779 @@
#define _MT6359_H_
/*************Register Bit Define*************/
-#define PMIC_ACCDET_IRQ_SHIFT 0
-#define PMIC_ACCDET_EINT0_IRQ_SHIFT 2
-#define PMIC_ACCDET_EINT1_IRQ_SHIFT 3
-#define PMIC_ACCDET_IRQ_CLR_SHIFT 8
-#define PMIC_ACCDET_EINT0_IRQ_CLR_SHIFT 10
-#define PMIC_ACCDET_EINT1_IRQ_CLR_SHIFT 11
-#define PMIC_RG_INT_STATUS_ACCDET_SHIFT 5
-#define PMIC_RG_INT_STATUS_ACCDET_EINT0_SHIFT 6
-#define PMIC_RG_INT_STATUS_ACCDET_EINT1_SHIFT 7
-#define PMIC_RG_EINT0CONFIGACCDET_SHIFT 11
-#define PMIC_RG_EINT1CONFIGACCDET_SHIFT 0
-#define PMIC_ACCDET_EINT0_INVERTER_SW_EN_SHIFT 6
-#define PMIC_ACCDET_EINT1_INVERTER_SW_EN_SHIFT 8
-#define PMIC_RG_MTEST_EN_SHIFT 8
-#define PMIC_RG_MTEST_SEL_SHIFT 9
-#define PMIC_ACCDET_EINT0_M_SW_EN_SHIFT 10
-#define PMIC_ACCDET_EINT1_M_SW_EN_SHIFT 11
-#define PMIC_ACCDET_EINT0_CEN_STABLE_SHIFT 5
-#define PMIC_ACCDET_EINT1_CEN_STABLE_SHIFT 10
-#define PMIC_ACCDET_DA_STABLE_SHIFT 0
-#define PMIC_ACCDET_EINT0_EN_STABLE_SHIFT 1
-#define PMIC_ACCDET_EINT0_CMPEN_STABLE_SHIFT 2
-#define PMIC_ACCDET_EINT1_EN_STABLE_SHIFT 6
-#define PMIC_ACCDET_EINT1_CMPEN_STABLE_SHIFT 7
-#define PMIC_ACCDET_EINT_CTURBO_SEL_SHIFT 7
-#define PMIC_ACCDET_EINT0_CTURBO_SW_SHIFT 7
-#define PMIC_RG_EINTCOMPVTH_SHIFT 4
-#define PMIC_RG_EINT0HIRENB_SHIFT 12
-#define PMIC_RG_EINT0NOHYS_SHIFT 10
-#define PMIC_ACCDET_SW_EN_SHIFT 0
-#define PMIC_ACCDET_EINT0_MEM_IN_SHIFT 6
-#define PMIC_ACCDET_MEM_IN_SHIFT 6
-#define PMIC_ACCDET_EINT_DEBOUNCE0_SHIFT 0
-#define PMIC_ACCDET_EINT_DEBOUNCE1_SHIFT 4
-#define PMIC_ACCDET_EINT_DEBOUNCE2_SHIFT 8
-#define PMIC_ACCDET_EINT_DEBOUNCE3_SHIFT 12
-#define PMIC_RG_ACCDET2AUXSWEN_SHIFT 14
-#define PMIC_AUDACCDETAUXADCSWCTRL_SEL_SHIFT 9
-#define PMIC_AUDACCDETAUXADCSWCTRL_SW_SHIFT 10
-#define PMIC_RG_EINT0CTURBO_SHIFT 5
-#define PMIC_RG_EINT1CTURBO_SHIFT 13
-#define PMIC_ACCDET_EINT_M_PLUG_IN_NUM_SHIFT 12
-#define PMIC_ACCDET_EINT_M_DETECT_EN_SHIFT 12
-#define PMIC_ACCDET_EINT0_SW_EN_SHIFT 2
-#define PMIC_ACCDET_EINT1_SW_EN_SHIFT 4
-#define PMIC_ACCDET_EINT_CMPMOUT_SEL_SHIFT 12
-#define PMIC_ACCDET_EINT_CMPMEN_SEL_SHIFT 6
-#define PMIC_RG_HPLOUTPUTSTBENH_VAUDP32_SHIFT 0
-#define PMIC_RG_HPROUTPUTSTBENH_VAUDP32_SHIFT 4
-#define PMIC_RG_EINT0EN_SHIFT 2
-#define PMIC_RG_EINT1EN_SHIFT 10
-#define PMIC_RG_NCP_PDDIS_EN_SHIFT 0
-#define PMIC_RG_ACCDETSPARE_SHIFT 0
-#define PMIC_RG_ACCDET_RST_SHIFT 1
-#define PMIC_RG_AUDMICBIAS1HVEN_SHIFT 12
-#define PMIC_RG_AUDMICBIAS1VREF_SHIFT 4
-#define PMIC_RG_ANALOGFDEN_SHIFT 12
-#define PMIC_RG_AUDMICBIAS1DCSW1PEN_SHIFT 8
-#define PMIC_RG_AUDMICBIAS1LOWPEN_SHIFT 2
-#define PMIC_ACCDET_SEQ_INIT_SHIFT 1
-#define PMIC_RG_EINTCOMPVTH_MASK 0xf
-#define PMIC_ACCDET_EINT0_MEM_IN_MASK 0x3
-#define PMIC_ACCDET_EINT_DEBOUNCE0_MASK 0xf
-#define PMIC_ACCDET_EINT_DEBOUNCE1_MASK 0xf
-#define PMIC_ACCDET_EINT_DEBOUNCE2_MASK 0xf
-#define PMIC_ACCDET_EINT_DEBOUNCE3_MASK 0xf
-#define PMIC_ACCDET_EINT0_IRQ_SHIFT 2
-#define PMIC_ACCDET_EINT1_IRQ_SHIFT 3
-
-/* AUDENC_ANA_CON16: */
-#define RG_AUD_MICBIAS1_LOWP_EN BIT(PMIC_RG_AUDMICBIAS1LOWPEN_SHIFT)
-
+#define MT6359_TOP0_ID 0x0
+#define MT6359_SMT_CON1 0x32
+#define MT6359_DRV_CON2 0x3c
+#define MT6359_DRV_CON3 0x3e
+#define MT6359_DRV_CON4 0x40
+#define MT6359_TOP_CKPDN_CON0 0x10c
+#define MT6359_TOP_CKPDN_CON0_SET 0x10e
+#define MT6359_TOP_CKPDN_CON0_CLR 0x110
+#define MT6359_AUXADC_RQST0 0x1108
+#define MT6359_AUXADC_CON10 0x11a0
+#define MT6359_AUXADC_ACCDET 0x11ba
+#define MT6359_LDO_VUSB_OP_EN 0x1d0c
+#define MT6359_LDO_VUSB_OP_EN_SET 0x1d0e
+#define MT6359_LDO_VUSB_OP_EN_CLR 0x1d10
+#define MT6359_AUD_TOP_CKPDN_CON0 0x230c
+#define MT6359_AUD_TOP_CKPDN_CON0_SET 0x230e
+#define MT6359_AUD_TOP_CKPDN_CON0_CLR 0x2310
+#define MT6359_AUD_TOP_RST_CON0 0x2320
+#define MT6359_AUD_TOP_RST_CON0_SET 0x2322
+#define MT6359_AUD_TOP_RST_CON0_CLR 0x2324
+#define MT6359_AUD_TOP_INT_CON0 0x2328
+#define MT6359_AUD_TOP_INT_CON0_SET 0x232a
+#define MT6359_AUD_TOP_INT_CON0_CLR 0x232c
+#define MT6359_AUD_TOP_INT_MASK_CON0 0x232e
+#define MT6359_AUD_TOP_INT_MASK_CON0_SET 0x2330
+#define MT6359_AUD_TOP_INT_MASK_CON0_CLR 0x2332
+#define MT6359_AUD_TOP_INT_STATUS0 0x2334
+#define MT6359_AFE_NCP_CFG2 0x24e2
+#define MT6359_AUDENC_DSN_ID 0x2500
+#define MT6359_AUDENC_DSN_REV0 0x2502
+#define MT6359_AUDENC_DSN_DBI 0x2504
+#define MT6359_AUDENC_DSN_FPI 0x2506
+#define MT6359_AUDENC_ANA_CON0 0x2508
+#define MT6359_AUDENC_ANA_CON1 0x250a
+#define MT6359_AUDENC_ANA_CON2 0x250c
+#define MT6359_AUDENC_ANA_CON3 0x250e
+#define MT6359_AUDENC_ANA_CON4 0x2510
+#define MT6359_AUDENC_ANA_CON5 0x2512
+#define MT6359_AUDENC_ANA_CON6 0x2514
+#define MT6359_AUDENC_ANA_CON7 0x2516
+#define MT6359_AUDENC_ANA_CON8 0x2518
+#define MT6359_AUDENC_ANA_CON9 0x251a
+#define MT6359_AUDENC_ANA_CON10 0x251c
+#define MT6359_AUDENC_ANA_CON11 0x251e
+#define MT6359_AUDENC_ANA_CON12 0x2520
+#define MT6359_AUDENC_ANA_CON13 0x2522
+#define MT6359_AUDENC_ANA_CON14 0x2524
+#define MT6359_AUDENC_ANA_CON15 0x2526
+#define MT6359_AUDENC_ANA_CON16 0x2528
+#define MT6359_AUDENC_ANA_CON17 0x252a
+#define MT6359_AUDENC_ANA_CON18 0x252c
+#define MT6359_AUDENC_ANA_CON19 0x252e
+#define MT6359_AUDENC_ANA_CON20 0x2530
+#define MT6359_AUDENC_ANA_CON21 0x2532
+#define MT6359_AUDENC_ANA_CON22 0x2534
+#define MT6359_AUDENC_ANA_CON23 0x2536
+#define MT6359_AUDDEC_DSN_ID 0x2580
+#define MT6359_AUDDEC_DSN_REV0 0x2582
+#define MT6359_AUDDEC_DSN_DBI 0x2584
+#define MT6359_AUDDEC_DSN_FPI 0x2586
+#define MT6359_AUDDEC_ANA_CON0 0x2588
+#define MT6359_AUDDEC_ANA_CON1 0x258a
+#define MT6359_AUDDEC_ANA_CON2 0x258c
+#define MT6359_AUDDEC_ANA_CON3 0x258e
+#define MT6359_AUDDEC_ANA_CON4 0x2590
+#define MT6359_AUDDEC_ANA_CON5 0x2592
+#define MT6359_AUDDEC_ANA_CON6 0x2594
+#define MT6359_AUDDEC_ANA_CON7 0x2596
+#define MT6359_AUDDEC_ANA_CON8 0x2598
+#define MT6359_AUDDEC_ANA_CON9 0x259a
+#define MT6359_AUDDEC_ANA_CON10 0x259c
+#define MT6359_AUDDEC_ANA_CON11 0x259e
+#define MT6359_AUDDEC_ANA_CON12 0x25a0
+#define MT6359_AUDDEC_ANA_CON13 0x25a2
+#define MT6359_AUDDEC_ANA_CON14 0x25a4
+#define MT6359_ACCDET_DSN_DIG_ID 0x2680
+#define MT6359_ACCDET_DSN_DIG_REV0 0x2682
+#define MT6359_ACCDET_DSN_DBI 0x2684
+#define MT6359_ACCDET_DSN_FPI 0x2686
+#define MT6359_ACCDET_CON0 0x2688
+#define MT6359_ACCDET_CON1 0x268a
+#define MT6359_ACCDET_CON2 0x268c
+#define MT6359_ACCDET_CON3 0x268e
+#define MT6359_ACCDET_CON4 0x2690
+#define MT6359_ACCDET_CON5 0x2692
+#define MT6359_ACCDET_CON6 0x2694
+#define MT6359_ACCDET_CON7 0x2696
+#define MT6359_ACCDET_CON8 0x2698
+#define MT6359_ACCDET_CON9 0x269a
+#define MT6359_ACCDET_CON10 0x269c
+#define MT6359_ACCDET_CON11 0x269e
+#define MT6359_ACCDET_CON12 0x26a0
+#define MT6359_ACCDET_CON13 0x26a2
+#define MT6359_ACCDET_CON14 0x26a4
+#define MT6359_ACCDET_CON15 0x26a6
+#define MT6359_ACCDET_CON16 0x26a8
+#define MT6359_ACCDET_CON17 0x26aa
+#define MT6359_ACCDET_CON18 0x26ac
+#define MT6359_ACCDET_CON19 0x26ae
+#define MT6359_ACCDET_CON20 0x26b0
+#define MT6359_ACCDET_CON21 0x26b2
+#define MT6359_ACCDET_CON22 0x26b4
+#define MT6359_ACCDET_CON23 0x26b6
+#define MT6359_ACCDET_CON24 0x26b8
+#define MT6359_ACCDET_CON25 0x26ba
+#define MT6359_ACCDET_CON26 0x26bc
+#define MT6359_ACCDET_CON27 0x26be
+#define MT6359_ACCDET_CON28 0x26c0
+#define MT6359_ACCDET_CON29 0x26c2
+#define MT6359_ACCDET_CON30 0x26c4
+#define MT6359_ACCDET_CON31 0x26c6
+#define MT6359_ACCDET_CON32 0x26c8
+#define MT6359_ACCDET_CON33 0x26ca
+#define MT6359_ACCDET_CON34 0x26cc
+#define MT6359_ACCDET_CON35 0x26ce
+#define MT6359_ACCDET_CON36 0x26d0
+#define MT6359_ACCDET_CON37 0x26d2
+#define MT6359_ACCDET_CON38 0x26d4
+#define MT6359_ACCDET_CON39 0x26d6
+#define MT6359_ACCDET_CON40 0x26d8
+
+#define TOP0_ANA_ID_ADDR \
+ MT6359_TOP0_ID
+#define TOP0_ANA_ID_SFT 0
+#define TOP0_ANA_ID_MASK 0xFF
+#define TOP0_ANA_ID_MASK_SFT (0xFF << 0)
+#define AUXADC_RQST_CH0_ADDR \
+ MT6359_AUXADC_RQST0
+#define AUXADC_RQST_CH0_SFT 0
+#define AUXADC_RQST_CH0_MASK 0x1
+#define AUXADC_RQST_CH0_MASK_SFT (0x1 << 0)
+#define AUXADC_ACCDET_ANASWCTRL_EN_ADDR \
+ MT6359_AUXADC_CON15
+#define AUXADC_ACCDET_ANASWCTRL_EN_SFT 6
+#define AUXADC_ACCDET_ANASWCTRL_EN_MASK 0x1
+#define AUXADC_ACCDET_ANASWCTRL_EN_MASK_SFT (0x1 << 6)
+
+#define AUXADC_ACCDET_AUTO_SPL_ADDR \
+ MT6359_AUXADC_ACCDET
+#define AUXADC_ACCDET_AUTO_SPL_SFT 0
+#define AUXADC_ACCDET_AUTO_SPL_MASK 0x1
+#define AUXADC_ACCDET_AUTO_SPL_MASK_SFT (0x1 << 0)
+#define AUXADC_ACCDET_AUTO_RQST_CLR_ADDR \
+ MT6359_AUXADC_ACCDET
+#define AUXADC_ACCDET_AUTO_RQST_CLR_SFT 1
+#define AUXADC_ACCDET_AUTO_RQST_CLR_MASK 0x1
+#define AUXADC_ACCDET_AUTO_RQST_CLR_MASK_SFT (0x1 << 1)
+#define AUXADC_ACCDET_DIG1_RSV0_ADDR \
+ MT6359_AUXADC_ACCDET
+#define AUXADC_ACCDET_DIG1_RSV0_SFT 2
+#define AUXADC_ACCDET_DIG1_RSV0_MASK 0x3F
+#define AUXADC_ACCDET_DIG1_RSV0_MASK_SFT (0x3F << 2)
+#define AUXADC_ACCDET_DIG0_RSV0_ADDR \
+ MT6359_AUXADC_ACCDET
+#define AUXADC_ACCDET_DIG0_RSV0_SFT 8
+#define AUXADC_ACCDET_DIG0_RSV0_MASK 0xFF
+#define AUXADC_ACCDET_DIG0_RSV0_MASK_SFT (0xFF << 8)
+
+#define RG_ACCDET_CK_PDN_ADDR \
+ MT6359_AUD_TOP_CKPDN_CON0
+#define RG_ACCDET_CK_PDN_SFT 0
+#define RG_ACCDET_CK_PDN_MASK 0x1
+#define RG_ACCDET_CK_PDN_MASK_SFT (0x1 << 0)
+
+#define RG_ACCDET_RST_ADDR \
+ MT6359_AUD_TOP_RST_CON0
+#define RG_ACCDET_RST_SFT 1
+#define RG_ACCDET_RST_MASK 0x1
+#define RG_ACCDET_RST_MASK_SFT (0x1 << 1)
+#define BANK_ACCDET_SWRST_ADDR \
+ MT6359_AUD_TOP_RST_BANK_CON0
+#define BANK_ACCDET_SWRST_SFT 0
+#define BANK_ACCDET_SWRST_MASK 0x1
+#define BANK_ACCDET_SWRST_MASK_SFT (0x1 << 0)
+
+#define RG_INT_EN_ACCDET_ADDR \
+ MT6359_AUD_TOP_INT_CON0
+#define RG_INT_EN_ACCDET_SFT 5
+#define RG_INT_EN_ACCDET_MASK 0x1
+#define RG_INT_EN_ACCDET_MASK_SFT (0x1 << 5)
+#define RG_INT_EN_ACCDET_EINT0_ADDR \
+ MT6359_AUD_TOP_INT_CON0
+#define RG_INT_EN_ACCDET_EINT0_SFT 6
+#define RG_INT_EN_ACCDET_EINT0_MASK 0x1
+#define RG_INT_EN_ACCDET_EINT0_MASK_SFT (0x1 << 6)
+#define RG_INT_EN_ACCDET_EINT1_ADDR \
+ MT6359_AUD_TOP_INT_CON0
+#define RG_INT_EN_ACCDET_EINT1_SFT 7
+#define RG_INT_EN_ACCDET_EINT1_MASK 0x1
+#define RG_INT_EN_ACCDET_EINT1_MASK_SFT (0x1 << 7)
+
+#define RG_INT_MASK_ACCDET_ADDR \
+ MT6359_AUD_TOP_INT_MASK_CON0
+#define RG_INT_MASK_ACCDET_SFT 5
+#define RG_INT_MASK_ACCDET_MASK 0x1
+#define RG_INT_MASK_ACCDET_MASK_SFT (0x1 << 5)
+#define RG_INT_MASK_ACCDET_EINT0_ADDR \
+ MT6359_AUD_TOP_INT_MASK_CON0
+#define RG_INT_MASK_ACCDET_EINT0_SFT 6
+#define RG_INT_MASK_ACCDET_EINT0_MASK 0x1
+#define RG_INT_MASK_ACCDET_EINT0_MASK_SFT (0x1 << 6)
+#define RG_INT_MASK_ACCDET_EINT1_ADDR \
+ MT6359_AUD_TOP_INT_MASK_CON0
+#define RG_INT_MASK_ACCDET_EINT1_SFT 7
+#define RG_INT_MASK_ACCDET_EINT1_MASK 0x1
+#define RG_INT_MASK_ACCDET_EINT1_MASK_SFT (0x1 << 7)
+
+#define RG_INT_STATUS_ACCDET_ADDR \
+ MT6359_AUD_TOP_INT_STATUS0
+#define RG_INT_STATUS_ACCDET_SFT 5
+#define RG_INT_STATUS_ACCDET_MASK 0x1
+#define RG_INT_STATUS_ACCDET_MASK_SFT (0x1 << 5)
+#define RG_INT_STATUS_ACCDET_EINT0_ADDR \
+ MT6359_AUD_TOP_INT_STATUS0
+#define RG_INT_STATUS_ACCDET_EINT0_SFT 6
+#define RG_INT_STATUS_ACCDET_EINT0_MASK 0x1
+#define RG_INT_STATUS_ACCDET_EINT0_MASK_SFT (0x1 << 6)
+#define RG_INT_STATUS_ACCDET_EINT1_ADDR \
+ MT6359_AUD_TOP_INT_STATUS0
+#define RG_INT_STATUS_ACCDET_EINT1_SFT 7
+#define RG_INT_STATUS_ACCDET_EINT1_MASK 0x1
+#define RG_INT_STATUS_ACCDET_EINT1_MASK_SFT (0x1 << 7)
+
+#define RG_INT_RAW_STATUS_ACCDET_ADDR \
+ MT6359_AUD_TOP_INT_RAW_STATUS0
+#define RG_INT_RAW_STATUS_ACCDET_SFT 5
+#define RG_INT_RAW_STATUS_ACCDET_MASK 0x1
+#define RG_INT_RAW_STATUS_ACCDET_MASK_SFT (0x1 << 5)
+#define RG_INT_RAW_STATUS_ACCDET_EINT0_ADDR \
+ MT6359_AUD_TOP_INT_RAW_STATUS0
+#define RG_INT_RAW_STATUS_ACCDET_EINT0_SFT 6
+#define RG_INT_RAW_STATUS_ACCDET_EINT0_MASK 0x1
+#define RG_INT_RAW_STATUS_ACCDET_EINT0_MASK_SFT (0x1 << 6)
+#define RG_INT_RAW_STATUS_ACCDET_EINT1_ADDR \
+ MT6359_AUD_TOP_INT_RAW_STATUS0
+#define RG_INT_RAW_STATUS_ACCDET_EINT1_SFT 7
+#define RG_INT_RAW_STATUS_ACCDET_EINT1_MASK 0x1
+#define RG_INT_RAW_STATUS_ACCDET_EINT1_MASK_SFT (0x1 << 7)
+
+#define RG_AUDACCDETMICBIAS0PULLLOW_ADDR \
+ MT6359_AUDENC_ANA_CON18
+#define RG_AUDACCDETMICBIAS0PULLLOW_SFT 0
+#define RG_AUDACCDETMICBIAS0PULLLOW_MASK 0x1
+#define RG_AUDACCDETMICBIAS0PULLLOW_MASK_SFT (0x1 << 0)
+#define RG_AUDACCDETMICBIAS1PULLLOW_ADDR \
+ MT6359_AUDENC_ANA_CON18
+#define RG_AUDACCDETMICBIAS1PULLLOW_SFT 1
+#define RG_AUDACCDETMICBIAS1PULLLOW_MASK 0x1
+#define RG_AUDACCDETMICBIAS1PULLLOW_MASK_SFT (0x1 << 1)
+#define RG_AUDACCDETMICBIAS2PULLLOW_ADDR \
+ MT6359_AUDENC_ANA_CON18
+#define RG_AUDACCDETMICBIAS2PULLLOW_SFT 2
+#define RG_AUDACCDETMICBIAS2PULLLOW_MASK 0x1
+#define RG_AUDACCDETMICBIAS2PULLLOW_MASK_SFT (0x1 << 2)
+#define RG_AUDACCDETVIN1PULLLOW_ADDR \
+ MT6359_AUDENC_ANA_CON18
+#define RG_AUDACCDETVIN1PULLLOW_SFT 3
+#define RG_AUDACCDETVIN1PULLLOW_MASK 0x1
+#define RG_AUDACCDETVIN1PULLLOW_MASK_SFT (0x1 << 3)
+#define RG_AUDACCDETVTHACAL_ADDR \
+ MT6359_AUDENC_ANA_CON18
+#define RG_AUDACCDETVTHACAL_SFT 4
+#define RG_AUDACCDETVTHACAL_MASK 0x1
+#define RG_AUDACCDETVTHACAL_MASK_SFT (0x1 << 4)
+#define RG_AUDACCDETVTHBCAL_ADDR \
+ MT6359_AUDENC_ANA_CON18
+#define RG_AUDACCDETVTHBCAL_SFT 5
+#define RG_AUDACCDETVTHBCAL_MASK 0x1
+#define RG_AUDACCDETVTHBCAL_MASK_SFT (0x1 << 5)
+#define RG_AUDACCDETTVDET_ADDR \
+ MT6359_AUDENC_ANA_CON18
+#define RG_AUDACCDETTVDET_SFT 6
+#define RG_AUDACCDETTVDET_MASK 0x1
+#define RG_AUDACCDETTVDET_MASK_SFT (0x1 << 6)
+#define RG_ACCDETSEL_ADDR \
+ MT6359_AUDENC_ANA_CON18
+#define RG_ACCDETSEL_SFT 7
+#define RG_ACCDETSEL_MASK 0x1
+#define RG_ACCDETSEL_MASK_SFT (0x1 << 7)
+
+#define RG_AUDPWDBMICBIAS1_ADDR \
+ MT6359_AUDENC_ANA_CON16
+#define RG_AUDPWDBMICBIAS1_SFT 0
+#define RG_AUDPWDBMICBIAS1_MASK 0x1
+#define RG_AUDPWDBMICBIAS1_MASK_SFT (0x1 << 0)
+#define RG_AUDMICBIAS1BYPASSEN_ADDR \
+ MT6359_AUDENC_ANA_CON16
+#define RG_AUDMICBIAS1BYPASSEN_SFT 1
+#define RG_AUDMICBIAS1BYPASSEN_MASK 0x1
+#define RG_AUDMICBIAS1BYPASSEN_MASK_SFT (0x1 << 1)
+#define RG_AUDMICBIAS1LOWPEN_ADDR \
+ MT6359_AUDENC_ANA_CON16
+#define RG_AUDMICBIAS1LOWPEN_SFT 2
+#define RG_AUDMICBIAS1LOWPEN_MASK 0x1
+#define RG_AUDMICBIAS1LOWPEN_MASK_SFT (0x1 << 2)
+#define RG_AUDMICBIAS1VREF_ADDR \
+ MT6359_AUDENC_ANA_CON16
+#define RG_AUDMICBIAS1VREF_SFT 4
+#define RG_AUDMICBIAS1VREF_MASK 0x7
+#define RG_AUDMICBIAS1VREF_MASK_SFT (0x7 << 4)
+#define RG_AUDMICBIAS1DCSW1PEN_ADDR \
+ MT6359_AUDENC_ANA_CON16
+#define RG_AUDMICBIAS1DCSW1PEN_SFT 8
+#define RG_AUDMICBIAS1DCSW1PEN_MASK 0x1
+#define RG_AUDMICBIAS1DCSW1PEN_MASK_SFT (0x1 << 8)
+#define RG_AUDMICBIAS1DCSW1NEN_ADDR \
+ MT6359_AUDENC_ANA_CON16
+#define RG_AUDMICBIAS1DCSW1NEN_SFT 9
+#define RG_AUDMICBIAS1DCSW1NEN_MASK 0x1
+#define RG_AUDMICBIAS1DCSW1NEN_MASK_SFT (0x1 << 9)
+#define RG_BANDGAPGEN_ADDR \
+ MT6359_AUDENC_ANA_CON16
+#define RG_BANDGAPGEN_SFT 10
+#define RG_BANDGAPGEN_MASK 0x1
+#define RG_BANDGAPGEN_MASK_SFT (0x1 << 10)
+#define RG_AUDMICBIAS1HVEN_ADDR \
+ MT6359_AUDENC_ANA_CON16
+#define RG_AUDMICBIAS1HVEN_SFT 12
+#define RG_AUDMICBIAS1HVEN_MASK 0x1
+#define RG_AUDMICBIAS1HVEN_MASK_SFT (0x1 << 12)
+#define RG_AUDMICBIAS1HVVREF_ADDR \
+ MT6359_AUDENC_ANA_CON16
+#define RG_AUDMICBIAS1HVVREF_SFT 13
+#define RG_AUDMICBIAS1HVVREF_MASK 0x1
+#define RG_AUDMICBIAS1HVVREF_MASK_SFT (0x1 << 13)
+
+#define RG_EINT0NOHYS_ADDR \
+ MT6359_AUDENC_ANA_CON18
+#define RG_EINT0NOHYS_SFT 10
+#define RG_EINT0NOHYS_MASK 0x1
+#define RG_EINT0NOHYS_MASK_SFT (0x1 << 10)
+#define RG_EINT0CONFIGACCDET_ADDR \
+ MT6359_AUDENC_ANA_CON18
+#define RG_EINT0CONFIGACCDET_SFT 11
+#define RG_EINT0CONFIGACCDET_MASK 0x1
+#define RG_EINT0CONFIGACCDET_MASK_SFT (0x1 << 11)
+#define RG_EINT0HIRENB_ADDR \
+ MT6359_AUDENC_ANA_CON18
+#define RG_EINT0HIRENB_SFT 12
+#define RG_EINT0HIRENB_MASK 0x1
+#define RG_EINT0HIRENB_MASK_SFT (0x1 << 12)
+#define RG_ACCDET2AUXRESBYPASS_ADDR \
+ MT6359_AUDENC_ANA_CON18
+#define RG_ACCDET2AUXRESBYPASS_SFT 13
+#define RG_ACCDET2AUXRESBYPASS_MASK 0x1
+#define RG_ACCDET2AUXRESBYPASS_MASK_SFT (0x1 << 13)
+#define RG_ACCDET2AUXSWEN_ADDR \
+ MT6359_AUDENC_ANA_CON18
+#define RG_ACCDET2AUXSWEN_SFT 14
+#define RG_ACCDET2AUXSWEN_MASK 0x1
+#define RG_ACCDET2AUXSWEN_MASK_SFT (0x1 << 14)
+#define RG_AUDACCDETMICBIAS3PULLLOW_ADDR \
+ MT6359_AUDENC_ANA_CON18
+#define RG_AUDACCDETMICBIAS3PULLLOW_SFT 15
+#define RG_AUDACCDETMICBIAS3PULLLOW_MASK 0x1
+#define RG_AUDACCDETMICBIAS3PULLLOW_MASK_SFT (0x1 << 15)
+#define RG_EINT1CONFIGACCDET_ADDR \
+ MT6359_AUDENC_ANA_CON19
+#define RG_EINT1CONFIGACCDET_SFT 0
+#define RG_EINT1CONFIGACCDET_MASK 0x1
+#define RG_EINT1CONFIGACCDET_MASK_SFT (0x1 << 0)
+#define RG_EINT1HIRENB_ADDR \
+ MT6359_AUDENC_ANA_CON19
+#define RG_EINT1HIRENB_SFT 1
+#define RG_EINT1HIRENB_MASK 0x1
+#define RG_EINT1HIRENB_MASK_SFT (0x1 << 1)
+#define RG_EINT1NOHYS_ADDR \
+ MT6359_AUDENC_ANA_CON19
+#define RG_EINT1NOHYS_SFT 2
+#define RG_EINT1NOHYS_MASK 0x1
+#define RG_EINT1NOHYS_MASK_SFT (0x1 << 2)
+#define RG_EINTCOMPVTH_ADDR \
+ MT6359_AUDENC_ANA_CON19
+#define RG_MTEST_EN_ADDR \
+ MT6359_AUDENC_ANA_CON19
+#define RG_MTEST_EN_SFT 8
+#define RG_MTEST_EN_MASK 0x1
+#define RG_MTEST_EN_MASK_SFT (0x1 << 8)
+#define RG_MTEST_SEL_ADDR \
+ MT6359_AUDENC_ANA_CON19
+#define RG_MTEST_SEL_SFT 9
+#define RG_MTEST_SEL_MASK 0x1
+#define RG_MTEST_SEL_MASK_SFT (0x1 << 9)
+#define RG_MTEST_CURRENT_ADDR \
+ MT6359_AUDENC_ANA_CON19
+#define RG_MTEST_CURRENT_SFT 10
+#define RG_MTEST_CURRENT_MASK 0x1
+#define RG_MTEST_CURRENT_MASK_SFT (0x1 << 10)
+#define RG_ANALOGFDEN_ADDR \
+ MT6359_AUDENC_ANA_CON19
+#define RG_ANALOGFDEN_SFT 12
+#define RG_ANALOGFDEN_MASK 0x1
+#define RG_ANALOGFDEN_MASK_SFT (0x1 << 12)
+#define RG_FDVIN1PPULLLOW_ADDR \
+ MT6359_AUDENC_ANA_CON19
+#define RG_FDVIN1PPULLLOW_SFT 13
+#define RG_FDVIN1PPULLLOW_MASK 0x1
+#define RG_FDVIN1PPULLLOW_MASK_SFT (0x1 << 13)
+#define RG_FDEINT0TYPE_ADDR \
+ MT6359_AUDENC_ANA_CON19
+#define RG_FDEINT0TYPE_SFT 14
+#define RG_FDEINT0TYPE_MASK 0x1
+#define RG_FDEINT0TYPE_MASK_SFT (0x1 << 14)
+#define RG_FDEINT1TYPE_ADDR \
+ MT6359_AUDENC_ANA_CON19
+#define RG_FDEINT1TYPE_SFT 15
+#define RG_FDEINT1TYPE_MASK 0x1
+#define RG_FDEINT1TYPE_MASK_SFT (0x1 << 15)
+#define RG_EINT0CMPEN_ADDR \
+ MT6359_AUDENC_ANA_CON20
+#define RG_EINT0CMPEN_SFT 0
+#define RG_EINT0CMPEN_MASK 0x1
+#define RG_EINT0CMPEN_MASK_SFT (0x1 << 0)
+#define RG_EINT0CMPMEN_ADDR \
+ MT6359_AUDENC_ANA_CON20
+#define RG_EINT0CMPMEN_SFT 1
+#define RG_EINT0CMPMEN_MASK 0x1
+#define RG_EINT0CMPMEN_MASK_SFT (0x1 << 1)
+#define RG_EINT0EN_ADDR \
+ MT6359_AUDENC_ANA_CON20
+#define RG_EINT0EN_SFT 2
+#define RG_EINT0EN_MASK 0x1
+#define RG_EINT0EN_MASK_SFT (0x1 << 2)
+#define RG_EINT0CEN_ADDR \
+ MT6359_AUDENC_ANA_CON20
+#define RG_EINT0CEN_SFT 3
+#define RG_EINT0CEN_MASK 0x1
+#define RG_EINT0CEN_MASK_SFT (0x1 << 3)
+#define RG_EINT0INVEN_ADDR \
+ MT6359_AUDENC_ANA_CON20
+#define RG_EINT0INVEN_SFT 4
+#define RG_EINT0INVEN_MASK 0x1
+#define RG_EINT0INVEN_MASK_SFT (0x1 << 4)
+#define RG_EINT0CTURBO_ADDR \
+ MT6359_AUDENC_ANA_CON20
+#define RG_EINT0CTURBO_SFT 5
+#define RG_EINT0CTURBO_MASK 0x7
+#define RG_EINT0CTURBO_MASK_SFT (0x7 << 5)
+#define RG_EINT1CMPEN_ADDR \
+ MT6359_AUDENC_ANA_CON20
+#define RG_EINT1CMPEN_SFT 8
+#define RG_EINT1CMPEN_MASK 0x1
+#define RG_EINT1CMPEN_MASK_SFT (0x1 << 8)
+#define RG_EINT1CMPMEN_ADDR \
+ MT6359_AUDENC_ANA_CON20
+#define RG_EINT1CMPMEN_SFT 9
+#define RG_EINT1CMPMEN_MASK 0x1
+#define RG_EINT1CMPMEN_MASK_SFT (0x1 << 9)
+#define RG_EINT1EN_ADDR \
+ MT6359_AUDENC_ANA_CON20
+#define RG_EINT1EN_SFT 10
+#define RG_EINT1EN_MASK 0x1
+#define RG_EINT1EN_MASK_SFT (0x1 << 10)
+#define RG_EINT1CEN_ADDR \
+ MT6359_AUDENC_ANA_CON20
+#define RG_EINT1CEN_SFT 11
+#define RG_EINT1CEN_MASK 0x1
+#define RG_EINT1CEN_MASK_SFT (0x1 << 11)
+#define RG_EINT1INVEN_ADDR \
+ MT6359_AUDENC_ANA_CON20
+#define RG_EINT1INVEN_SFT 12
+#define RG_EINT1INVEN_MASK 0x1
+#define RG_EINT1INVEN_MASK_SFT (0x1 << 12)
+#define RG_EINT1CTURBO_ADDR \
+ MT6359_AUDENC_ANA_CON20
+#define RG_EINT1CTURBO_SFT 13
+#define RG_EINT1CTURBO_MASK 0x7
+#define RG_EINT1CTURBO_MASK_SFT (0x7 << 13)
+#define RG_ACCDETSPARE_ADDR \
+ MT6359_AUDENC_ANA_CON21
+
+#define ACCDET_ANA_ID_ADDR \
+ MT6359_ACCDET_DSN_DIG_ID
+#define ACCDET_ANA_ID_SFT 0
+#define ACCDET_ANA_ID_MASK 0xFF
+#define ACCDET_ANA_ID_MASK_SFT (0xFF << 0)
+#define ACCDET_DIG_ID_ADDR \
+ MT6359_ACCDET_DSN_DIG_ID
+#define ACCDET_DIG_ID_SFT 8
+#define ACCDET_DIG_ID_MASK 0xFF
+#define ACCDET_DIG_ID_MASK_SFT (0xFF << 8)
+#define ACCDET_ANA_MINOR_REV_ADDR \
+ MT6359_ACCDET_DSN_DIG_REV0
+#define ACCDET_ANA_MINOR_REV_SFT 0
+#define ACCDET_ANA_MINOR_REV_MASK 0xF
+#define ACCDET_ANA_MINOR_REV_MASK_SFT (0xF << 0)
+#define ACCDET_ANA_MAJOR_REV_ADDR \
+ MT6359_ACCDET_DSN_DIG_REV0
+#define ACCDET_ANA_MAJOR_REV_SFT 4
+#define ACCDET_ANA_MAJOR_REV_MASK 0xF
+#define ACCDET_ANA_MAJOR_REV_MASK_SFT (0xF << 4)
+#define ACCDET_DIG_MINOR_REV_ADDR \
+ MT6359_ACCDET_DSN_DIG_REV0
+#define ACCDET_DIG_MINOR_REV_SFT 8
+#define ACCDET_DIG_MINOR_REV_MASK 0xF
+#define ACCDET_DIG_MINOR_REV_MASK_SFT (0xF << 8)
+#define ACCDET_DIG_MAJOR_REV_ADDR \
+ MT6359_ACCDET_DSN_DIG_REV0
+#define ACCDET_DIG_MAJOR_REV_SFT 12
+#define ACCDET_DIG_MAJOR_REV_MASK 0xF
+#define ACCDET_DIG_MAJOR_REV_MASK_SFT (0xF << 12)
+#define ACCDET_DSN_CBS_ADDR \
+ MT6359_ACCDET_DSN_DBI
+#define ACCDET_DSN_CBS_SFT 0
+#define ACCDET_DSN_CBS_MASK 0x3
+#define ACCDET_DSN_CBS_MASK_SFT (0x3 << 0)
+#define ACCDET_DSN_BIX_ADDR \
+ MT6359_ACCDET_DSN_DBI
+#define ACCDET_DSN_BIX_SFT 2
+#define ACCDET_DSN_BIX_MASK 0x3
+#define ACCDET_DSN_BIX_MASK_SFT (0x3 << 2)
+#define ACCDET_ESP_ADDR \
+ MT6359_ACCDET_DSN_DBI
+#define ACCDET_ESP_SFT 8
+#define ACCDET_ESP_MASK 0xFF
+#define ACCDET_ESP_MASK_SFT (0xFF << 8)
+#define ACCDET_DSN_FPI_ADDR \
+ MT6359_ACCDET_DSN_FPI
+#define ACCDET_DSN_FPI_SFT 0
+#define ACCDET_DSN_FPI_MASK 0xFF
+#define ACCDET_DSN_FPI_MASK_SFT (0xFF << 0)
+#define ACCDET_AUXADC_SEL_ADDR \
+ MT6359_ACCDET_CON0
+#define ACCDET_AUXADC_SEL_SFT 0
+#define ACCDET_AUXADC_SEL_MASK 0x1
+#define ACCDET_AUXADC_SEL_MASK_SFT (0x1 << 0)
+#define ACCDET_AUXADC_SW_ADDR \
+ MT6359_ACCDET_CON0
+#define ACCDET_AUXADC_SW_SFT 1
+#define ACCDET_AUXADC_SW_MASK 0x1
+#define ACCDET_AUXADC_SW_MASK_SFT (0x1 << 1)
+#define ACCDET_TEST_AUXADC_ADDR \
+ MT6359_ACCDET_CON0
+#define ACCDET_TEST_AUXADC_SFT 2
+#define ACCDET_TEST_AUXADC_MASK 0x1
+#define ACCDET_TEST_AUXADC_MASK_SFT (0x1 << 2)
+#define ACCDET_AUXADC_ANASWCTRL_SEL_ADDR \
+ MT6359_ACCDET_CON0
+#define ACCDET_AUXADC_ANASWCTRL_SEL_SFT 8
+#define ACCDET_AUXADC_ANASWCTRL_SEL_MASK 0x1
+#define ACCDET_AUXADC_ANASWCTRL_SEL_MASK_SFT (0x1 << 8)
+#define AUDACCDETAUXADCSWCTRL_SEL_ADDR \
+ MT6359_ACCDET_CON0
+#define AUDACCDETAUXADCSWCTRL_SEL_SFT 9
+#define AUDACCDETAUXADCSWCTRL_SEL_MASK 0x1
+#define AUDACCDETAUXADCSWCTRL_SEL_MASK_SFT (0x1 << 9)
+#define AUDACCDETAUXADCSWCTRL_SW_ADDR \
+ MT6359_ACCDET_CON0
+#define AUDACCDETAUXADCSWCTRL_SW_SFT 10
+#define AUDACCDETAUXADCSWCTRL_SW_MASK 0x1
+#define AUDACCDETAUXADCSWCTRL_SW_MASK_SFT (0x1 << 10)
+#define ACCDET_TEST_ANA_ADDR \
+ MT6359_ACCDET_CON0
+#define ACCDET_TEST_ANA_SFT 11
+#define ACCDET_TEST_ANA_MASK 0x1
+#define ACCDET_TEST_ANA_MASK_SFT (0x1 << 11)
+#define RG_AUDACCDETRSV_ADDR \
+ MT6359_ACCDET_CON0
+#define RG_AUDACCDETRSV_SFT 13
+#define RG_AUDACCDETRSV_MASK 0x3
+#define RG_AUDACCDETRSV_MASK_SFT (0x3 << 13)
+#define ACCDET_SW_EN_ADDR \
+ MT6359_ACCDET_CON1
+#define ACCDET_SW_EN_SFT 0
+#define ACCDET_SW_EN_MASK 0x1
+#define ACCDET_SW_EN_MASK_SFT (0x1 << 0)
+#define ACCDET_SEQ_INIT_ADDR \
+ MT6359_ACCDET_CON1
+#define ACCDET_SEQ_INIT_SFT 1
+#define ACCDET_SEQ_INIT_MASK 0x1
+#define ACCDET_SEQ_INIT_MASK_SFT (0x1 << 1)
+#define ACCDET_EINT0_SW_EN_ADDR \
+ MT6359_ACCDET_CON1
+#define ACCDET_EINT0_SW_EN_SFT 2
+#define ACCDET_EINT0_SW_EN_MASK 0x1
+#define ACCDET_EINT0_SW_EN_MASK_SFT (0x1 << 2)
+#define ACCDET_EINT0_SEQ_INIT_ADDR \
+ MT6359_ACCDET_CON1
+#define ACCDET_EINT0_SEQ_INIT_SFT 3
+#define ACCDET_EINT0_SEQ_INIT_MASK 0x1
+#define ACCDET_EINT0_SEQ_INIT_MASK_SFT (0x1 << 3)
+#define ACCDET_EINT1_SW_EN_ADDR \
+ MT6359_ACCDET_CON1
+#define ACCDET_EINT1_SW_EN_SFT 4
+#define ACCDET_EINT1_SW_EN_MASK 0x1
+#define ACCDET_EINT1_SW_EN_MASK_SFT (0x1 << 4)
+#define ACCDET_EINT1_SEQ_INIT_ADDR \
+ MT6359_ACCDET_CON1
+#define ACCDET_EINT1_SEQ_INIT_SFT 5
+#define ACCDET_EINT1_SEQ_INIT_MASK 0x1
+#define ACCDET_EINT1_SEQ_INIT_MASK_SFT (0x1 << 5)
+#define ACCDET_EINT0_INVERTER_SW_EN_ADDR \
+ MT6359_ACCDET_CON1
+#define ACCDET_EINT0_INVERTER_SW_EN_SFT 6
+#define ACCDET_EINT0_INVERTER_SW_EN_MASK 0x1
+#define ACCDET_EINT0_INVERTER_SW_EN_MASK_SFT (0x1 << 6)
+#define ACCDET_EINT0_INVERTER_SEQ_INIT_ADDR \
+ MT6359_ACCDET_CON1
+#define ACCDET_EINT0_INVERTER_SEQ_INIT_SFT 7
+#define ACCDET_EINT0_INVERTER_SEQ_INIT_MASK 0x1
+#define ACCDET_EINT0_INVERTER_SEQ_INIT_MASK_SFT (0x1 << 7)
+#define ACCDET_EINT1_INVERTER_SW_EN_ADDR \
+ MT6359_ACCDET_CON1
+#define ACCDET_EINT1_INVERTER_SW_EN_SFT 8
+#define ACCDET_EINT1_INVERTER_SW_EN_MASK 0x1
+#define ACCDET_EINT1_INVERTER_SW_EN_MASK_SFT (0x1 << 8)
+#define ACCDET_EINT1_INVERTER_SEQ_INIT_ADDR \
+ MT6359_ACCDET_CON1
+#define ACCDET_EINT1_INVERTER_SEQ_INIT_SFT 9
+#define ACCDET_EINT1_INVERTER_SEQ_INIT_MASK 0x1
+#define ACCDET_EINT1_INVERTER_SEQ_INIT_MASK_SFT (0x1 << 9)
+#define ACCDET_EINT0_M_SW_EN_ADDR \
+ MT6359_ACCDET_CON1
+#define ACCDET_EINT0_M_SW_EN_SFT 10
+#define ACCDET_EINT0_M_SW_EN_MASK 0x1
+#define ACCDET_EINT0_M_SW_EN_MASK_SFT (0x1 << 10)
+#define ACCDET_EINT1_M_SW_EN_ADDR \
+ MT6359_ACCDET_CON1
+#define ACCDET_EINT1_M_SW_EN_SFT 11
+#define ACCDET_EINT1_M_SW_EN_MASK 0x1
+#define ACCDET_EINT1_M_SW_EN_MASK_SFT (0x1 << 11)
+#define ACCDET_EINT_M_DETECT_EN_ADDR \
+ MT6359_ACCDET_CON1
+#define ACCDET_EINT_M_DETECT_EN_SFT 12
+#define ACCDET_EINT_M_DETECT_EN_MASK 0x1
+#define ACCDET_EINT_M_DETECT_EN_MASK_SFT (0x1 << 12)
+#define ACCDET_CMP_PWM_EN_ADDR \
+ MT6359_ACCDET_CON2
+#define ACCDET_CMP_PWM_EN_SFT 0
+#define ACCDET_CMP_PWM_EN_MASK 0x1
+#define ACCDET_CMP_PWM_EN_MASK_SFT (0x1 << 0)
+#define ACCDET_VTH_PWM_EN_ADDR \
+ MT6359_ACCDET_CON2
+#define ACCDET_VTH_PWM_EN_SFT 1
+#define ACCDET_VTH_PWM_EN_MASK 0x1
+#define ACCDET_VTH_PWM_EN_MASK_SFT (0x1 << 1)
+#define ACCDET_MBIAS_PWM_EN_ADDR \
+ MT6359_ACCDET_CON2
+#define ACCDET_MBIAS_PWM_EN_SFT 2
+#define ACCDET_MBIAS_PWM_EN_MASK 0x1
+#define ACCDET_MBIAS_PWM_EN_MASK_SFT (0x1 << 2)
+#define ACCDET_EINT_EN_PWM_EN_ADDR \
+ MT6359_ACCDET_CON2
+#define ACCDET_EINT_EN_PWM_EN_SFT 3
+#define ACCDET_EINT_EN_PWM_EN_MASK 0x1
+#define ACCDET_EINT_EN_PWM_EN_MASK_SFT (0x1 << 3)
+#define ACCDET_EINT_CMPEN_PWM_EN_ADDR \
+ MT6359_ACCDET_CON2
+#define ACCDET_EINT_CMPEN_PWM_EN_SFT 4
+#define ACCDET_EINT_CMPEN_PWM_EN_MASK 0x1
+#define ACCDET_EINT_CMPEN_PWM_EN_MASK_SFT (0x1 << 4)
+#define ACCDET_EINT_CMPMEN_PWM_EN_ADDR \
+ MT6359_ACCDET_CON2
+#define ACCDET_EINT_CMPMEN_PWM_EN_SFT 5
+#define ACCDET_EINT_CMPMEN_PWM_EN_MASK 0x1
+#define ACCDET_EINT_CMPMEN_PWM_EN_MASK_SFT (0x1 << 5)
+#define ACCDET_EINT_CTURBO_PWM_EN_ADDR \
+ MT6359_ACCDET_CON2
+#define ACCDET_EINT_CTURBO_PWM_EN_SFT 6
+#define ACCDET_EINT_CTURBO_PWM_EN_MASK 0x1
+#define ACCDET_EINT_CTURBO_PWM_EN_MASK_SFT (0x1 << 6)
+#define ACCDET_CMP_PWM_IDLE_ADDR \
+ MT6359_ACCDET_CON2
+#define ACCDET_CMP_PWM_IDLE_SFT 8
+#define ACCDET_CMP_PWM_IDLE_MASK 0x1
+#define ACCDET_CMP_PWM_IDLE_MASK_SFT (0x1 << 8)
+#define ACCDET_VTH_PWM_IDLE_ADDR \
+ MT6359_ACCDET_CON2
+#define ACCDET_VTH_PWM_IDLE_SFT 9
+#define ACCDET_VTH_PWM_IDLE_MASK 0x1
+#define ACCDET_VTH_PWM_IDLE_MASK_SFT (0x1 << 9)
+#define ACCDET_MBIAS_PWM_IDLE_ADDR \
+ MT6359_ACCDET_CON2
+#define ACCDET_MBIAS_PWM_IDLE_SFT 10
+#define ACCDET_MBIAS_PWM_IDLE_MASK 0x1
+#define ACCDET_MBIAS_PWM_IDLE_MASK_SFT (0x1 << 10)
+#define ACCDET_EINT0_CMPEN_PWM_IDLE_ADDR \
+ MT6359_ACCDET_CON2
+#define ACCDET_EINT0_CMPEN_PWM_IDLE_SFT 11
+#define ACCDET_EINT0_CMPEN_PWM_IDLE_MASK 0x1
+#define ACCDET_EINT0_CMPEN_PWM_IDLE_MASK_SFT (0x1 << 11)
+#define ACCDET_EINT1_CMPEN_PWM_IDLE_ADDR \
+ MT6359_ACCDET_CON2
+#define ACCDET_EINT1_CMPEN_PWM_IDLE_SFT 12
+#define ACCDET_EINT1_CMPEN_PWM_IDLE_MASK 0x1
+#define ACCDET_EINT1_CMPEN_PWM_IDLE_MASK_SFT (0x1 << 12)
+#define ACCDET_PWM_EN_SW_ADDR \
+ MT6359_ACCDET_CON2
+#define ACCDET_PWM_EN_SW_SFT 13
+#define ACCDET_PWM_EN_SW_MASK 0x1
+#define ACCDET_PWM_EN_SW_MASK_SFT (0x1 << 13)
+#define ACCDET_PWM_EN_SEL_ADDR \
+ MT6359_ACCDET_CON2
+#define ACCDET_PWM_EN_SEL_SFT 14
+#define ACCDET_PWM_EN_SEL_MASK 0x3
+#define ACCDET_PWM_EN_SEL_MASK_SFT (0x3 << 14)
+#define ACCDET_PWM_WIDTH_ADDR \
+ MT6359_ACCDET_CON3
+#define ACCDET_PWM_WIDTH_SFT 0
+#define ACCDET_PWM_WIDTH_MASK 0xFFFF
+#define ACCDET_PWM_WIDTH_MASK_SFT (0xFFFF << 0)
+#define ACCDET_PWM_THRESH_ADDR \
+ MT6359_ACCDET_CON4
+#define ACCDET_PWM_THRESH_SFT 0
+#define ACCDET_PWM_THRESH_MASK 0xFFFF
+#define ACCDET_PWM_THRESH_MASK_SFT (0xFFFF << 0)
+#define ACCDET_RISE_DELAY_ADDR \
+ MT6359_ACCDET_CON5
+#define ACCDET_RISE_DELAY_SFT 0
+#define ACCDET_RISE_DELAY_MASK 0x7FFF
+#define ACCDET_RISE_DELAY_MASK_SFT (0x7FFF << 0)
+#define ACCDET_FALL_DELAY_ADDR \
+ MT6359_ACCDET_CON5
+#define ACCDET_FALL_DELAY_SFT 15
+#define ACCDET_FALL_DELAY_MASK 0x1
+#define ACCDET_FALL_DELAY_MASK_SFT (0x1 << 15)
+#define ACCDET_EINT_CMPMEN_PWM_THRESH_ADDR \
+ MT6359_ACCDET_CON6
+#define ACCDET_EINT_CMPMEN_PWM_THRESH_SFT 0
+#define ACCDET_EINT_CMPMEN_PWM_THRESH_MASK 0x7
+#define ACCDET_EINT_CMPMEN_PWM_THRESH_MASK_SFT (0x7 << 0)
+#define ACCDET_EINT_CMPMEN_PWM_WIDTH_ADDR \
+ MT6359_ACCDET_CON6
+#define ACCDET_EINT_CMPMEN_PWM_WIDTH_SFT 4
+#define ACCDET_EINT_CMPMEN_PWM_WIDTH_MASK 0x7
+#define ACCDET_EINT_CMPMEN_PWM_WIDTH_MASK_SFT (0x7 << 4)
+#define ACCDET_EINT_EN_PWM_THRESH_ADDR \
+ MT6359_ACCDET_CON7
+#define ACCDET_EINT_EN_PWM_THRESH_SFT 0
+#define ACCDET_EINT_EN_PWM_THRESH_MASK 0x7
+#define ACCDET_EINT_EN_PWM_THRESH_MASK_SFT (0x7 << 0)
+#define ACCDET_EINT_EN_PWM_WIDTH_ADDR \
+ MT6359_ACCDET_CON7
+#define ACCDET_EINT_EN_PWM_WIDTH_SFT 4
+#define ACCDET_EINT_EN_PWM_WIDTH_MASK 0x3
+#define ACCDET_EINT_EN_PWM_WIDTH_MASK_SFT (0x3 << 4)
+#define ACCDET_EINT_CMPEN_PWM_THRESH_ADDR \
+ MT6359_ACCDET_CON7
+#define ACCDET_EINT_CMPEN_PWM_THRESH_SFT 8
+#define ACCDET_EINT_CMPEN_PWM_THRESH_MASK 0x7
+#define ACCDET_EINT_CMPEN_PWM_THRESH_MASK_SFT (0x7 << 8)
+#define ACCDET_EINT_CMPEN_PWM_WIDTH_ADDR \
+ MT6359_ACCDET_CON7
+#define ACCDET_EINT_CMPEN_PWM_WIDTH_SFT 12
+#define ACCDET_EINT_CMPEN_PWM_WIDTH_MASK 0x3
+#define ACCDET_EINT_CMPEN_PWM_WIDTH_MASK_SFT (0x3 << 12)
+#define ACCDET_DEBOUNCE0_ADDR \
+ MT6359_ACCDET_CON8
+#define ACCDET_DEBOUNCE0_SFT 0
+#define ACCDET_DEBOUNCE0_MASK 0xFFFF
+#define ACCDET_DEBOUNCE0_MASK_SFT (0xFFFF << 0)
+#define ACCDET_DEBOUNCE1_ADDR \
+ MT6359_ACCDET_CON9
+#define ACCDET_DEBOUNCE1_SFT 0
+#define ACCDET_DEBOUNCE1_MASK 0xFFFF
+#define ACCDET_DEBOUNCE1_MASK_SFT (0xFFFF << 0)
+#define ACCDET_DEBOUNCE2_ADDR \
+ MT6359_ACCDET_CON10
+#define ACCDET_DEBOUNCE2_SFT 0
+#define ACCDET_DEBOUNCE2_MASK 0xFFFF
+#define ACCDET_DEBOUNCE2_MASK_SFT (0xFFFF << 0)
+#define ACCDET_DEBOUNCE3_ADDR \
+ MT6359_ACCDET_CON11
+#define ACCDET_DEBOUNCE3_SFT 0
+#define ACCDET_DEBOUNCE3_MASK 0xFFFF
+#define ACCDET_DEBOUNCE3_MASK_SFT (0xFFFF << 0)
+#define ACCDET_CONNECT_AUXADC_TIME_DIG_ADDR \
+ MT6359_ACCDET_CON12
+#define ACCDET_CONNECT_AUXADC_TIME_DIG_SFT 0
+#define ACCDET_CONNECT_AUXADC_TIME_DIG_MASK 0xFFFF
+#define ACCDET_CONNECT_AUXADC_TIME_DIG_MASK_SFT (0xFFFF << 0)
+#define ACCDET_CONNECT_AUXADC_TIME_ANA_ADDR \
+ MT6359_ACCDET_CON13
+#define ACCDET_CONNECT_AUXADC_TIME_ANA_SFT 0
+#define ACCDET_CONNECT_AUXADC_TIME_ANA_MASK 0xFFFF
+#define ACCDET_CONNECT_AUXADC_TIME_ANA_MASK_SFT (0xFFFF << 0)
+#define ACCDET_EINT_DEBOUNCE0_ADDR \
+ MT6359_ACCDET_CON14
+#define ACCDET_EINT_DEBOUNCE0_SFT 0
+#define ACCDET_EINT_DEBOUNCE0_MASK 0xF
+#define ACCDET_EINT_DEBOUNCE0_MASK_SFT (0xF << 0)
+#define ACCDET_EINT_DEBOUNCE1_ADDR \
+ MT6359_ACCDET_CON14
+#define ACCDET_EINT_DEBOUNCE1_SFT 4
+#define ACCDET_EINT_DEBOUNCE1_MASK 0xF
+#define ACCDET_EINT_DEBOUNCE1_MASK_SFT (0xF << 4)
+#define ACCDET_EINT_DEBOUNCE2_ADDR \
+ MT6359_ACCDET_CON14
+#define ACCDET_EINT_DEBOUNCE2_SFT 8
+#define ACCDET_EINT_DEBOUNCE2_MASK 0xF
+#define ACCDET_EINT_DEBOUNCE2_MASK_SFT (0xF << 8)
+#define ACCDET_EINT_DEBOUNCE3_ADDR \
+ MT6359_ACCDET_CON14
+#define ACCDET_EINT_DEBOUNCE3_SFT 12
+#define ACCDET_EINT_DEBOUNCE3_MASK 0xF
+#define ACCDET_EINT_DEBOUNCE3_MASK_SFT (0xF << 12)
+#define ACCDET_EINT_INVERTER_DEBOUNCE_ADDR \
+ MT6359_ACCDET_CON15
+#define ACCDET_EINT_INVERTER_DEBOUNCE_SFT 0
+#define ACCDET_EINT_INVERTER_DEBOUNCE_MASK 0xF
+#define ACCDET_EINT_INVERTER_DEBOUNCE_MASK_SFT (0xF << 0)
+#define ACCDET_IVAL_CUR_IN_ADDR \
+ MT6359_ACCDET_CON16
+#define ACCDET_IVAL_CUR_IN_SFT 0
+#define ACCDET_IVAL_CUR_IN_MASK 0x3
+#define ACCDET_IVAL_CUR_IN_MASK_SFT (0x3 << 0)
+#define ACCDET_IVAL_SAM_IN_ADDR \
+ MT6359_ACCDET_CON16
+#define ACCDET_IVAL_SAM_IN_SFT 2
+#define ACCDET_IVAL_SAM_IN_MASK 0x3
+#define ACCDET_IVAL_SAM_IN_MASK_SFT (0x3 << 2)
+#define ACCDET_IVAL_MEM_IN_ADDR \
+ MT6359_ACCDET_CON16
+#define ACCDET_IVAL_MEM_IN_SFT 4
+#define ACCDET_IVAL_MEM_IN_MASK 0x3
+#define ACCDET_IVAL_MEM_IN_MASK_SFT (0x3 << 4)
+#define ACCDET_EINT_IVAL_CUR_IN_ADDR \
+ MT6359_ACCDET_CON16
+#define ACCDET_EINT_IVAL_CUR_IN_SFT 6
+#define ACCDET_EINT_IVAL_CUR_IN_MASK 0x3
+#define ACCDET_EINT_IVAL_CUR_IN_MASK_SFT (0x3 << 6)
+#define ACCDET_EINT_IVAL_SAM_IN_ADDR \
+ MT6359_ACCDET_CON16
+#define ACCDET_EINT_IVAL_SAM_IN_SFT 8
+#define ACCDET_EINT_IVAL_SAM_IN_MASK 0x3
+#define ACCDET_EINT_IVAL_SAM_IN_MASK_SFT (0x3 << 8)
+#define ACCDET_EINT_IVAL_MEM_IN_ADDR \
+ MT6359_ACCDET_CON16
+#define ACCDET_EINT_IVAL_MEM_IN_SFT 10
+#define ACCDET_EINT_IVAL_MEM_IN_MASK 0x3
+#define ACCDET_EINT_IVAL_MEM_IN_MASK_SFT (0x3 << 10)
+#define ACCDET_IVAL_SEL_ADDR \
+ MT6359_ACCDET_CON16
+#define ACCDET_IVAL_SEL_SFT 12
+#define ACCDET_IVAL_SEL_MASK 0x1
+#define ACCDET_IVAL_SEL_MASK_SFT (0x1 << 12)
+#define ACCDET_EINT_IVAL_SEL_ADDR \
+ MT6359_ACCDET_CON16
+#define ACCDET_EINT_IVAL_SEL_SFT 13
+#define ACCDET_EINT_IVAL_SEL_MASK 0x1
+#define ACCDET_EINT_IVAL_SEL_MASK_SFT (0x1 << 13)
+#define ACCDET_EINT_INVERTER_IVAL_CUR_IN_ADDR \
+ MT6359_ACCDET_CON17
+#define ACCDET_EINT_INVERTER_IVAL_CUR_IN_SFT 0
+#define ACCDET_EINT_INVERTER_IVAL_CUR_IN_MASK 0x1
+#define ACCDET_EINT_INVERTER_IVAL_CUR_IN_MASK_SFT (0x1 << 0)
+#define ACCDET_EINT_INVERTER_IVAL_SAM_IN_ADDR \
+ MT6359_ACCDET_CON17
+#define ACCDET_EINT_INVERTER_IVAL_SAM_IN_SFT 1
+#define ACCDET_EINT_INVERTER_IVAL_SAM_IN_MASK 0x1
+#define ACCDET_EINT_INVERTER_IVAL_SAM_IN_MASK_SFT (0x1 << 1)
+#define ACCDET_EINT_INVERTER_IVAL_MEM_IN_ADDR \
+ MT6359_ACCDET_CON17
+#define ACCDET_EINT_INVERTER_IVAL_MEM_IN_SFT 2
+#define ACCDET_EINT_INVERTER_IVAL_MEM_IN_MASK 0x1
+#define ACCDET_EINT_INVERTER_IVAL_MEM_IN_MASK_SFT (0x1 << 2)
+#define ACCDET_EINT_INVERTER_IVAL_SEL_ADDR \
+ MT6359_ACCDET_CON17
+#define ACCDET_EINT_INVERTER_IVAL_SEL_SFT 3
+#define ACCDET_EINT_INVERTER_IVAL_SEL_MASK 0x1
+#define ACCDET_EINT_INVERTER_IVAL_SEL_MASK_SFT (0x1 << 3)
+#define ACCDET_IRQ_ADDR \
+ MT6359_ACCDET_CON18
+#define ACCDET_IRQ_SFT 0
+#define ACCDET_IRQ_MASK 0x1
+#define ACCDET_IRQ_MASK_SFT (0x1 << 0)
+#define ACCDET_EINT0_IRQ_ADDR \
+ MT6359_ACCDET_CON18
+#define ACCDET_EINT0_IRQ_SFT 2
+#define ACCDET_EINT0_IRQ_MASK 0x1
+#define ACCDET_EINT0_IRQ_MASK_SFT (0x1 << 2)
+#define ACCDET_EINT1_IRQ_ADDR \
+ MT6359_ACCDET_CON18
+#define ACCDET_EINT1_IRQ_SFT 3
+#define ACCDET_EINT1_IRQ_MASK 0x1
+#define ACCDET_EINT1_IRQ_MASK_SFT (0x1 << 3)
+#define ACCDET_EINT_IN_INVERSE_ADDR \
+ MT6359_ACCDET_CON18
+#define ACCDET_EINT_IN_INVERSE_SFT 4
+#define ACCDET_EINT_IN_INVERSE_MASK 0x1
+#define ACCDET_EINT_IN_INVERSE_MASK_SFT (0x1 << 4)
+#define ACCDET_IRQ_CLR_ADDR \
+ MT6359_ACCDET_CON18
+#define ACCDET_IRQ_CLR_SFT 8
+#define ACCDET_IRQ_CLR_MASK 0x1
+#define ACCDET_IRQ_CLR_MASK_SFT (0x1 << 8)
+#define ACCDET_EINT0_IRQ_CLR_ADDR \
+ MT6359_ACCDET_CON18
+#define ACCDET_EINT0_IRQ_CLR_SFT 10
+#define ACCDET_EINT0_IRQ_CLR_MASK 0x1
+#define ACCDET_EINT0_IRQ_CLR_MASK_SFT (0x1 << 10)
+#define ACCDET_EINT1_IRQ_CLR_ADDR \
+ MT6359_ACCDET_CON18
+#define ACCDET_EINT1_IRQ_CLR_SFT 11
+#define ACCDET_EINT1_IRQ_CLR_MASK 0x1
+#define ACCDET_EINT1_IRQ_CLR_MASK_SFT (0x1 << 11)
+#define ACCDET_EINT_M_PLUG_IN_NUM_ADDR \
+ MT6359_ACCDET_CON18
+#define ACCDET_EINT_M_PLUG_IN_NUM_SFT 12
+#define ACCDET_EINT_M_PLUG_IN_NUM_MASK 0x7
+#define ACCDET_EINT_M_PLUG_IN_NUM_MASK_SFT (0x7 << 12)
+#define ACCDET_DA_STABLE_ADDR \
+ MT6359_ACCDET_CON19
+#define ACCDET_DA_STABLE_SFT 0
+#define ACCDET_DA_STABLE_MASK 0x1
+#define ACCDET_DA_STABLE_MASK_SFT (0x1 << 0)
+#define ACCDET_EINT0_EN_STABLE_ADDR \
+ MT6359_ACCDET_CON19
+#define ACCDET_EINT0_EN_STABLE_SFT 1
+#define ACCDET_EINT0_EN_STABLE_MASK 0x1
+#define ACCDET_EINT0_EN_STABLE_MASK_SFT (0x1 << 1)
+#define ACCDET_EINT0_CMPEN_STABLE_ADDR \
+ MT6359_ACCDET_CON19
+#define ACCDET_EINT0_CMPEN_STABLE_SFT 2
+#define ACCDET_EINT0_CMPEN_STABLE_MASK 0x1
+#define ACCDET_EINT0_CMPEN_STABLE_MASK_SFT (0x1 << 2)
+#define ACCDET_EINT0_CMPMEN_STABLE_ADDR \
+ MT6359_ACCDET_CON19
+#define ACCDET_EINT0_CMPMEN_STABLE_SFT 3
+#define ACCDET_EINT0_CMPMEN_STABLE_MASK 0x1
+#define ACCDET_EINT0_CMPMEN_STABLE_MASK_SFT (0x1 << 3)
+#define ACCDET_EINT0_CTURBO_STABLE_ADDR \
+ MT6359_ACCDET_CON19
+#define ACCDET_EINT0_CTURBO_STABLE_SFT 4
+#define ACCDET_EINT0_CTURBO_STABLE_MASK 0x1
+#define ACCDET_EINT0_CTURBO_STABLE_MASK_SFT (0x1 << 4)
+#define ACCDET_EINT0_CEN_STABLE_ADDR \
+ MT6359_ACCDET_CON19
+#define ACCDET_EINT0_CEN_STABLE_SFT 5
+#define ACCDET_EINT0_CEN_STABLE_MASK 0x1
+#define ACCDET_EINT0_CEN_STABLE_MASK_SFT (0x1 << 5)
+#define ACCDET_EINT1_EN_STABLE_ADDR \
+ MT6359_ACCDET_CON19
+#define ACCDET_EINT1_EN_STABLE_SFT 6
+#define ACCDET_EINT1_EN_STABLE_MASK 0x1
+#define ACCDET_EINT1_EN_STABLE_MASK_SFT (0x1 << 6)
+#define ACCDET_EINT1_CMPEN_STABLE_ADDR \
+ MT6359_ACCDET_CON19
+#define ACCDET_EINT1_CMPEN_STABLE_SFT 7
+#define ACCDET_EINT1_CMPEN_STABLE_MASK 0x1
+#define ACCDET_EINT1_CMPEN_STABLE_MASK_SFT (0x1 << 7)
+#define ACCDET_EINT1_CMPMEN_STABLE_ADDR \
+ MT6359_ACCDET_CON19
+#define ACCDET_EINT1_CMPMEN_STABLE_SFT 8
+#define ACCDET_EINT1_CMPMEN_STABLE_MASK 0x1
+#define ACCDET_EINT1_CMPMEN_STABLE_MASK_SFT (0x1 << 8)
+#define ACCDET_EINT1_CTURBO_STABLE_ADDR \
+ MT6359_ACCDET_CON19
+#define ACCDET_EINT1_CTURBO_STABLE_SFT 9
+#define ACCDET_EINT1_CTURBO_STABLE_MASK 0x1
+#define ACCDET_EINT1_CTURBO_STABLE_MASK_SFT (0x1 << 9)
+#define ACCDET_EINT1_CEN_STABLE_ADDR \
+ MT6359_ACCDET_CON19
+#define ACCDET_EINT1_CEN_STABLE_SFT 10
+#define ACCDET_EINT1_CEN_STABLE_MASK 0x1
+#define ACCDET_EINT1_CEN_STABLE_MASK_SFT (0x1 << 10)
+#define ACCDET_HWMODE_EN_ADDR \
+ MT6359_ACCDET_CON20
+#define ACCDET_HWMODE_EN_SFT 0
+#define ACCDET_HWMODE_EN_MASK 0x1
+#define ACCDET_HWMODE_EN_MASK_SFT (0x1 << 0)
+#define ACCDET_HWMODE_SEL_ADDR \
+ MT6359_ACCDET_CON20
+#define ACCDET_HWMODE_SEL_SFT 1
+#define ACCDET_HWMODE_SEL_MASK 0x3
+#define ACCDET_HWMODE_SEL_MASK_SFT (0x3 << 1)
+#define ACCDET_PLUG_OUT_DETECT_ADDR \
+ MT6359_ACCDET_CON20
+#define ACCDET_PLUG_OUT_DETECT_SFT 3
+#define ACCDET_PLUG_OUT_DETECT_MASK 0x1
+#define ACCDET_PLUG_OUT_DETECT_MASK_SFT (0x1 << 3)
+#define ACCDET_EINT0_REVERSE_ADDR \
+ MT6359_ACCDET_CON20
+#define ACCDET_EINT0_REVERSE_SFT 4
+#define ACCDET_EINT0_REVERSE_MASK 0x1
+#define ACCDET_EINT0_REVERSE_MASK_SFT (0x1 << 4)
+#define ACCDET_EINT1_REVERSE_ADDR \
+ MT6359_ACCDET_CON20
+#define ACCDET_EINT1_REVERSE_SFT 5
+#define ACCDET_EINT1_REVERSE_MASK 0x1
+#define ACCDET_EINT1_REVERSE_MASK_SFT (0x1 << 5)
+#define ACCDET_EINT_HWMODE_EN_ADDR \
+ MT6359_ACCDET_CON20
+#define ACCDET_EINT_HWMODE_EN_SFT 8
+#define ACCDET_EINT_HWMODE_EN_MASK 0x1
+#define ACCDET_EINT_HWMODE_EN_MASK_SFT (0x1 << 8)
+#define ACCDET_EINT_PLUG_OUT_BYPASS_DEB_ADDR \
+ MT6359_ACCDET_CON20
+#define ACCDET_EINT_PLUG_OUT_BYPASS_DEB_SFT 9
+#define ACCDET_EINT_PLUG_OUT_BYPASS_DEB_MASK 0x1
+#define ACCDET_EINT_PLUG_OUT_BYPASS_DEB_MASK_SFT (0x1 << 9)
+#define ACCDET_EINT_M_PLUG_IN_EN_ADDR \
+ MT6359_ACCDET_CON20
+#define ACCDET_EINT_M_PLUG_IN_EN_SFT 10
+#define ACCDET_EINT_M_PLUG_IN_EN_MASK 0x1
+#define ACCDET_EINT_M_PLUG_IN_EN_MASK_SFT (0x1 << 10)
+#define ACCDET_EINT_M_HWMODE_EN_ADDR \
+ MT6359_ACCDET_CON20
+#define ACCDET_EINT_M_HWMODE_EN_SFT 11
+#define ACCDET_EINT_M_HWMODE_EN_MASK 0x1
+#define ACCDET_EINT_M_HWMODE_EN_MASK_SFT (0x1 << 11)
+#define ACCDET_TEST_CMPEN_ADDR \
+ MT6359_ACCDET_CON21
+#define ACCDET_TEST_CMPEN_SFT 0
+#define ACCDET_TEST_CMPEN_MASK 0x1
+#define ACCDET_TEST_CMPEN_MASK_SFT (0x1 << 0)
+#define ACCDET_TEST_VTHEN_ADDR \
+ MT6359_ACCDET_CON21
+#define ACCDET_TEST_VTHEN_SFT 1
+#define ACCDET_TEST_VTHEN_MASK 0x1
+#define ACCDET_TEST_VTHEN_MASK_SFT (0x1 << 1)
+#define ACCDET_TEST_MBIASEN_ADDR \
+ MT6359_ACCDET_CON21
+#define ACCDET_TEST_MBIASEN_SFT 2
+#define ACCDET_TEST_MBIASEN_MASK 0x1
+#define ACCDET_TEST_MBIASEN_MASK_SFT (0x1 << 2)
+#define ACCDET_EINT_TEST_EN_ADDR \
+ MT6359_ACCDET_CON21
+#define ACCDET_EINT_TEST_EN_SFT 3
+#define ACCDET_EINT_TEST_EN_MASK 0x1
+#define ACCDET_EINT_TEST_EN_MASK_SFT (0x1 << 3)
+#define ACCDET_EINT_TEST_INVEN_ADDR \
+ MT6359_ACCDET_CON21
+#define ACCDET_EINT_TEST_INVEN_SFT 4
+#define ACCDET_EINT_TEST_INVEN_MASK 0x1
+#define ACCDET_EINT_TEST_INVEN_MASK_SFT (0x1 << 4)
+#define ACCDET_EINT_TEST_CMPEN_ADDR \
+ MT6359_ACCDET_CON21
+#define ACCDET_EINT_TEST_CMPEN_SFT 5
+#define ACCDET_EINT_TEST_CMPEN_MASK 0x1
+#define ACCDET_EINT_TEST_CMPEN_MASK_SFT (0x1 << 5)
+#define ACCDET_EINT_TEST_CMPMEN_ADDR \
+ MT6359_ACCDET_CON21
+#define ACCDET_EINT_TEST_CMPMEN_SFT 6
+#define ACCDET_EINT_TEST_CMPMEN_MASK 0x1
+#define ACCDET_EINT_TEST_CMPMEN_MASK_SFT (0x1 << 6)
+#define ACCDET_EINT_TEST_CTURBO_ADDR \
+ MT6359_ACCDET_CON21
+#define ACCDET_EINT_TEST_CTURBO_SFT 7
+#define ACCDET_EINT_TEST_CTURBO_MASK 0x1
+#define ACCDET_EINT_TEST_CTURBO_MASK_SFT (0x1 << 7)
+#define ACCDET_EINT_TEST_CEN_ADDR \
+ MT6359_ACCDET_CON21
+#define ACCDET_EINT_TEST_CEN_SFT 8
+#define ACCDET_EINT_TEST_CEN_MASK 0x1
+#define ACCDET_EINT_TEST_CEN_MASK_SFT (0x1 << 8)
+#define ACCDET_TEST_B_ADDR \
+ MT6359_ACCDET_CON21
+#define ACCDET_TEST_B_SFT 9
+#define ACCDET_TEST_B_MASK 0x1
+#define ACCDET_TEST_B_MASK_SFT (0x1 << 9)
+#define ACCDET_TEST_A_ADDR \
+ MT6359_ACCDET_CON21
+#define ACCDET_TEST_A_SFT 10
+#define ACCDET_TEST_A_MASK 0x1
+#define ACCDET_TEST_A_MASK_SFT (0x1 << 10)
+#define ACCDET_EINT_TEST_CMPOUT_ADDR \
+ MT6359_ACCDET_CON21
+#define ACCDET_EINT_TEST_CMPOUT_SFT 11
+#define ACCDET_EINT_TEST_CMPOUT_MASK 0x1
+#define ACCDET_EINT_TEST_CMPOUT_MASK_SFT (0x1 << 11)
+#define ACCDET_EINT_TEST_CMPMOUT_ADDR \
+ MT6359_ACCDET_CON21
+#define ACCDET_EINT_TEST_CMPMOUT_SFT 12
+#define ACCDET_EINT_TEST_CMPMOUT_MASK 0x1
+#define ACCDET_EINT_TEST_CMPMOUT_MASK_SFT (0x1 << 12)
+#define ACCDET_EINT_TEST_INVOUT_ADDR \
+ MT6359_ACCDET_CON21
+#define ACCDET_EINT_TEST_INVOUT_SFT 13
+#define ACCDET_EINT_TEST_INVOUT_MASK 0x1
+#define ACCDET_EINT_TEST_INVOUT_MASK_SFT (0x1 << 13)
+#define ACCDET_CMPEN_SEL_ADDR \
+ MT6359_ACCDET_CON22
+#define ACCDET_CMPEN_SEL_SFT 0
+#define ACCDET_CMPEN_SEL_MASK 0x1
+#define ACCDET_CMPEN_SEL_MASK_SFT (0x1 << 0)
+#define ACCDET_VTHEN_SEL_ADDR \
+ MT6359_ACCDET_CON22
+#define ACCDET_VTHEN_SEL_SFT 1
+#define ACCDET_VTHEN_SEL_MASK 0x1
+#define ACCDET_VTHEN_SEL_MASK_SFT (0x1 << 1)
+#define ACCDET_MBIASEN_SEL_ADDR \
+ MT6359_ACCDET_CON22
+#define ACCDET_MBIASEN_SEL_SFT 2
+#define ACCDET_MBIASEN_SEL_MASK 0x1
+#define ACCDET_MBIASEN_SEL_MASK_SFT (0x1 << 2)
+#define ACCDET_EINT_EN_SEL_ADDR \
+ MT6359_ACCDET_CON22
+#define ACCDET_EINT_EN_SEL_SFT 3
+#define ACCDET_EINT_EN_SEL_MASK 0x1
+#define ACCDET_EINT_EN_SEL_MASK_SFT (0x1 << 3)
+#define ACCDET_EINT_INVEN_SEL_ADDR \
+ MT6359_ACCDET_CON22
+#define ACCDET_EINT_INVEN_SEL_SFT 4
+#define ACCDET_EINT_INVEN_SEL_MASK 0x1
+#define ACCDET_EINT_INVEN_SEL_MASK_SFT (0x1 << 4)
+#define ACCDET_EINT_CMPEN_SEL_ADDR \
+ MT6359_ACCDET_CON22
+#define ACCDET_EINT_CMPEN_SEL_SFT 5
+#define ACCDET_EINT_CMPEN_SEL_MASK 0x1
+#define ACCDET_EINT_CMPEN_SEL_MASK_SFT (0x1 << 5)
+#define ACCDET_EINT_CMPMEN_SEL_ADDR \
+ MT6359_ACCDET_CON22
+#define ACCDET_EINT_CMPMEN_SEL_SFT 6
+#define ACCDET_EINT_CMPMEN_SEL_MASK 0x1
+#define ACCDET_EINT_CMPMEN_SEL_MASK_SFT (0x1 << 6)
+#define ACCDET_EINT_CTURBO_SEL_ADDR \
+ MT6359_ACCDET_CON22
+#define ACCDET_EINT_CTURBO_SEL_SFT 7
+#define ACCDET_EINT_CTURBO_SEL_MASK 0x1
+#define ACCDET_EINT_CTURBO_SEL_MASK_SFT (0x1 << 7)
+#define ACCDET_B_SEL_ADDR \
+ MT6359_ACCDET_CON22
+#define ACCDET_B_SEL_SFT 9
+#define ACCDET_B_SEL_MASK 0x1
+#define ACCDET_B_SEL_MASK_SFT (0x1 << 9)
+#define ACCDET_A_SEL_ADDR \
+ MT6359_ACCDET_CON22
+#define ACCDET_A_SEL_SFT 10
+#define ACCDET_A_SEL_MASK 0x1
+#define ACCDET_A_SEL_MASK_SFT (0x1 << 10)
+#define ACCDET_EINT_CMPOUT_SEL_ADDR \
+ MT6359_ACCDET_CON22
+#define ACCDET_EINT_CMPOUT_SEL_SFT 11
+#define ACCDET_EINT_CMPOUT_SEL_MASK 0x1
+#define ACCDET_EINT_CMPOUT_SEL_MASK_SFT (0x1 << 11)
+#define ACCDET_EINT_CMPMOUT_SEL_ADDR \
+ MT6359_ACCDET_CON22
+#define ACCDET_EINT_CMPMOUT_SEL_SFT 12
+#define ACCDET_EINT_CMPMOUT_SEL_MASK 0x1
+#define ACCDET_EINT_CMPMOUT_SEL_MASK_SFT (0x1 << 12)
+#define ACCDET_EINT_INVOUT_SEL_ADDR \
+ MT6359_ACCDET_CON22
+#define ACCDET_EINT_INVOUT_SEL_SFT 13
+#define ACCDET_EINT_INVOUT_SEL_MASK 0x1
+#define ACCDET_EINT_INVOUT_SEL_MASK_SFT (0x1 << 13)
+#define ACCDET_CMPEN_SW_ADDR \
+ MT6359_ACCDET_CON23
+#define ACCDET_CMPEN_SW_SFT 0
+#define ACCDET_CMPEN_SW_MASK 0x1
+#define ACCDET_CMPEN_SW_MASK_SFT (0x1 << 0)
+#define ACCDET_VTHEN_SW_ADDR \
+ MT6359_ACCDET_CON23
+#define ACCDET_VTHEN_SW_SFT 1
+#define ACCDET_VTHEN_SW_MASK 0x1
+#define ACCDET_VTHEN_SW_MASK_SFT (0x1 << 1)
+#define ACCDET_MBIASEN_SW_ADDR \
+ MT6359_ACCDET_CON23
+#define ACCDET_MBIASEN_SW_SFT 2
+#define ACCDET_MBIASEN_SW_MASK 0x1
+#define ACCDET_MBIASEN_SW_MASK_SFT (0x1 << 2)
+#define ACCDET_EINT0_EN_SW_ADDR \
+ MT6359_ACCDET_CON23
+#define ACCDET_EINT0_EN_SW_SFT 3
+#define ACCDET_EINT0_EN_SW_MASK 0x1
+#define ACCDET_EINT0_EN_SW_MASK_SFT (0x1 << 3)
+#define ACCDET_EINT0_INVEN_SW_ADDR \
+ MT6359_ACCDET_CON23
+#define ACCDET_EINT0_INVEN_SW_SFT 4
+#define ACCDET_EINT0_INVEN_SW_MASK 0x1
+#define ACCDET_EINT0_INVEN_SW_MASK_SFT (0x1 << 4)
+#define ACCDET_EINT0_CMPEN_SW_ADDR \
+ MT6359_ACCDET_CON23
+#define ACCDET_EINT0_CMPEN_SW_SFT 5
+#define ACCDET_EINT0_CMPEN_SW_MASK 0x1
+#define ACCDET_EINT0_CMPEN_SW_MASK_SFT (0x1 << 5)
+#define ACCDET_EINT0_CMPMEN_SW_ADDR \
+ MT6359_ACCDET_CON23
+#define ACCDET_EINT0_CMPMEN_SW_SFT 6
+#define ACCDET_EINT0_CMPMEN_SW_MASK 0x1
+#define ACCDET_EINT0_CMPMEN_SW_MASK_SFT (0x1 << 6)
+#define ACCDET_EINT0_CTURBO_SW_ADDR \
+ MT6359_ACCDET_CON23
+#define ACCDET_EINT0_CTURBO_SW_SFT 7
+#define ACCDET_EINT0_CTURBO_SW_MASK 0x1
+#define ACCDET_EINT0_CTURBO_SW_MASK_SFT (0x1 << 7)
+#define ACCDET_EINT1_EN_SW_ADDR \
+ MT6359_ACCDET_CON23
+#define ACCDET_EINT1_EN_SW_SFT 8
+#define ACCDET_EINT1_EN_SW_MASK 0x1
+#define ACCDET_EINT1_EN_SW_MASK_SFT (0x1 << 8)
+#define ACCDET_EINT1_INVEN_SW_ADDR \
+ MT6359_ACCDET_CON23
+#define ACCDET_EINT1_INVEN_SW_SFT 9
+#define ACCDET_EINT1_INVEN_SW_MASK 0x1
+#define ACCDET_EINT1_INVEN_SW_MASK_SFT (0x1 << 9)
+#define ACCDET_EINT1_CMPEN_SW_ADDR \
+ MT6359_ACCDET_CON23
+#define ACCDET_EINT1_CMPEN_SW_SFT 10
+#define ACCDET_EINT1_CMPEN_SW_MASK 0x1
+#define ACCDET_EINT1_CMPEN_SW_MASK_SFT (0x1 << 10)
+#define ACCDET_EINT1_CMPMEN_SW_ADDR \
+ MT6359_ACCDET_CON23
+#define ACCDET_EINT1_CMPMEN_SW_SFT 11
+#define ACCDET_EINT1_CMPMEN_SW_MASK 0x1
+#define ACCDET_EINT1_CMPMEN_SW_MASK_SFT (0x1 << 11)
+#define ACCDET_EINT1_CTURBO_SW_ADDR \
+ MT6359_ACCDET_CON23
+#define ACCDET_EINT1_CTURBO_SW_SFT 12
+#define ACCDET_EINT1_CTURBO_SW_MASK 0x1
+#define ACCDET_EINT1_CTURBO_SW_MASK_SFT (0x1 << 12)
+#define ACCDET_B_SW_ADDR \
+ MT6359_ACCDET_CON24
+#define ACCDET_B_SW_SFT 0
+#define ACCDET_B_SW_MASK 0x1
+#define ACCDET_B_SW_MASK_SFT (0x1 << 0)
+#define ACCDET_A_SW_ADDR \
+ MT6359_ACCDET_CON24
+#define ACCDET_A_SW_SFT 1
+#define ACCDET_A_SW_MASK 0x1
+#define ACCDET_A_SW_MASK_SFT (0x1 << 1)
+#define ACCDET_EINT0_CMPOUT_SW_ADDR \
+ MT6359_ACCDET_CON24
+#define ACCDET_EINT0_CMPOUT_SW_SFT 2
+#define ACCDET_EINT0_CMPOUT_SW_MASK 0x1
+#define ACCDET_EINT0_CMPOUT_SW_MASK_SFT (0x1 << 2)
+#define ACCDET_EINT0_CMPMOUT_SW_ADDR \
+ MT6359_ACCDET_CON24
+#define ACCDET_EINT0_CMPMOUT_SW_SFT 3
+#define ACCDET_EINT0_CMPMOUT_SW_MASK 0x1
+#define ACCDET_EINT0_CMPMOUT_SW_MASK_SFT (0x1 << 3)
+#define ACCDET_EINT0_INVOUT_SW_ADDR \
+ MT6359_ACCDET_CON24
+#define ACCDET_EINT0_INVOUT_SW_SFT 4
+#define ACCDET_EINT0_INVOUT_SW_MASK 0x1
+#define ACCDET_EINT0_INVOUT_SW_MASK_SFT (0x1 << 4)
+#define ACCDET_EINT1_CMPOUT_SW_ADDR \
+ MT6359_ACCDET_CON24
+#define ACCDET_EINT1_CMPOUT_SW_SFT 5
+#define ACCDET_EINT1_CMPOUT_SW_MASK 0x1
+#define ACCDET_EINT1_CMPOUT_SW_MASK_SFT (0x1 << 5)
+#define ACCDET_EINT1_CMPMOUT_SW_ADDR \
+ MT6359_ACCDET_CON24
+#define ACCDET_EINT1_CMPMOUT_SW_SFT 6
+#define ACCDET_EINT1_CMPMOUT_SW_MASK 0x1
+#define ACCDET_EINT1_CMPMOUT_SW_MASK_SFT (0x1 << 6)
+#define ACCDET_EINT1_INVOUT_SW_ADDR \
+ MT6359_ACCDET_CON24
+#define ACCDET_EINT1_INVOUT_SW_SFT 7
+#define ACCDET_EINT1_INVOUT_SW_MASK 0x1
+#define ACCDET_EINT1_INVOUT_SW_MASK_SFT (0x1 << 7)
+#define AD_AUDACCDETCMPOB_ADDR \
+ MT6359_ACCDET_CON25
+#define AD_AUDACCDETCMPOB_SFT 0
+#define AD_AUDACCDETCMPOB_MASK 0x1
+#define AD_AUDACCDETCMPOB_MASK_SFT (0x1 << 0)
+#define AD_AUDACCDETCMPOA_ADDR \
+ MT6359_ACCDET_CON25
+#define AD_AUDACCDETCMPOA_SFT 1
+#define AD_AUDACCDETCMPOA_MASK 0x1
+#define AD_AUDACCDETCMPOA_MASK_SFT (0x1 << 1)
+#define ACCDET_CUR_IN_ADDR \
+ MT6359_ACCDET_CON25
+#define ACCDET_CUR_IN_SFT 2
+#define ACCDET_CUR_IN_MASK 0x3
+#define ACCDET_CUR_IN_MASK_SFT (0x3 << 2)
+#define ACCDET_SAM_IN_ADDR \
+ MT6359_ACCDET_CON25
+#define ACCDET_SAM_IN_SFT 4
+#define ACCDET_SAM_IN_MASK 0x3
+#define ACCDET_SAM_IN_MASK_SFT (0x3 << 4)
+#define ACCDET_MEM_IN_ADDR \
+ MT6359_ACCDET_CON25
+#define ACCDET_MEM_IN_SFT 6
+#define ACCDET_MEM_IN_MASK 0x3
+#define ACCDET_MEM_IN_MASK_SFT (0x3 << 6)
+#define ACCDET_STATE_ADDR \
+ MT6359_ACCDET_CON25
+#define ACCDET_STATE_SFT 8
+#define ACCDET_STATE_MASK 0x7
+#define ACCDET_STATE_MASK_SFT (0x7 << 8)
+#define DA_AUDACCDETMBIASCLK_ADDR \
+ MT6359_ACCDET_CON25
+#define DA_AUDACCDETMBIASCLK_SFT 12
+#define DA_AUDACCDETMBIASCLK_MASK 0x1
+#define DA_AUDACCDETMBIASCLK_MASK_SFT (0x1 << 12)
+#define DA_AUDACCDETVTHCLK_ADDR \
+ MT6359_ACCDET_CON25
+#define DA_AUDACCDETVTHCLK_SFT 13
+#define DA_AUDACCDETVTHCLK_MASK 0x1
+#define DA_AUDACCDETVTHCLK_MASK_SFT (0x1 << 13)
+#define DA_AUDACCDETCMPCLK_ADDR \
+ MT6359_ACCDET_CON25
+#define DA_AUDACCDETCMPCLK_SFT 14
+#define DA_AUDACCDETCMPCLK_MASK 0x1
+#define DA_AUDACCDETCMPCLK_MASK_SFT (0x1 << 14)
+#define DA_AUDACCDETAUXADCSWCTRL_ADDR \
+ MT6359_ACCDET_CON25
+#define DA_AUDACCDETAUXADCSWCTRL_SFT 15
+#define DA_AUDACCDETAUXADCSWCTRL_MASK 0x1
+#define DA_AUDACCDETAUXADCSWCTRL_MASK_SFT (0x1 << 15)
+#define AD_EINT0CMPMOUT_ADDR \
+ MT6359_ACCDET_CON26
+#define AD_EINT0CMPMOUT_SFT 0
+#define AD_EINT0CMPMOUT_MASK 0x1
+#define AD_EINT0CMPMOUT_MASK_SFT (0x1 << 0)
+#define AD_EINT0CMPOUT_ADDR \
+ MT6359_ACCDET_CON26
+#define AD_EINT0CMPOUT_SFT 1
+#define AD_EINT0CMPOUT_MASK 0x1
+#define AD_EINT0CMPOUT_MASK_SFT (0x1 << 1)
+#define ACCDET_EINT0_CUR_IN_ADDR \
+ MT6359_ACCDET_CON26
+#define ACCDET_EINT0_CUR_IN_SFT 2
+#define ACCDET_EINT0_CUR_IN_MASK 0x3
+#define ACCDET_EINT0_CUR_IN_MASK_SFT (0x3 << 2)
+#define ACCDET_EINT0_SAM_IN_ADDR \
+ MT6359_ACCDET_CON26
+#define ACCDET_EINT0_SAM_IN_SFT 4
+#define ACCDET_EINT0_SAM_IN_MASK 0x3
+#define ACCDET_EINT0_SAM_IN_MASK_SFT (0x3 << 4)
+#define ACCDET_EINT0_MEM_IN_ADDR \
+ MT6359_ACCDET_CON26
+#define ACCDET_EINT0_MEM_IN_SFT 6
+#define ACCDET_EINT0_MEM_IN_MASK 0x3
+#define ACCDET_EINT0_MEM_IN_MASK_SFT (0x3 << 6)
+#define ACCDET_EINT0_STATE_ADDR \
+ MT6359_ACCDET_CON26
+#define ACCDET_EINT0_STATE_SFT 8
+#define ACCDET_EINT0_STATE_MASK 0x7
+#define ACCDET_EINT0_STATE_MASK_SFT (0x7 << 8)
+#define DA_EINT0CMPEN_ADDR \
+ MT6359_ACCDET_CON26
+#define DA_EINT0CMPEN_SFT 13
+#define DA_EINT0CMPEN_MASK 0x1
+#define DA_EINT0CMPEN_MASK_SFT (0x1 << 13)
+#define DA_EINT0CMPMEN_ADDR \
+ MT6359_ACCDET_CON26
+#define DA_EINT0CMPMEN_SFT 14
+#define DA_EINT0CMPMEN_MASK 0x1
+#define DA_EINT0CMPMEN_MASK_SFT (0x1 << 14)
+#define DA_EINT0CTURBO_ADDR \
+ MT6359_ACCDET_CON26
+#define DA_EINT0CTURBO_SFT 15
+#define DA_EINT0CTURBO_MASK 0x1
+#define DA_EINT0CTURBO_MASK_SFT (0x1 << 15)
+#define AD_EINT1CMPMOUT_ADDR \
+ MT6359_ACCDET_CON27
+#define AD_EINT1CMPMOUT_SFT 0
+#define AD_EINT1CMPMOUT_MASK 0x1
+#define AD_EINT1CMPMOUT_MASK_SFT (0x1 << 0)
+#define AD_EINT1CMPOUT_ADDR \
+ MT6359_ACCDET_CON27
+#define AD_EINT1CMPOUT_SFT 1
+#define AD_EINT1CMPOUT_MASK 0x1
+#define AD_EINT1CMPOUT_MASK_SFT (0x1 << 1)
+#define ACCDET_EINT1_CUR_IN_ADDR \
+ MT6359_ACCDET_CON27
+#define ACCDET_EINT1_CUR_IN_SFT 2
+#define ACCDET_EINT1_CUR_IN_MASK 0x3
+#define ACCDET_EINT1_CUR_IN_MASK_SFT (0x3 << 2)
+#define ACCDET_EINT1_SAM_IN_ADDR \
+ MT6359_ACCDET_CON27
+#define ACCDET_EINT1_SAM_IN_SFT 4
+#define ACCDET_EINT1_SAM_IN_MASK 0x3
+#define ACCDET_EINT1_SAM_IN_MASK_SFT (0x3 << 4)
+#define ACCDET_EINT1_MEM_IN_ADDR \
+ MT6359_ACCDET_CON27
+#define ACCDET_EINT1_MEM_IN_SFT 6
+#define ACCDET_EINT1_MEM_IN_MASK 0x3
+#define ACCDET_EINT1_MEM_IN_MASK_SFT (0x3 << 6)
+#define ACCDET_EINT1_STATE_ADDR \
+ MT6359_ACCDET_CON27
+#define ACCDET_EINT1_STATE_SFT 8
+#define ACCDET_EINT1_STATE_MASK 0x7
+#define ACCDET_EINT1_STATE_MASK_SFT (0x7 << 8)
+#define DA_EINT1CMPEN_ADDR \
+ MT6359_ACCDET_CON27
+#define DA_EINT1CMPEN_SFT 13
+#define DA_EINT1CMPEN_MASK 0x1
+#define DA_EINT1CMPEN_MASK_SFT (0x1 << 13)
+#define DA_EINT1CMPMEN_ADDR \
+ MT6359_ACCDET_CON27
+#define DA_EINT1CMPMEN_SFT 14
+#define DA_EINT1CMPMEN_MASK 0x1
+#define DA_EINT1CMPMEN_MASK_SFT (0x1 << 14)
+#define DA_EINT1CTURBO_ADDR \
+ MT6359_ACCDET_CON27
+#define DA_EINT1CTURBO_SFT 15
+#define DA_EINT1CTURBO_MASK 0x1
+#define DA_EINT1CTURBO_MASK_SFT (0x1 << 15)
+#define AD_EINT0INVOUT_ADDR \
+ MT6359_ACCDET_CON28
+#define AD_EINT0INVOUT_SFT 0
+#define AD_EINT0INVOUT_MASK 0x1
+#define AD_EINT0INVOUT_MASK_SFT (0x1 << 0)
+#define ACCDET_EINT0_INVERTER_CUR_IN_ADDR \
+ MT6359_ACCDET_CON28
+#define ACCDET_EINT0_INVERTER_CUR_IN_SFT 1
+#define ACCDET_EINT0_INVERTER_CUR_IN_MASK 0x1
+#define ACCDET_EINT0_INVERTER_CUR_IN_MASK_SFT (0x1 << 1)
+#define ACCDET_EINT0_INVERTER_SAM_IN_ADDR \
+ MT6359_ACCDET_CON28
+#define ACCDET_EINT0_INVERTER_SAM_IN_SFT 2
+#define ACCDET_EINT0_INVERTER_SAM_IN_MASK 0x1
+#define ACCDET_EINT0_INVERTER_SAM_IN_MASK_SFT (0x1 << 2)
+#define ACCDET_EINT0_INVERTER_MEM_IN_ADDR \
+ MT6359_ACCDET_CON28
+#define ACCDET_EINT0_INVERTER_MEM_IN_SFT 3
+#define ACCDET_EINT0_INVERTER_MEM_IN_MASK 0x1
+#define ACCDET_EINT0_INVERTER_MEM_IN_MASK_SFT (0x1 << 3)
+#define ACCDET_EINT0_INVERTER_STATE_ADDR \
+ MT6359_ACCDET_CON28
+#define ACCDET_EINT0_INVERTER_STATE_SFT 8
+#define ACCDET_EINT0_INVERTER_STATE_MASK 0x7
+#define ACCDET_EINT0_INVERTER_STATE_MASK_SFT (0x7 << 8)
+#define DA_EINT0EN_ADDR \
+ MT6359_ACCDET_CON28
+#define DA_EINT0EN_SFT 12
+#define DA_EINT0EN_MASK 0x1
+#define DA_EINT0EN_MASK_SFT (0x1 << 12)
+#define DA_EINT0INVEN_ADDR \
+ MT6359_ACCDET_CON28
+#define DA_EINT0INVEN_SFT 13
+#define DA_EINT0INVEN_MASK 0x1
+#define DA_EINT0INVEN_MASK_SFT (0x1 << 13)
+#define DA_EINT0CEN_ADDR \
+ MT6359_ACCDET_CON28
+#define DA_EINT0CEN_SFT 14
+#define DA_EINT0CEN_MASK 0x1
+#define DA_EINT0CEN_MASK_SFT (0x1 << 14)
+#define AD_EINT1INVOUT_ADDR \
+ MT6359_ACCDET_CON29
+#define AD_EINT1INVOUT_SFT 0
+#define AD_EINT1INVOUT_MASK 0x1
+#define AD_EINT1INVOUT_MASK_SFT (0x1 << 0)
+#define ACCDET_EINT1_INVERTER_CUR_IN_ADDR \
+ MT6359_ACCDET_CON29
+#define ACCDET_EINT1_INVERTER_CUR_IN_SFT 1
+#define ACCDET_EINT1_INVERTER_CUR_IN_MASK 0x1
+#define ACCDET_EINT1_INVERTER_CUR_IN_MASK_SFT (0x1 << 1)
+#define ACCDET_EINT1_INVERTER_SAM_IN_ADDR \
+ MT6359_ACCDET_CON29
+#define ACCDET_EINT1_INVERTER_SAM_IN_SFT 2
+#define ACCDET_EINT1_INVERTER_SAM_IN_MASK 0x1
+#define ACCDET_EINT1_INVERTER_SAM_IN_MASK_SFT (0x1 << 2)
+#define ACCDET_EINT1_INVERTER_MEM_IN_ADDR \
+ MT6359_ACCDET_CON29
+#define ACCDET_EINT1_INVERTER_MEM_IN_SFT 3
+#define ACCDET_EINT1_INVERTER_MEM_IN_MASK 0x1
+#define ACCDET_EINT1_INVERTER_MEM_IN_MASK_SFT (0x1 << 3)
+#define ACCDET_EINT1_INVERTER_STATE_ADDR \
+ MT6359_ACCDET_CON29
+#define ACCDET_EINT1_INVERTER_STATE_SFT 8
+#define ACCDET_EINT1_INVERTER_STATE_MASK 0x7
+#define ACCDET_EINT1_INVERTER_STATE_MASK_SFT (0x7 << 8)
+#define DA_EINT1EN_ADDR \
+ MT6359_ACCDET_CON29
+#define DA_EINT1EN_SFT 12
+#define DA_EINT1EN_MASK 0x1
+#define DA_EINT1EN_MASK_SFT (0x1 << 12)
+#define DA_EINT1INVEN_ADDR \
+ MT6359_ACCDET_CON29
+#define DA_EINT1INVEN_SFT 13
+#define DA_EINT1INVEN_MASK 0x1
+#define DA_EINT1INVEN_MASK_SFT (0x1 << 13)
+#define DA_EINT1CEN_ADDR \
+ MT6359_ACCDET_CON29
+#define DA_EINT1CEN_SFT 14
+#define DA_EINT1CEN_MASK 0x1
+#define DA_EINT1CEN_MASK_SFT (0x1 << 14)
+#define ACCDET_EN_ADDR \
+ MT6359_ACCDET_CON30
+#define ACCDET_EN_SFT 0
+#define ACCDET_EN_MASK 0x1
+#define ACCDET_EN_MASK_SFT (0x1 << 0)
+#define ACCDET_EINT0_EN_ADDR \
+ MT6359_ACCDET_CON30
+#define ACCDET_EINT0_EN_SFT 1
+#define ACCDET_EINT0_EN_MASK 0x1
+#define ACCDET_EINT0_EN_MASK_SFT (0x1 << 1)
+#define ACCDET_EINT1_EN_ADDR \
+ MT6359_ACCDET_CON30
+#define ACCDET_EINT1_EN_SFT 2
+#define ACCDET_EINT1_EN_MASK 0x1
+#define ACCDET_EINT1_EN_MASK_SFT (0x1 << 2)
+#define ACCDET_EINT0_M_EN_ADDR \
+ MT6359_ACCDET_CON30
+#define ACCDET_EINT0_M_EN_SFT 3
+#define ACCDET_EINT0_M_EN_MASK 0x1
+#define ACCDET_EINT0_M_EN_MASK_SFT (0x1 << 3)
+#define ACCDET_EINT0_DETECT_MOISTURE_ADDR \
+ MT6359_ACCDET_CON30
+#define ACCDET_EINT0_DETECT_MOISTURE_SFT 4
+#define ACCDET_EINT0_DETECT_MOISTURE_MASK 0x1
+#define ACCDET_EINT0_DETECT_MOISTURE_MASK_SFT (0x1 << 4)
+#define ACCDET_EINT0_PLUG_IN_ADDR \
+ MT6359_ACCDET_CON30
+#define ACCDET_EINT0_PLUG_IN_SFT 5
+#define ACCDET_EINT0_PLUG_IN_MASK 0x1
+#define ACCDET_EINT0_PLUG_IN_MASK_SFT (0x1 << 5)
+#define ACCDET_EINT0_M_PLUG_IN_ADDR \
+ MT6359_ACCDET_CON30
+#define ACCDET_EINT0_M_PLUG_IN_SFT 6
+#define ACCDET_EINT0_M_PLUG_IN_MASK 0x1
+#define ACCDET_EINT0_M_PLUG_IN_MASK_SFT (0x1 << 6)
+#define ACCDET_EINT1_M_EN_ADDR \
+ MT6359_ACCDET_CON30
+#define ACCDET_EINT1_M_EN_SFT 7
+#define ACCDET_EINT1_M_EN_MASK 0x1
+#define ACCDET_EINT1_M_EN_MASK_SFT (0x1 << 7)
+#define ACCDET_EINT1_DETECT_MOISTURE_ADDR \
+ MT6359_ACCDET_CON30
+#define ACCDET_EINT1_DETECT_MOISTURE_SFT 8
+#define ACCDET_EINT1_DETECT_MOISTURE_MASK 0x1
+#define ACCDET_EINT1_DETECT_MOISTURE_MASK_SFT (0x1 << 8)
+#define ACCDET_EINT1_PLUG_IN_ADDR \
+ MT6359_ACCDET_CON30
+#define ACCDET_EINT1_PLUG_IN_SFT 9
+#define ACCDET_EINT1_PLUG_IN_MASK 0x1
+#define ACCDET_EINT1_PLUG_IN_MASK_SFT (0x1 << 9)
+#define ACCDET_EINT1_M_PLUG_IN_ADDR \
+ MT6359_ACCDET_CON30
+#define ACCDET_EINT1_M_PLUG_IN_SFT 10
+#define ACCDET_EINT1_M_PLUG_IN_MASK 0x1
+#define ACCDET_EINT1_M_PLUG_IN_MASK_SFT (0x1 << 10)
+#define ACCDET_CUR_DEB_ADDR \
+ MT6359_ACCDET_CON31
+#define ACCDET_CUR_DEB_SFT 0
+#define ACCDET_CUR_DEB_MASK 0xFFFF
+#define ACCDET_CUR_DEB_MASK_SFT (0xFFFF << 0)
+#define ACCDET_EINT0_CUR_DEB_ADDR \
+ MT6359_ACCDET_CON32
+#define ACCDET_EINT0_CUR_DEB_SFT 0
+#define ACCDET_EINT0_CUR_DEB_MASK 0x7FFF
+#define ACCDET_EINT0_CUR_DEB_MASK_SFT (0x7FFF << 0)
+#define ACCDET_EINT1_CUR_DEB_ADDR \
+ MT6359_ACCDET_CON33
+#define ACCDET_EINT1_CUR_DEB_SFT 0
+#define ACCDET_EINT1_CUR_DEB_MASK 0x7FFF
+#define ACCDET_EINT1_CUR_DEB_MASK_SFT (0x7FFF << 0)
+#define ACCDET_EINT0_INVERTER_CUR_DEB_ADDR \
+ MT6359_ACCDET_CON34
+#define ACCDET_EINT0_INVERTER_CUR_DEB_SFT 0
+#define ACCDET_EINT0_INVERTER_CUR_DEB_MASK 0x7FFF
+#define ACCDET_EINT0_INVERTER_CUR_DEB_MASK_SFT (0x7FFF << 0)
+#define ACCDET_EINT1_INVERTER_CUR_DEB_ADDR \
+ MT6359_ACCDET_CON35
+#define ACCDET_EINT1_INVERTER_CUR_DEB_SFT 0
+#define ACCDET_EINT1_INVERTER_CUR_DEB_MASK 0x7FFF
+#define ACCDET_EINT1_INVERTER_CUR_DEB_MASK_SFT (0x7FFF << 0)
+#define AD_AUDACCDETCMPOB_MON_ADDR \
+ MT6359_ACCDET_CON36
+#define AD_AUDACCDETCMPOB_MON_SFT 0
+#define AD_AUDACCDETCMPOB_MON_MASK 0x1
+#define AD_AUDACCDETCMPOB_MON_MASK_SFT (0x1 << 0)
+#define AD_AUDACCDETCMPOA_MON_ADDR \
+ MT6359_ACCDET_CON36
+#define AD_AUDACCDETCMPOA_MON_SFT 1
+#define AD_AUDACCDETCMPOA_MON_MASK 0x1
+#define AD_AUDACCDETCMPOA_MON_MASK_SFT (0x1 << 1)
+#define AD_EINT0CMPMOUT_MON_ADDR \
+ MT6359_ACCDET_CON36
+#define AD_EINT0CMPMOUT_MON_SFT 2
+#define AD_EINT0CMPMOUT_MON_MASK 0x1
+#define AD_EINT0CMPMOUT_MON_MASK_SFT (0x1 << 2)
+#define AD_EINT0CMPOUT_MON_ADDR \
+ MT6359_ACCDET_CON36
+#define AD_EINT0CMPOUT_MON_SFT 3
+#define AD_EINT0CMPOUT_MON_MASK 0x1
+#define AD_EINT0CMPOUT_MON_MASK_SFT (0x1 << 3)
+#define AD_EINT0INVOUT_MON_ADDR \
+ MT6359_ACCDET_CON36
+#define AD_EINT0INVOUT_MON_SFT 4
+#define AD_EINT0INVOUT_MON_MASK 0x1
+#define AD_EINT0INVOUT_MON_MASK_SFT (0x1 << 4)
+#define AD_EINT1CMPMOUT_MON_ADDR \
+ MT6359_ACCDET_CON36
+#define AD_EINT1CMPMOUT_MON_SFT 5
+#define AD_EINT1CMPMOUT_MON_MASK 0x1
+#define AD_EINT1CMPMOUT_MON_MASK_SFT (0x1 << 5)
+#define AD_EINT1CMPOUT_MON_ADDR \
+ MT6359_ACCDET_CON36
+#define AD_EINT1CMPOUT_MON_SFT 6
+#define AD_EINT1CMPOUT_MON_MASK 0x1
+#define AD_EINT1CMPOUT_MON_MASK_SFT (0x1 << 6)
+#define AD_EINT1INVOUT_MON_ADDR \
+ MT6359_ACCDET_CON36
+#define AD_EINT1INVOUT_MON_SFT 7
+#define AD_EINT1INVOUT_MON_MASK 0x1
+#define AD_EINT1INVOUT_MON_MASK_SFT (0x1 << 7)
+#define DA_AUDACCDETCMPCLK_MON_ADDR \
+ MT6359_ACCDET_CON37
+#define DA_AUDACCDETCMPCLK_MON_SFT 0
+#define DA_AUDACCDETCMPCLK_MON_MASK 0x1
+#define DA_AUDACCDETCMPCLK_MON_MASK_SFT (0x1 << 0)
+#define DA_AUDACCDETVTHCLK_MON_ADDR \
+ MT6359_ACCDET_CON37
+#define DA_AUDACCDETVTHCLK_MON_SFT 1
+#define DA_AUDACCDETVTHCLK_MON_MASK 0x1
+#define DA_AUDACCDETVTHCLK_MON_MASK_SFT (0x1 << 1)
+#define DA_AUDACCDETMBIASCLK_MON_ADDR \
+ MT6359_ACCDET_CON37
+#define DA_AUDACCDETMBIASCLK_MON_SFT 2
+#define DA_AUDACCDETMBIASCLK_MON_MASK 0x1
+#define DA_AUDACCDETMBIASCLK_MON_MASK_SFT (0x1 << 2)
+#define DA_AUDACCDETAUXADCSWCTRL_MON_ADDR \
+ MT6359_ACCDET_CON37
+#define DA_AUDACCDETAUXADCSWCTRL_MON_SFT 3
+#define DA_AUDACCDETAUXADCSWCTRL_MON_MASK 0x1
+#define DA_AUDACCDETAUXADCSWCTRL_MON_MASK_SFT (0x1 << 3)
+#define DA_EINT0CTURBO_MON_ADDR \
+ MT6359_ACCDET_CON38
+#define DA_EINT0CTURBO_MON_SFT 0
+#define DA_EINT0CTURBO_MON_MASK 0x1
+#define DA_EINT0CTURBO_MON_MASK_SFT (0x1 << 0)
+#define DA_EINT0CMPMEN_MON_ADDR \
+ MT6359_ACCDET_CON38
+#define DA_EINT0CMPMEN_MON_SFT 1
+#define DA_EINT0CMPMEN_MON_MASK 0x1
+#define DA_EINT0CMPMEN_MON_MASK_SFT (0x1 << 1)
+#define DA_EINT0CMPEN_MON_ADDR \
+ MT6359_ACCDET_CON38
+#define DA_EINT0CMPEN_MON_SFT 2
+#define DA_EINT0CMPEN_MON_MASK 0x1
+#define DA_EINT0CMPEN_MON_MASK_SFT (0x1 << 2)
+#define DA_EINT0INVEN_MON_ADDR \
+ MT6359_ACCDET_CON38
+#define DA_EINT0INVEN_MON_SFT 3
+#define DA_EINT0INVEN_MON_MASK 0x1
+#define DA_EINT0INVEN_MON_MASK_SFT (0x1 << 3)
+#define DA_EINT0CEN_MON_ADDR \
+ MT6359_ACCDET_CON38
+#define DA_EINT0CEN_MON_SFT 4
+#define DA_EINT0CEN_MON_MASK 0x1
+#define DA_EINT0CEN_MON_MASK_SFT (0x1 << 4)
+#define DA_EINT0EN_MON_ADDR \
+ MT6359_ACCDET_CON38
+#define DA_EINT0EN_MON_SFT 5
+#define DA_EINT0EN_MON_MASK 0x1
+#define DA_EINT0EN_MON_MASK_SFT (0x1 << 5)
+#define DA_EINT1CTURBO_MON_ADDR \
+ MT6359_ACCDET_CON38
+#define DA_EINT1CTURBO_MON_SFT 8
+#define DA_EINT1CTURBO_MON_MASK 0x1
+#define DA_EINT1CTURBO_MON_MASK_SFT (0x1 << 8)
+#define DA_EINT1CMPMEN_MON_ADDR \
+ MT6359_ACCDET_CON38
+#define DA_EINT1CMPMEN_MON_SFT 9
+#define DA_EINT1CMPMEN_MON_MASK 0x1
+#define DA_EINT1CMPMEN_MON_MASK_SFT (0x1 << 9)
+#define DA_EINT1CMPEN_MON_ADDR \
+ MT6359_ACCDET_CON38
+#define DA_EINT1CMPEN_MON_SFT 10
+#define DA_EINT1CMPEN_MON_MASK 0x1
+#define DA_EINT1CMPEN_MON_MASK_SFT (0x1 << 10)
+#define DA_EINT1INVEN_MON_ADDR \
+ MT6359_ACCDET_CON38
+#define DA_EINT1INVEN_MON_SFT 11
+#define DA_EINT1INVEN_MON_MASK 0x1
+#define DA_EINT1INVEN_MON_MASK_SFT (0x1 << 11)
+#define DA_EINT1CEN_MON_ADDR \
+ MT6359_ACCDET_CON38
+#define DA_EINT1CEN_MON_SFT 12
+#define DA_EINT1CEN_MON_MASK 0x1
+#define DA_EINT1CEN_MON_MASK_SFT (0x1 << 12)
+#define DA_EINT1EN_MON_ADDR \
+ MT6359_ACCDET_CON38
+#define DA_EINT1EN_MON_SFT 13
+#define DA_EINT1EN_MON_MASK 0x1
+#define DA_EINT1EN_MON_MASK_SFT (0x1 << 13)
+#define ACCDET_EINT0_M_PLUG_IN_COUNT_ADDR \
+ MT6359_ACCDET_CON39
+#define ACCDET_EINT0_M_PLUG_IN_COUNT_SFT 0
+#define ACCDET_EINT0_M_PLUG_IN_COUNT_MASK 0x7
+#define ACCDET_EINT0_M_PLUG_IN_COUNT_MASK_SFT (0x7 << 0)
+#define ACCDET_EINT1_M_PLUG_IN_COUNT_ADDR \
+ MT6359_ACCDET_CON39
+#define ACCDET_EINT1_M_PLUG_IN_COUNT_SFT 4
+#define ACCDET_EINT1_M_PLUG_IN_COUNT_MASK 0x7
+#define ACCDET_EINT1_M_PLUG_IN_COUNT_MASK_SFT (0x7 << 4)
+#define ACCDET_MON_FLAG_EN_ADDR \
+ MT6359_ACCDET_CON40
+#define ACCDET_MON_FLAG_EN_SFT 0
+#define ACCDET_MON_FLAG_EN_MASK 0x1
+#define ACCDET_MON_FLAG_EN_MASK_SFT (0x1 << 0)
+#define ACCDET_MON_FLAG_SEL_ADDR \
+ MT6359_ACCDET_CON40
+#define ACCDET_MON_FLAG_SEL_SFT 4
+#define ACCDET_MON_FLAG_SEL_MASK 0xF
+#define ACCDET_MON_FLAG_SEL_MASK_SFT (0xF << 4)
+
+#define RG_AUDPWDBMICBIAS0_ADDR \
+ MT6359_AUDENC_ANA_CON15
+#define RG_AUDPWDBMICBIAS0_SFT 0
+#define RG_AUDPWDBMICBIAS0_MASK 0x1
+#define RG_AUDPWDBMICBIAS0_MASK_SFT (0x1 << 0)
+#define RG_AUDPREAMPLON_ADDR \
+ MT6359_AUDENC_ANA_CON0
+#define RG_AUDPREAMPLON_SFT 0
+#define RG_AUDPREAMPLON_MASK 0x1
+#define RG_AUDPREAMPLON_MASK_SFT (0x1 << 0)
+#define RG_CLKSQ_EN_ADDR \
+ MT6359_AUDENC_ANA_CON23
+#define RG_CLKSQ_EN_SFT 0
+#define RG_CLKSQ_EN_MASK 0x1
+#define RG_CLKSQ_EN_MASK_SFT (0x1 << 0)
+#define RG_RTC32K_CK_PDN_ADDR \
+ MT6359_TOP_CKPDN_CON0
+#define RG_RTC32K_CK_PDN_SFT 15
+#define RG_RTC32K_CK_PDN_MASK 0x1
+#define RG_RTC32K_CK_PDN_MASK_SFT (0x1 << 15)
+#define RG_HPLOUTPUTSTBENH_VAUDP32_ADDR \
+ MT6359_AUDDEC_ANA_CON2
+#define RG_HPLOUTPUTSTBENH_VAUDP32_SFT 0
+#define RG_HPLOUTPUTSTBENH_VAUDP32_MASK 0x7
+#define RG_HPLOUTPUTSTBENH_VAUDP32_MASK_SFT (0x7 << 0)
+#define AUXADC_RQST_CH5_ADDR \
+ MT6359_AUXADC_RQST0
+#define AUXADC_RQST_CH5_SFT 5
+#define AUXADC_RQST_CH5_MASK 0x1
+#define AUXADC_RQST_CH5_MASK_SFT (0x1 << 5)
+#define RG_LDO_VUSB_HW0_OP_EN_ADDR \
+ MT6359_LDO_VUSB_OP_EN
+#define RG_LDO_VUSB_HW0_OP_EN_SFT 0
+#define RG_LDO_VUSB_HW0_OP_EN_MASK 0x1
+#define RG_LDO_VUSB_HW0_OP_EN_MASK_SFT (0x1 << 0)
+#define RG_HPROUTPUTSTBENH_VAUDP32_ADDR \
+ MT6359_AUDDEC_ANA_CON2
+#define RG_HPROUTPUTSTBENH_VAUDP32_SFT 4
+#define RG_HPROUTPUTSTBENH_VAUDP32_MASK 0x7
+#define RG_HPROUTPUTSTBENH_VAUDP32_MASK_SFT (0x7 << 4)
+#define RG_NCP_PDDIS_EN_ADDR \
+ MT6359_AFE_NCP_CFG2
+#define RG_NCP_PDDIS_EN_SFT 0
+#define RG_NCP_PDDIS_EN_MASK 0x1
+#define RG_NCP_PDDIS_EN_MASK_SFT (0x1 << 0)
+#define RG_SCK32K_CK_PDN_ADDR \
+ MT6359_TOP_CKPDN_CON0
+#define RG_SCK32K_CK_PDN_SFT 0
+#define RG_SCK32K_CK_PDN_MASK 0x1
+#define RG_SCK32K_CK_PDN_MASK_SFT (0x1 << 0)
/* AUDENC_ANA_CON18: */
-#define RG_ACCDET_MODE_ANA11_MODE1 (0x000f)
-#define RG_ACCDET_MODE_ANA11_MODE2 (0x008f)
-#define RG_ACCDET_MODE_ANA11_MODE6 (0x008f)
+#define RG_ACCDET_MODE_ANA11_MODE1 (0x000F)
+#define RG_ACCDET_MODE_ANA11_MODE2 (0x008F)
+#define RG_ACCDET_MODE_ANA11_MODE6 (0x008F)
/* AUXADC_ADC5: Auxadc CH5 read data */
#define AUXADC_DATA_RDY_CH5 BIT(15)
#define AUXADC_DATA_PROCEED_CH5 BIT(15)
-#define AUXADC_DATA_MASK (0x0fff)
+#define AUXADC_DATA_MASK (0x0FFF)
/* AUXADC_RQST0_SET: Auxadc CH5 request, relevant 0x07EC */
#define AUXADC_RQST_CH5_SET BIT(5)
/* AUXADC_RQST0_CLR: Auxadc CH5 request, relevant 0x07EC */
#define AUXADC_RQST_CH5_CLR BIT(5)
-#define ACCDET_CALI_MASK0 (0xff)
-#define ACCDET_CALI_MASK1 (0xff << 8)
-#define ACCDET_CALI_MASK2 (0xff)
-#define ACCDET_CALI_MASK3 (0xff << 8)
-#define ACCDET_CALI_MASK4 (0xff)
-
-#define ACCDET_EINT1_IRQ_CLR_B11 BIT(PMIC_ACCDET_EINT1_IRQ_CLR_SHIFT)
-#define ACCDET_EINT0_IRQ_CLR_B10 BIT(PMIC_ACCDET_EINT0_IRQ_CLR_SHIFT)
-#define ACCDET_EINT_IRQ_CLR_B10_11 (0x03 << \
- PMIC_ACCDET_EINT0_IRQ_CLR_SHIFT)
-#define ACCDET_IRQ_CLR_B8 BIT(PMIC_ACCDET_IRQ_CLR_SHIFT)
+#define ACCDET_CALI_MASK0 (0xFF)
+#define ACCDET_CALI_MASK1 (0xFF << 8)
+#define ACCDET_CALI_MASK2 (0xFF)
+#define ACCDET_CALI_MASK3 (0xFF << 8)
+#define ACCDET_CALI_MASK4 (0xFF)
-#define ACCDET_EINT1_IRQ_B3 BIT(PMIC_ACCDET_EINT1_IRQ_SHIFT)
-#define ACCDET_EINT0_IRQ_B2 BIT(PMIC_ACCDET_EINT0_IRQ_SHIFT)
-#define ACCDET_EINT_IRQ_B2_B3 (0x03 << PMIC_ACCDET_EINT0_IRQ_SHIFT)
-#define ACCDET_IRQ_B0 BIT(PMIC_ACCDET_IRQ_SHIFT)
+#define ACCDET_EINT_IRQ_B2_B3 (0x03 << ACCDET_EINT0_IRQ_SFT)
/* ACCDET_CON25: RO, accdet FSM state,etc.*/
-#define ACCDET_STATE_MEM_IN_OFFSET (PMIC_ACCDET_MEM_IN_SHIFT)
-#define ACCDET_STATE_AB_MASK (0x03)
-#define ACCDET_STATE_AB_00 (0x00)
-#define ACCDET_STATE_AB_01 (0x01)
-#define ACCDET_STATE_AB_10 (0x02)
-#define ACCDET_STATE_AB_11 (0x03)
+#define ACCDET_STATE_MEM_IN_OFFSET (ACCDET_MEM_IN_SFT)
+#define ACCDET_STATE_AB_MASK (0x03)
+#define ACCDET_STATE_AB_00 (0x00)
+#define ACCDET_STATE_AB_01 (0x01)
+#define ACCDET_STATE_AB_10 (0x02)
+#define ACCDET_STATE_AB_11 (0x03)
/* ACCDET_CON19 */
-#define ACCDET_EINT0_STABLE_VAL ((1 << PMIC_ACCDET_DA_STABLE_SHIFT) | \
- (1 << PMIC_ACCDET_EINT0_EN_STABLE_SHIFT) | \
- (1 << PMIC_ACCDET_EINT0_CMPEN_STABLE_SHIFT) | \
- (1 << PMIC_ACCDET_EINT0_CEN_STABLE_SHIFT))
-
-#define ACCDET_EINT1_STABLE_VAL ((1 << PMIC_ACCDET_DA_STABLE_SHIFT) | \
- (1 << PMIC_ACCDET_EINT1_EN_STABLE_SHIFT) | \
- (1 << PMIC_ACCDET_EINT1_CMPEN_STABLE_SHIFT) | \
- (1 << PMIC_ACCDET_EINT1_CEN_STABLE_SHIFT))
-
+#define ACCDET_EINT0_STABLE_VAL ((ACCDET_DA_STABLE_MASK_SFT) | \
+ (ACCDET_EINT0_EN_STABLE_MASK_SFT) | \
+ (ACCDET_EINT0_CMPEN_STABLE_MASK_SFT) | \
+ (ACCDET_EINT0_CEN_STABLE_MASK_SFT))
+
+#define ACCDET_EINT1_STABLE_VAL ((ACCDET_DA_STABLE_MASK_SFT) | \
+ (ACCDET_EINT1_EN_STABLE_MASK_SFT) | \
+ (ACCDET_EINT1_CMPEN_STABLE_MASK_SFT) | \
+ (ACCDET_EINT1_CEN_STABLE_MASK_SFT))
/* The following are used for mt6359.c */
/* MT6359_DCXO_CW12 */
#define RG_XO_AUDIO_EN_M_SFT 13
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index f0cba7b5758b..67de0e49ccf4 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -295,7 +295,7 @@ static inline void nau8825_sema_reset(struct nau8825 *nau8825)
}
/**
- * Ramp up the headphone volume change gradually to target level.
+ * nau8825_hpvol_ramp - Ramp up the headphone volume change gradually to target level.
*
* @nau8825: component to register the codec private data with
* @vol_from: the volume to start up
@@ -347,8 +347,9 @@ static void nau8825_hpvol_ramp(struct nau8825 *nau8825,
}
/**
- * Computes log10 of a value; the result is round off to 3 decimal. This func-
- * tion takes reference to dvb-math. The source code locates as the following.
+ * nau8825_intlog10_dec3 - Computes log10 of a value
+ * the result is round off to 3 decimal. This function takes reference to
+ * dvb-math. The source code locates as the following.
* Linux/drivers/media/dvb-core/dvb_math.c
* @value: input for log10
*
@@ -408,7 +409,7 @@ static u32 nau8825_intlog10_dec3(u32 value)
}
/**
- * computes cross talk suppression sidetone gain.
+ * nau8825_xtalk_sidetone - computes cross talk suppression sidetone gain.
*
* @sig_org: orignal signal level
* @sig_cros: cross talk signal level
@@ -2110,7 +2111,7 @@ static int nau8825_set_pll(struct snd_soc_component *component, int pll_id, int
static int nau8825_mclk_prepare(struct nau8825 *nau8825, unsigned int freq)
{
- int ret = 0;
+ int ret;
nau8825->mclk = devm_clk_get(nau8825->dev, "mclk");
if (IS_ERR(nau8825->mclk)) {
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index 07ed8fded471..5b78e9299c95 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -84,7 +84,7 @@ static const int pcm1681_deemph[] = { 44100, 48000, 32000 };
static int pcm1681_set_deemph(struct snd_soc_component *component)
{
struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
- int i = 0, val = -1, enable = 0;
+ int i, val = -1, enable = 0;
if (priv->deemph) {
for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++) {
diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c
index bfe045367db3..faff2b558687 100644
--- a/sound/soc/codecs/rt1011.c
+++ b/sound/soc/codecs/rt1011.c
@@ -1089,25 +1089,21 @@ static int rt1011_recv_spk_mode_put(struct snd_kcontrol *kcontrol,
static bool rt1011_validate_bq_drc_coeff(unsigned short reg)
{
- if ((reg == RT1011_DAC_SET_1) |
- (reg >= RT1011_ADC_SET && reg <= RT1011_ADC_SET_1) |
- (reg == RT1011_ADC_SET_4) | (reg == RT1011_ADC_SET_5) |
- (reg == RT1011_MIXER_1) |
- (reg == RT1011_A_TIMING_1) | (reg >= RT1011_POWER_7 &&
- reg <= RT1011_POWER_8) |
- (reg == RT1011_CLASS_D_POS) | (reg == RT1011_ANALOG_CTRL) |
- (reg >= RT1011_SPK_TEMP_PROTECT_0 &&
- reg <= RT1011_SPK_TEMP_PROTECT_6) |
- (reg >= RT1011_SPK_PRO_DC_DET_5 && reg <= RT1011_BAT_GAIN_1) |
- (reg >= RT1011_RT_DRC_CROSS && reg <= RT1011_RT_DRC_POS_8) |
- (reg >= RT1011_CROSS_BQ_SET_1 && reg <= RT1011_BQ_10_A2_15_0) |
- (reg >= RT1011_SMART_BOOST_TIMING_1 &&
- reg <= RT1011_SMART_BOOST_TIMING_36) |
- (reg == RT1011_SINE_GEN_REG_1) |
- (reg >= RT1011_STP_ALPHA_RECIPROCAL_MSB &&
- reg <= RT1011_BQ_6_PARAMS_CHECK_5) |
- (reg >= RT1011_BQ_7_PARAMS_CHECK_1 &&
- reg <= RT1011_BQ_10_PARAMS_CHECK_5))
+ if ((reg == RT1011_DAC_SET_1) ||
+ (reg >= RT1011_ADC_SET && reg <= RT1011_ADC_SET_1) ||
+ (reg == RT1011_ADC_SET_4) || (reg == RT1011_ADC_SET_5) ||
+ (reg == RT1011_MIXER_1) ||
+ (reg == RT1011_A_TIMING_1) ||
+ (reg >= RT1011_POWER_7 && reg <= RT1011_POWER_8) ||
+ (reg == RT1011_CLASS_D_POS) || (reg == RT1011_ANALOG_CTRL) ||
+ (reg >= RT1011_SPK_TEMP_PROTECT_0 && reg <= RT1011_SPK_TEMP_PROTECT_6) ||
+ (reg >= RT1011_SPK_PRO_DC_DET_5 && reg <= RT1011_BAT_GAIN_1) ||
+ (reg >= RT1011_RT_DRC_CROSS && reg <= RT1011_RT_DRC_POS_8) ||
+ (reg >= RT1011_CROSS_BQ_SET_1 && reg <= RT1011_BQ_10_A2_15_0) ||
+ (reg >= RT1011_SMART_BOOST_TIMING_1 && reg <= RT1011_SMART_BOOST_TIMING_36) ||
+ (reg == RT1011_SINE_GEN_REG_1) ||
+ (reg >= RT1011_STP_ALPHA_RECIPROCAL_MSB && reg <= RT1011_BQ_6_PARAMS_CHECK_5) ||
+ (reg >= RT1011_BQ_7_PARAMS_CHECK_1 && reg <= RT1011_BQ_10_PARAMS_CHECK_5))
return true;
return false;
@@ -1782,8 +1778,9 @@ static int rt1011_set_component_pll(struct snd_soc_component *component,
pll_code.n_code, pll_code.k_code);
snd_soc_component_write(component, RT1011_PLL_1,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT1011_PLL1_QM_SFT |
- pll_code.m_bp << RT1011_PLL1_BPM_SFT | pll_code.n_code);
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT1011_PLL1_QM_SFT) |
+ (pll_code.m_bp << RT1011_PLL1_BPM_SFT) |
+ pll_code.n_code);
snd_soc_component_write(component, RT1011_PLL_2,
pll_code.k_code);
@@ -1991,10 +1988,10 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai,
RT1011_TDM_I2S_DOCK_EN_1_MASK, tdm_en);
snd_soc_component_update_bits(component, RT1011_TDM2_SET_2,
RT1011_TDM_I2S_DOCK_EN_2_MASK, tdm_en);
- if (tx_slotnum)
- snd_soc_component_update_bits(component, RT1011_TDM_TOTAL_SET,
- RT1011_ADCDAT1_PIN_CONFIG | RT1011_ADCDAT2_PIN_CONFIG,
- RT1011_ADCDAT1_OUTPUT | RT1011_ADCDAT2_OUTPUT);
+
+ snd_soc_component_update_bits(component, RT1011_TDM_TOTAL_SET,
+ RT1011_ADCDAT1_PIN_CONFIG | RT1011_ADCDAT2_PIN_CONFIG,
+ RT1011_ADCDAT1_OUTPUT | RT1011_ADCDAT2_OUTPUT);
_set_tdm_err_:
snd_soc_dapm_mutex_unlock(dapm);
@@ -2151,7 +2148,7 @@ MODULE_DEVICE_TABLE(of, rt1011_of_match);
#endif
#ifdef CONFIG_ACPI
-static struct acpi_device_id rt1011_acpi_match[] = {
+static const struct acpi_device_id rt1011_acpi_match[] = {
{"10EC1011", 0,},
{},
};
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c
index 844e4079d176..9238f12999aa 100644
--- a/sound/soc/codecs/rt1015.c
+++ b/sound/soc/codecs/rt1015.c
@@ -669,8 +669,23 @@ static int rt1015_amp_drv_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
+ unsigned int ret, ret2;
switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = snd_soc_component_read(component, RT1015_CLK_DET);
+ ret2 = snd_soc_component_read(component, RT1015_SPK_DC_DETECT1);
+ if (!((ret >> 15) & 0x1)) {
+ snd_soc_component_update_bits(component, RT1015_CLK_DET,
+ RT1015_EN_BCLK_DET_MASK, RT1015_EN_BCLK_DET);
+ dev_dbg(component->dev, "BCLK Detection Enabled.\n");
+ }
+ if (!((ret2 >> 12) & 0x1)) {
+ snd_soc_component_update_bits(component, RT1015_SPK_DC_DETECT1,
+ RT1015_EN_CLA_D_DC_DET_MASK, RT1015_EN_CLA_D_DC_DET);
+ dev_dbg(component->dev, "Class-D DC Detection Enabled.\n");
+ }
+ break;
case SND_SOC_DAPM_POST_PMU:
if (rt1015->hw_config == RT1015_HW_28)
schedule_delayed_work(&rt1015->flush_work, msecs_to_jiffies(10));
@@ -690,7 +705,8 @@ static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = {
r1015_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_OUT_DRV_E("Amp Drv", SND_SOC_NOPM, 0, 0, NULL, 0,
- rt1015_amp_drv_event, SND_SOC_DAPM_POST_PMU),
+ rt1015_amp_drv_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_OUTPUT("SPO"),
};
@@ -893,8 +909,9 @@ static int rt1015_set_component_pll(struct snd_soc_component *component,
pll_code.n_code, pll_code.k_code);
snd_soc_component_write(component, RT1015_PLL1,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT1015_PLL_M_SFT |
- pll_code.m_bp << RT1015_PLL_M_BP_SFT | pll_code.n_code);
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT1015_PLL_M_SFT) |
+ (pll_code.m_bp << RT1015_PLL_M_BP_SFT) |
+ pll_code.n_code);
snd_soc_component_write(component, RT1015_PLL2,
pll_code.k_code);
@@ -1028,7 +1045,7 @@ static void rt1015_remove(struct snd_soc_component *component)
#define RT1015_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
-static struct snd_soc_dai_ops rt1015_aif_dai_ops = {
+static const struct snd_soc_dai_ops rt1015_aif_dai_ops = {
.hw_params = rt1015_hw_params,
.set_fmt = rt1015_set_dai_fmt,
.set_tdm_slot = rt1015_set_tdm_slot,
@@ -1121,7 +1138,7 @@ MODULE_DEVICE_TABLE(of, rt1015_of_match);
#endif
#ifdef CONFIG_ACPI
-static struct acpi_device_id rt1015_acpi_match[] = {
+static const struct acpi_device_id rt1015_acpi_match[] = {
{"10EC1015", 0,},
{},
};
diff --git a/sound/soc/codecs/rt1015.h b/sound/soc/codecs/rt1015.h
index 2aeaf65ba793..14344532048e 100644
--- a/sound/soc/codecs/rt1015.h
+++ b/sound/soc/codecs/rt1015.h
@@ -209,6 +209,11 @@
#define RT1015_PLL_K_MASK (RT1015_PLL_K_MAX)
#define RT1015_PLL_K_SFT 0
+/* 0x0020 */
+#define RT1015_EN_BCLK_DET_MASK (0x1 << 15)
+#define RT1015_EN_BCLK_DET (0x1 << 15)
+#define RT1015_DIS_BCLK_DET (0x0 << 15)
+
/* 0x007a */
#define RT1015_ID_MASK 0xff
#define RT1015_ID_VERA 0x0
@@ -374,6 +379,11 @@
#define RT1015_PWR_SWR (0x1 << 12)
#define RT1015_PWR_SWR_BIT 12
+/* 0x0519 */
+#define RT1015_EN_CLA_D_DC_DET_MASK (0x1 << 12)
+#define RT1015_EN_CLA_D_DC_DET (0x1 << 12)
+#define RT1015_DIS_CLA_D_DC_DET (0x0 << 12)
+
/* 0x1300 */
#define RT1015_PWR_CLSD (0x1 << 12)
#define RT1015_PWR_CLSD_BIT 12
diff --git a/sound/soc/codecs/rt1015p.c b/sound/soc/codecs/rt1015p.c
index 671f2a2130fe..40f2063aefbe 100644
--- a/sound/soc/codecs/rt1015p.c
+++ b/sound/soc/codecs/rt1015p.c
@@ -4,6 +4,7 @@
//
// Copyright 2020 The Linux Foundation. All rights reserved.
+#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -95,7 +96,8 @@ static struct snd_soc_dai_driver rt1015p_dai_driver = {
.name = "HiFi",
.playback = {
.stream_name = "HiFi Playback",
- .formats = SNDRV_PCM_FMTBIT_S24,
+ .formats = SNDRV_PCM_FMTBIT_S24 |
+ SNDRV_PCM_FMTBIT_S32,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 1,
.channels_max = 2,
@@ -130,10 +132,19 @@ static const struct of_device_id rt1015p_device_id[] = {
MODULE_DEVICE_TABLE(of, rt1015p_device_id);
#endif
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt1015p_acpi_match[] = {
+ { "RTL1015", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, rt1015p_acpi_match);
+#endif
+
static struct platform_driver rt1015p_platform_driver = {
.driver = {
.name = "rt1015p",
.of_match_table = of_match_ptr(rt1015p_device_id),
+ .acpi_match_table = ACPI_PTR(rt1015p_acpi_match),
},
.probe = rt1015p_platform_probe,
};
diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c
index a23d368ab4da..7561d202274c 100644
--- a/sound/soc/codecs/rt1016.c
+++ b/sound/soc/codecs/rt1016.c
@@ -500,10 +500,11 @@ static int rt1016_set_component_pll(struct snd_soc_component *component,
(pll_code.k_bp ? 0 : pll_code.k_code));
snd_soc_component_write(component, RT1016_PLL1,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT1016_PLL_M_SFT |
- pll_code.m_bp << RT1016_PLL_M_BP_SFT | pll_code.n_code);
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT1016_PLL_M_SFT) |
+ (pll_code.m_bp << RT1016_PLL_M_BP_SFT) |
+ pll_code.n_code);
snd_soc_component_write(component, RT1016_PLL2,
- pll_code.k_bp << RT1016_PLL_K_BP_SFT |
+ (pll_code.k_bp << RT1016_PLL_K_BP_SFT) |
(pll_code.k_bp ? 0 : pll_code.k_code));
rt1016->pll_in = freq_in;
@@ -534,7 +535,7 @@ static void rt1016_remove(struct snd_soc_component *component)
#define RT1016_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
-static struct snd_soc_dai_ops rt1016_aif_dai_ops = {
+static const struct snd_soc_dai_ops rt1016_aif_dai_ops = {
.hw_params = rt1016_hw_params,
.set_fmt = rt1016_set_dai_fmt,
};
@@ -623,7 +624,7 @@ MODULE_DEVICE_TABLE(of, rt1016_of_match);
#endif
#ifdef CONFIG_ACPI
-static struct acpi_device_id rt1016_acpi_match[] = {
+static const struct acpi_device_id rt1016_acpi_match[] = {
{"10EC1016", 0,},
{},
};
diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c
new file mode 100644
index 000000000000..10656a5927f1
--- /dev/null
+++ b/sound/soc/codecs/rt1019.c
@@ -0,0 +1,608 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt1019.c -- RT1019 ALSA SoC audio amplifier driver
+// Author: Jack Yu <jack.yu@realtek.com>
+//
+// Copyright(c) 2021 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 "rl6231.h"
+#include "rt1019.h"
+
+static const struct reg_default rt1019_reg[] = {
+ { 0x0000, 0x00 },
+ { 0x0011, 0x04 },
+ { 0x0013, 0x00 },
+ { 0x0019, 0x30 },
+ { 0x001b, 0x01 },
+ { 0x005c, 0x00 },
+ { 0x005e, 0x10 },
+ { 0x005f, 0xec },
+ { 0x0061, 0x10 },
+ { 0x0062, 0x19 },
+ { 0x0066, 0x08 },
+ { 0x0100, 0x80 },
+ { 0x0100, 0x51 },
+ { 0x0102, 0x23 },
+ { 0x0311, 0x00 },
+ { 0x0312, 0x3e },
+ { 0x0313, 0x86 },
+ { 0x0400, 0x03 },
+ { 0x0401, 0x02 },
+ { 0x0402, 0x01 },
+ { 0x0504, 0xff },
+ { 0x0505, 0x24 },
+ { 0x0b00, 0x50 },
+ { 0x0b01, 0xc3 },
+};
+
+static bool rt1019_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT1019_PWR_STRP_2:
+ case RT1019_VER_ID:
+ case RT1019_VEND_ID_1:
+ case RT1019_VEND_ID_2:
+ case RT1019_DEV_ID_1:
+ case RT1019_DEV_ID_2:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool rt1019_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT1019_RESET:
+ case RT1019_IDS_CTRL:
+ case RT1019_ASEL_CTRL:
+ case RT1019_PWR_STRP_2:
+ case RT1019_BEEP_TONE:
+ case RT1019_VER_ID:
+ case RT1019_VEND_ID_1:
+ case RT1019_VEND_ID_2:
+ case RT1019_DEV_ID_1:
+ case RT1019_DEV_ID_2:
+ case RT1019_SDB_CTRL:
+ case RT1019_CLK_TREE_1:
+ case RT1019_CLK_TREE_2:
+ case RT1019_CLK_TREE_3:
+ case RT1019_PLL_1:
+ case RT1019_PLL_2:
+ case RT1019_PLL_3:
+ case RT1019_TDM_1:
+ case RT1019_TDM_2:
+ case RT1019_TDM_3:
+ case RT1019_DMIX_MONO_1:
+ case RT1019_DMIX_MONO_2:
+ case RT1019_BEEP_1:
+ case RT1019_BEEP_2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9525, 75, 0);
+
+static const char * const rt1019_din_source_select[] = {
+ "Left",
+ "Right",
+ "Left + Right average",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1019_mono_lr_sel, RT1019_IDS_CTRL, 0,
+ rt1019_din_source_select);
+
+static const struct snd_kcontrol_new rt1019_snd_controls[] = {
+ SOC_SINGLE_TLV("DAC Playback Volume", RT1019_DMIX_MONO_1, 0,
+ 127, 0, dac_vol_tlv),
+ SOC_ENUM("Mono LR Select", rt1019_mono_lr_sel),
+};
+
+static int r1019_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);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_write(component, RT1019_SDB_CTRL, 0xb);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_write(component, RT1019_SDB_CTRL, 0xa);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt1019_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0,
+ r1019_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUTPUT("SPO"),
+};
+
+static const struct snd_soc_dapm_route rt1019_dapm_routes[] = {
+ { "DAC", NULL, "AIFRX" },
+ { "SPO", NULL, "DAC" },
+};
+
+static int rt1019_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 rt1019_priv *rt1019 = snd_soc_component_get_drvdata(component);
+ int pre_div, bclk_ms, frame_size;
+ unsigned int val_len = 0, sys_div_da_filter = 0;
+ unsigned int sys_dac_osr = 0, sys_fifo_clk = 0;
+ unsigned int sys_clk_cal = 0, sys_asrc_in = 0;
+
+ rt1019->lrck = params_rate(params);
+ pre_div = rl6231_get_clk_info(rt1019->sysclk, rt1019->lrck);
+ if (pre_div < 0) {
+ dev_err(component->dev, "Unsupported clock setting\n");
+ return -EINVAL;
+ }
+
+ frame_size = snd_soc_params_to_frame_size(params);
+ if (frame_size < 0) {
+ dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
+ return -EINVAL;
+ }
+
+ bclk_ms = frame_size > 32;
+ rt1019->bclk = rt1019->lrck * (32 << bclk_ms);
+
+ dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+ rt1019->bclk, rt1019->lrck);
+ dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+ bclk_ms, pre_div, dai->id);
+
+ switch (pre_div) {
+ case 0:
+ sys_div_da_filter = RT1019_SYS_DIV_DA_FIL_DIV1;
+ sys_dac_osr = RT1019_SYS_DA_OSR_DIV1;
+ sys_asrc_in = RT1019_ASRC_256FS_DIV1;
+ sys_fifo_clk = RT1019_SEL_FIFO_DIV1;
+ sys_clk_cal = RT1019_SEL_CLK_CAL_DIV1;
+ break;
+ case 1:
+ sys_div_da_filter = RT1019_SYS_DIV_DA_FIL_DIV2;
+ sys_dac_osr = RT1019_SYS_DA_OSR_DIV2;
+ sys_asrc_in = RT1019_ASRC_256FS_DIV2;
+ sys_fifo_clk = RT1019_SEL_FIFO_DIV2;
+ sys_clk_cal = RT1019_SEL_CLK_CAL_DIV2;
+ break;
+ case 3:
+ sys_div_da_filter = RT1019_SYS_DIV_DA_FIL_DIV4;
+ sys_dac_osr = RT1019_SYS_DA_OSR_DIV4;
+ sys_asrc_in = RT1019_ASRC_256FS_DIV4;
+ sys_fifo_clk = RT1019_SEL_FIFO_DIV4;
+ sys_clk_cal = RT1019_SEL_CLK_CAL_DIV4;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (params_width(params)) {
+ case 16:
+ break;
+ case 20:
+ val_len = RT1019_I2S_DL_20;
+ break;
+ case 24:
+ val_len = RT1019_I2S_DL_24;
+ break;
+ case 32:
+ val_len = RT1019_I2S_DL_32;
+ break;
+ case 8:
+ val_len = RT1019_I2S_DL_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component, RT1019_TDM_2, RT1019_I2S_DL_MASK,
+ val_len);
+ snd_soc_component_update_bits(component, RT1019_CLK_TREE_1,
+ RT1019_SEL_FIFO_MASK, sys_fifo_clk);
+ snd_soc_component_update_bits(component, RT1019_CLK_TREE_2,
+ RT1019_SYS_DIV_DA_FIL_MASK | RT1019_SYS_DA_OSR_MASK |
+ RT1019_ASRC_256FS_MASK, sys_div_da_filter | sys_dac_osr |
+ sys_asrc_in);
+ snd_soc_component_update_bits(component, RT1019_CLK_TREE_3,
+ RT1019_SEL_CLK_CAL_MASK, sys_clk_cal);
+
+ return 0;
+}
+
+static int rt1019_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->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 |= RT1019_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 |= RT1019_I2S_DF_LEFT;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_A:
+ reg_val |= RT1019_I2S_DF_PCM_A_R;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_B:
+ reg_val |= RT1019_I2S_DF_PCM_B_R;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component, RT1019_TDM_2,
+ RT1019_I2S_DF_MASK, reg_val);
+ snd_soc_component_update_bits(component, RT1019_TDM_1,
+ RT1019_TDM_BCLK_MASK, reg_val2);
+
+ return 0;
+}
+
+static int rt1019_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1019_priv *rt1019 = snd_soc_component_get_drvdata(component);
+ unsigned int reg_val = 0;
+
+ if (freq == rt1019->sysclk && clk_id == rt1019->sysclk_src)
+ return 0;
+
+ switch (clk_id) {
+ case RT1019_SCLK_S_BCLK:
+ reg_val |= RT1019_CLK_SYS_PRE_SEL_BCLK;
+ break;
+
+ case RT1019_SCLK_S_PLL:
+ reg_val |= RT1019_CLK_SYS_PRE_SEL_PLL;
+ break;
+
+ default:
+ dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+ return -EINVAL;
+ }
+
+ rt1019->sysclk = freq;
+ rt1019->sysclk_src = clk_id;
+
+ dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+ snd_soc_component_update_bits(component, RT1019_CLK_TREE_1,
+ RT1019_CLK_SYS_PRE_SEL_MASK, reg_val);
+
+ return 0;
+}
+
+static int rt1019_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 rt1019_priv *rt1019 = snd_soc_component_get_drvdata(component);
+ struct rl6231_pll_code pll_code;
+ int ret;
+
+ if (!freq_in || !freq_out) {
+ dev_dbg(component->dev, "PLL disabled\n");
+ rt1019->pll_in = 0;
+ rt1019->pll_out = 0;
+ return 0;
+ }
+
+ if (source == rt1019->pll_src && freq_in == rt1019->pll_in &&
+ freq_out == rt1019->pll_out)
+ return 0;
+
+ switch (source) {
+ case RT1019_PLL_S_BCLK:
+ snd_soc_component_update_bits(component, RT1019_CLK_TREE_1,
+ RT1019_PLL_SRC_MASK, RT1019_PLL_SRC_SEL_BCLK);
+ break;
+
+ case RT1019_PLL_S_RC25M:
+ snd_soc_component_update_bits(component, RT1019_CLK_TREE_1,
+ RT1019_PLL_SRC_MASK, RT1019_PLL_SRC_SEL_RC);
+ break;
+
+ default:
+ dev_err(component->dev, "Unknown PLL source %d\n", source);
+ return -EINVAL;
+ }
+
+ ret = rl6231_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);
+
+ snd_soc_component_update_bits(component, RT1019_PWR_STRP_2,
+ RT1019_AUTO_BITS_SEL_MASK | RT1019_AUTO_CLK_SEL_MASK,
+ RT1019_AUTO_BITS_SEL_MANU | RT1019_AUTO_CLK_SEL_MANU);
+ snd_soc_component_update_bits(component, RT1019_PLL_1,
+ RT1019_PLL_M_MASK | RT1019_PLL_M_BP_MASK | RT1019_PLL_Q_8_8_MASK,
+ (pll_code.m_bp ? 0 : pll_code.m_code) << RT1019_PLL_M_SFT |
+ pll_code.m_bp << RT1019_PLL_M_BP_SFT |
+ ((pll_code.n_code >> 8) & RT1019_PLL_Q_8_8_MASK));
+ snd_soc_component_update_bits(component, RT1019_PLL_2,
+ RT1019_PLL_Q_7_0_MASK, pll_code.n_code & RT1019_PLL_Q_7_0_MASK);
+ snd_soc_component_update_bits(component, RT1019_PLL_3,
+ RT1019_PLL_K_MASK, pll_code.k_code);
+
+ rt1019->pll_in = freq_in;
+ rt1019->pll_out = freq_out;
+ rt1019->pll_src = source;
+
+ return 0;
+}
+
+static int rt1019_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct snd_soc_component *component = dai->component;
+ unsigned int val = 0, rx_slotnum;
+ int ret = 0, first_bit;
+
+ switch (slots) {
+ case 4:
+ val |= RT1019_I2S_TX_4CH;
+ break;
+ case 6:
+ val |= RT1019_I2S_TX_6CH;
+ break;
+ case 8:
+ val |= RT1019_I2S_TX_8CH;
+ break;
+ case 2:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (slot_width) {
+ case 20:
+ val |= RT1019_I2S_DL_20;
+ break;
+ case 24:
+ val |= RT1019_I2S_DL_24;
+ break;
+ case 32:
+ val |= RT1019_I2S_DL_32;
+ break;
+ case 8:
+ val |= RT1019_I2S_DL_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_;
+ }
+ /* This is an assumption that the system sends stereo audio to the
+ * amplifier typically. And the stereo audio is placed in slot 0/2/4/6
+ * as the starting slot. The users could select the channel from
+ * L/R/L+R by "Mono LR Select" control.
+ */
+ first_bit = __ffs(rx_mask);
+ switch (first_bit) {
+ case 0:
+ case 2:
+ case 4:
+ case 6:
+ snd_soc_component_update_bits(component,
+ RT1019_TDM_3,
+ RT1019_TDM_I2S_TX_L_DAC1_1_MASK |
+ RT1019_TDM_I2S_TX_R_DAC1_1_MASK,
+ (first_bit << RT1019_TDM_I2S_TX_L_DAC1_1_SFT) |
+ ((first_bit + 1) << RT1019_TDM_I2S_TX_R_DAC1_1_SFT));
+ break;
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ snd_soc_component_update_bits(component,
+ RT1019_TDM_3,
+ RT1019_TDM_I2S_TX_L_DAC1_1_MASK |
+ RT1019_TDM_I2S_TX_R_DAC1_1_MASK,
+ ((first_bit - 1) << RT1019_TDM_I2S_TX_L_DAC1_1_SFT) |
+ (first_bit << RT1019_TDM_I2S_TX_R_DAC1_1_SFT));
+ break;
+ default:
+ ret = -EINVAL;
+ goto _set_tdm_err_;
+ }
+
+ snd_soc_component_update_bits(component, RT1019_TDM_2,
+ RT1019_I2S_CH_TX_MASK | RT1019_I2S_DF_MASK, val);
+
+_set_tdm_err_:
+ return ret;
+}
+
+static int rt1019_probe(struct snd_soc_component *component)
+{
+ struct rt1019_priv *rt1019 = snd_soc_component_get_drvdata(component);
+
+ rt1019->component = component;
+ snd_soc_component_write(component, RT1019_SDB_CTRL, 0xa);
+
+ return 0;
+}
+
+#define RT1019_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT1019_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 rt1019_aif_dai_ops = {
+ .hw_params = rt1019_hw_params,
+ .set_fmt = rt1019_set_dai_fmt,
+ .set_sysclk = rt1019_set_dai_sysclk,
+ .set_pll = rt1019_set_dai_pll,
+ .set_tdm_slot = rt1019_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver rt1019_dai[] = {
+ {
+ .name = "rt1019-aif",
+ .id = 0,
+ .playback = {
+ .stream_name = "AIF Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT1019_STEREO_RATES,
+ .formats = RT1019_FORMATS,
+ },
+ .ops = &rt1019_aif_dai_ops,
+ }
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt1019 = {
+ .probe = rt1019_probe,
+ .controls = rt1019_snd_controls,
+ .num_controls = ARRAY_SIZE(rt1019_snd_controls),
+ .dapm_widgets = rt1019_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt1019_dapm_widgets),
+ .dapm_routes = rt1019_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt1019_dapm_routes),
+};
+
+static const struct regmap_config rt1019_regmap = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .use_single_read = true,
+ .use_single_write = true,
+ .max_register = RT1019_BEEP_2,
+ .volatile_reg = rt1019_volatile_register,
+ .readable_reg = rt1019_readable_register,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = rt1019_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt1019_reg),
+};
+
+static const struct i2c_device_id rt1019_i2c_id[] = {
+ { "rt1019", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rt1019_i2c_id);
+
+static const struct of_device_id rt1019_of_match[] = {
+ { .compatible = "realtek,rt1019", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt1019_of_match);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt1019_acpi_match[] = {
+ { "10EC1019", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, rt1019_acpi_match);
+#endif
+
+static int rt1019_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rt1019_priv *rt1019;
+ int ret;
+ unsigned int val, val2, dev_id;
+
+ rt1019 = devm_kzalloc(&i2c->dev, sizeof(struct rt1019_priv),
+ GFP_KERNEL);
+ if (!rt1019)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, rt1019);
+
+ rt1019->regmap = devm_regmap_init_i2c(i2c, &rt1019_regmap);
+ if (IS_ERR(rt1019->regmap)) {
+ ret = PTR_ERR(rt1019->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ regmap_read(rt1019->regmap, RT1019_DEV_ID_1, &val);
+ regmap_read(rt1019->regmap, RT1019_DEV_ID_2, &val2);
+ dev_id = val << 8 | val2;
+ if (dev_id != RT1019_DEVICE_ID_VAL && dev_id != RT1019_DEVICE_ID_VAL2) {
+ dev_err(&i2c->dev,
+ "Device with ID register 0x%x is not rt1019\n", dev_id);
+ return -ENODEV;
+ }
+
+ return devm_snd_soc_register_component(&i2c->dev,
+ &soc_component_dev_rt1019, rt1019_dai, ARRAY_SIZE(rt1019_dai));
+}
+
+static struct i2c_driver rt1019_i2c_driver = {
+ .driver = {
+ .name = "rt1019",
+ .of_match_table = of_match_ptr(rt1019_of_match),
+ .acpi_match_table = ACPI_PTR(rt1019_acpi_match),
+ },
+ .probe = rt1019_i2c_probe,
+ .id_table = rt1019_i2c_id,
+};
+module_i2c_driver(rt1019_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT1019 driver");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt1019.h b/sound/soc/codecs/rt1019.h
new file mode 100644
index 000000000000..64df831eeb72
--- /dev/null
+++ b/sound/soc/codecs/rt1019.h
@@ -0,0 +1,158 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt1019.h -- RT1019 ALSA SoC audio amplifier driver
+ *
+ * Copyright(c) 2021 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT1019_H__
+#define __RT1019_H__
+
+#define RT1019_DEVICE_ID_VAL 0x1019
+#define RT1019_DEVICE_ID_VAL2 0x6731
+
+#define RT1019_RESET 0x0000
+#define RT1019_IDS_CTRL 0x0011
+#define RT1019_ASEL_CTRL 0x0013
+#define RT1019_PWR_STRP_2 0x0019
+#define RT1019_BEEP_TONE 0x001b
+#define RT1019_VER_ID 0x005c
+#define RT1019_VEND_ID_1 0x005e
+#define RT1019_VEND_ID_2 0x005f
+#define RT1019_DEV_ID_1 0x0061
+#define RT1019_DEV_ID_2 0x0062
+#define RT1019_SDB_CTRL 0x0066
+#define RT1019_CLK_TREE_1 0x0100
+#define RT1019_CLK_TREE_2 0x0101
+#define RT1019_CLK_TREE_3 0x0102
+#define RT1019_PLL_1 0x0311
+#define RT1019_PLL_2 0x0312
+#define RT1019_PLL_3 0x0313
+#define RT1019_TDM_1 0x0400
+#define RT1019_TDM_2 0x0401
+#define RT1019_TDM_3 0x0402
+#define RT1019_DMIX_MONO_1 0x0504
+#define RT1019_DMIX_MONO_2 0x0505
+#define RT1019_BEEP_1 0x0b00
+#define RT1019_BEEP_2 0x0b01
+
+/* 0x0019 Power On Strap Control-2 */
+#define RT1019_AUTO_BITS_SEL_MASK (0x1 << 5)
+#define RT1019_AUTO_BITS_SEL_AUTO (0x1 << 5)
+#define RT1019_AUTO_BITS_SEL_MANU (0x0 << 5)
+#define RT1019_AUTO_CLK_SEL_MASK (0x1 << 4)
+#define RT1019_AUTO_CLK_SEL_AUTO (0x1 << 4)
+#define RT1019_AUTO_CLK_SEL_MANU (0x0 << 4)
+
+/* 0x0100 Clock Tree Control-1 */
+#define RT1019_CLK_SYS_PRE_SEL_MASK (0x1 << 7)
+#define RT1019_CLK_SYS_PRE_SEL_SFT 7
+#define RT1019_CLK_SYS_PRE_SEL_BCLK (0x0 << 7)
+#define RT1019_CLK_SYS_PRE_SEL_PLL (0x1 << 7)
+#define RT1019_PLL_SRC_MASK (0x1 << 4)
+#define RT1019_PLL_SRC_SFT 4
+#define RT1019_PLL_SRC_SEL_BCLK (0x0 << 4)
+#define RT1019_PLL_SRC_SEL_RC (0x1 << 4)
+#define RT1019_SEL_FIFO_MASK (0x3 << 2)
+#define RT1019_SEL_FIFO_DIV1 (0x0 << 2)
+#define RT1019_SEL_FIFO_DIV2 (0x1 << 2)
+#define RT1019_SEL_FIFO_DIV4 (0x2 << 2)
+
+/* 0x0101 clock tree control-2 */
+#define RT1019_SYS_DIV_DA_FIL_MASK (0x7 << 5)
+#define RT1019_SYS_DIV_DA_FIL_DIV1 (0x2 << 5)
+#define RT1019_SYS_DIV_DA_FIL_DIV2 (0x3 << 5)
+#define RT1019_SYS_DIV_DA_FIL_DIV4 (0x4 << 5)
+#define RT1019_SYS_DA_OSR_MASK (0x3 << 2)
+#define RT1019_SYS_DA_OSR_DIV1 (0x0 << 2)
+#define RT1019_SYS_DA_OSR_DIV2 (0x1 << 2)
+#define RT1019_SYS_DA_OSR_DIV4 (0x2 << 2)
+#define RT1019_ASRC_256FS_MASK 0x3
+#define RT1019_ASRC_256FS_DIV1 0x0
+#define RT1019_ASRC_256FS_DIV2 0x1
+#define RT1019_ASRC_256FS_DIV4 0x2
+
+/* 0x0102 clock tree control-3 */
+#define RT1019_SEL_CLK_CAL_MASK (0x3 << 6)
+#define RT1019_SEL_CLK_CAL_DIV1 (0x0 << 6)
+#define RT1019_SEL_CLK_CAL_DIV2 (0x1 << 6)
+#define RT1019_SEL_CLK_CAL_DIV4 (0x2 << 6)
+
+/* 0x0311 PLL-1 */
+#define RT1019_PLL_M_MASK (0xf << 4)
+#define RT1019_PLL_M_SFT 4
+#define RT1019_PLL_M_BP_MASK (0x1 << 1)
+#define RT1019_PLL_M_BP_SFT 1
+#define RT1019_PLL_Q_8_8_MASK (0x1)
+
+/* 0x0312 PLL-2 */
+#define RT1019_PLL_Q_7_0_MASK 0xff
+
+/* 0x0313 PLL-3 */
+#define RT1019_PLL_K_MASK 0x1f
+
+/* 0x0400 TDM Control-1 */
+#define RT1019_TDM_BCLK_MASK (0x1 << 6)
+#define RT1019_TDM_BCLK_NORM (0x0 << 6)
+#define RT1019_TDM_BCLK_INV (0x1 << 6)
+
+/* 0x0401 TDM Control-2 */
+#define RT1019_I2S_CH_TX_MASK (0x3 << 6)
+#define RT1019_I2S_CH_TX_SFT 6
+#define RT1019_I2S_TX_2CH (0x0 << 6)
+#define RT1019_I2S_TX_4CH (0x1 << 6)
+#define RT1019_I2S_TX_6CH (0x2 << 6)
+#define RT1019_I2S_TX_8CH (0x3 << 6)
+#define RT1019_I2S_DF_MASK (0x7 << 3)
+#define RT1019_I2S_DF_SFT 3
+#define RT1019_I2S_DF_I2S (0x0 << 3)
+#define RT1019_I2S_DF_LEFT (0x1 << 3)
+#define RT1019_I2S_DF_PCM_A_R (0x2 << 3)
+#define RT1019_I2S_DF_PCM_B_R (0x3 << 3)
+#define RT1019_I2S_DF_PCM_A_F (0x6 << 3)
+#define RT1019_I2S_DF_PCM_B_F (0x7 << 3)
+#define RT1019_I2S_DL_MASK 0x7
+#define RT1019_I2S_DL_SFT 0
+#define RT1019_I2S_DL_16 0x0
+#define RT1019_I2S_DL_20 0x1
+#define RT1019_I2S_DL_24 0x2
+#define RT1019_I2S_DL_32 0x3
+#define RT1019_I2S_DL_8 0x4
+
+/* TDM1 Control-3 (0x0402) */
+#define RT1019_TDM_I2S_TX_L_DAC1_1_MASK (0x7 << 4)
+#define RT1019_TDM_I2S_TX_R_DAC1_1_MASK 0x7
+#define RT1019_TDM_I2S_TX_L_DAC1_1_SFT 4
+#define RT1019_TDM_I2S_TX_R_DAC1_1_SFT 0
+
+/* System Clock Source */
+enum {
+ RT1019_SCLK_S_BCLK,
+ RT1019_SCLK_S_PLL,
+};
+
+/* PLL1 Source */
+enum {
+ RT1019_PLL_S_BCLK,
+ RT1019_PLL_S_RC25M,
+};
+
+enum {
+ RT1019_AIF1,
+ RT1019_AIFS
+};
+
+struct rt1019_priv {
+ struct snd_soc_component *component;
+ struct regmap *regmap;
+ int sysclk;
+ int sysclk_src;
+ int lrck;
+ int bclk;
+ int pll_src;
+ int pll_in;
+ int pll_out;
+ unsigned int bclk_ratio;
+};
+
+#endif /* __RT1019_H__ */
diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c
index 4e9dfd235e59..7a0094578e46 100644
--- a/sound/soc/codecs/rt1305.c
+++ b/sound/soc/codecs/rt1305.c
@@ -850,8 +850,8 @@ static int rt1305_set_component_pll(struct snd_soc_component *component,
pll_code.n_code, pll_code.k_code);
snd_soc_component_write(component, RT1305_PLL1_1,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT1305_PLL_1_M_SFT |
- pll_code.m_bp << RT1305_PLL_1_M_BYPASS_SFT |
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT1305_PLL_1_M_SFT) |
+ (pll_code.m_bp << RT1305_PLL_1_M_BYPASS_SFT) |
pll_code.n_code);
snd_soc_component_write(component, RT1305_PLL1_2,
pll_code.k_code);
@@ -975,7 +975,7 @@ MODULE_DEVICE_TABLE(of, rt1305_of_match);
#endif
#ifdef CONFIG_ACPI
-static struct acpi_device_id rt1305_acpi_match[] = {
+static const struct acpi_device_id rt1305_acpi_match[] = {
{"10EC1305", 0,},
{"10EC1306", 0,},
{},
diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c
index afd2c3b687cc..1c226994aebd 100644
--- a/sound/soc/codecs/rt1308-sdw.c
+++ b/sound/soc/codecs/rt1308-sdw.c
@@ -594,7 +594,7 @@ static int rt1308_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
* slave_ops: callbacks for get_clock_stop_mode, clock_stop and
* port_prep are not defined for now
*/
-static struct sdw_slave_ops rt1308_slave_ops = {
+static const struct sdw_slave_ops rt1308_slave_ops = {
.read_prop = rt1308_read_prop,
.interrupt_callback = rt1308_interrupt_callback,
.update_status = rt1308_update_status,
diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c
index b75931a69a1c..b4e5546e2e21 100644
--- a/sound/soc/codecs/rt1308.c
+++ b/sound/soc/codecs/rt1308.c
@@ -673,10 +673,10 @@ static int rt1308_set_component_pll(struct snd_soc_component *component,
pll_code.n_code, pll_code.k_code);
snd_soc_component_write(component, RT1308_PLL_1,
- pll_code.k_code << RT1308_PLL1_K_SFT |
- pll_code.m_bp << RT1308_PLL1_M_BYPASS_SFT |
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT1308_PLL1_M_SFT |
- pll_code.n_code << RT1308_PLL1_N_SFT);
+ (pll_code.k_code << RT1308_PLL1_K_SFT) |
+ (pll_code.m_bp << RT1308_PLL1_M_BYPASS_SFT) |
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT1308_PLL1_M_SFT) |
+ (pll_code.n_code << RT1308_PLL1_N_SFT));
rt1308->pll_in = freq_in;
rt1308->pll_out = freq_out;
@@ -790,7 +790,7 @@ MODULE_DEVICE_TABLE(of, rt1308_of_match);
#endif
#ifdef CONFIG_ACPI
-static struct acpi_device_id rt1308_acpi_match[] = {
+static const struct acpi_device_id rt1308_acpi_match[] = {
{ "10EC1308", 0, },
{ },
};
diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
new file mode 100644
index 000000000000..3b029c56467d
--- /dev/null
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -0,0 +1,744 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt1316-sdw.c -- rt1316 SDCA ALSA SoC amplifier audio driver
+//
+// Copyright(c) 2021 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 <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include "rt1316-sdw.h"
+
+static const struct reg_default rt1316_reg_defaults[] = {
+ { 0x3004, 0x00 },
+ { 0x3005, 0x00 },
+ { 0x3206, 0x00 },
+ { 0xc001, 0x00 },
+ { 0xc002, 0x00 },
+ { 0xc003, 0x00 },
+ { 0xc004, 0x00 },
+ { 0xc005, 0x00 },
+ { 0xc006, 0x00 },
+ { 0xc007, 0x00 },
+ { 0xc008, 0x00 },
+ { 0xc009, 0x00 },
+ { 0xc00a, 0x00 },
+ { 0xc00b, 0x00 },
+ { 0xc00c, 0x00 },
+ { 0xc00d, 0x00 },
+ { 0xc00e, 0x00 },
+ { 0xc00f, 0x00 },
+ { 0xc010, 0xa5 },
+ { 0xc011, 0x00 },
+ { 0xc012, 0xff },
+ { 0xc013, 0xff },
+ { 0xc014, 0x40 },
+ { 0xc015, 0x00 },
+ { 0xc016, 0x00 },
+ { 0xc017, 0x00 },
+ { 0xc605, 0x30 },
+ { 0xc700, 0x0a },
+ { 0xc701, 0xaa },
+ { 0xc702, 0x1a },
+ { 0xc703, 0x0a },
+ { 0xc710, 0x80 },
+ { 0xc711, 0x00 },
+ { 0xc712, 0x3e },
+ { 0xc713, 0x80 },
+ { 0xc714, 0x80 },
+ { 0xc715, 0x06 },
+ { 0xd101, 0x00 },
+ { 0xd102, 0x30 },
+ { 0xd103, 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_XU24, RT1316_SDCA_CTL_BYPASS, 0), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE23, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE22, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE24, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+};
+
+static const struct reg_sequence rt1316_blind_write[] = {
+ { 0xc710, 0x17 },
+ { 0xc711, 0x80 },
+ { 0xc712, 0x26 },
+ { 0xc713, 0x06 },
+ { 0xc714, 0x80 },
+ { 0xc715, 0x06 },
+ { 0xc702, 0x0a },
+ { 0xc703, 0x0a },
+ { 0xc001, 0x45 },
+ { 0xc003, 0x00 },
+ { 0xc004, 0x11 },
+ { 0xc005, 0x00 },
+ { 0xc006, 0x00 },
+ { 0xc106, 0x00 },
+ { 0xc007, 0x11 },
+ { 0xc008, 0x11 },
+ { 0xc009, 0x00 },
+
+ { 0x2f0a, 0x00 },
+ { 0xd101, 0xf0 },
+ { 0xd103, 0x9b },
+ { 0x2f36, 0x8e },
+ { 0x3206, 0x80 },
+ { 0x3211, 0x0b },
+ { 0x3216, 0x06 },
+ { 0xc614, 0x20 },
+ { 0xc615, 0x0a },
+ { 0xc616, 0x02 },
+ { 0xc617, 0x00 },
+ { 0xc60b, 0x10 },
+ { 0xc60e, 0x05 },
+ { 0xc102, 0x00 },
+ { 0xc090, 0xb0 },
+ { 0xc00f, 0x01 },
+ { 0xc09c, 0x7b },
+
+ { 0xc602, 0x07 },
+ { 0xc603, 0x07 },
+ { 0xc0a3, 0x71 },
+ { 0xc00b, 0x30 },
+ { 0xc093, 0x80 },
+ { 0xc09d, 0x80 },
+ { 0xc0b0, 0x77 },
+ { 0xc010, 0xa5 },
+ { 0xc050, 0x83 },
+ { 0x2f55, 0x03 },
+ { 0x3217, 0xb5 },
+ { 0x3202, 0x02 },
+
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_XU24, RT1316_SDCA_CTL_BYPASS, 0), 0x00 },
+
+ /* for IV sense */
+ { 0x2232, 0x80 },
+ { 0xc0b0, 0x77 },
+ { 0xc011, 0x00 },
+ { 0xc020, 0x00 },
+ { 0xc023, 0x00 },
+ { 0x3101, 0x00 },
+ { 0x3004, 0xa0 },
+ { 0x3005, 0xb1 },
+ { 0xc007, 0x11 },
+ { 0xc008, 0x11 },
+ { 0xc009, 0x00 },
+ { 0xc022, 0xd6 },
+ { 0xc025, 0xd6 },
+
+ { 0xd001, 0x03 },
+ { 0xd002, 0xbf },
+ { 0xd003, 0x03 },
+ { 0xd004, 0xbf },
+};
+
+static bool rt1316_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f0a:
+ case 0x2f36:
+ case 0x3203 ... 0x320e:
+ case 0xc000 ... 0xc7b4:
+ case 0xcf00 ... 0xcf03:
+ case 0xd101 ... 0xd103:
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE23, RT1316_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE27, RT1316_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE22, RT1316_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE24, RT1316_SDCA_CTL_REQ_POWER_STATE, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt1316_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0xc000:
+ case 0xc093:
+ case 0xc09d:
+ case 0xc0a3:
+ case 0xc201:
+ case 0xc427 ... 0xc428:
+ case 0xd102:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rt1316_sdw_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt1316_readable_register,
+ .volatile_reg = rt1316_volatile_register,
+ .max_register = 0x4108ffff,
+ .reg_defaults = rt1316_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt1316_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt1316_read_prop(struct sdw_slave *slave)
+{
+ struct sdw_slave_prop *prop = &slave->prop;
+ int nval;
+ int i, j;
+ u32 bit;
+ unsigned long addr;
+ struct sdw_dpn_prop *dpn;
+
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+ prop->is_sdca = true;
+
+ prop->paging_support = true;
+
+ /* first we need to allocate memory for set bits in port lists */
+ prop->source_ports = 0x04; /* BITMAP: 00000100 */
+ prop->sink_ports = 0x2; /* BITMAP: 00000010 */
+
+ nval = hweight32(prop->source_ports);
+ prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->src_dpn_prop), GFP_KERNEL);
+ if (!prop->src_dpn_prop)
+ return -ENOMEM;
+
+ i = 0;
+ dpn = prop->src_dpn_prop;
+ addr = prop->source_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[i].num = bit;
+ dpn[i].type = SDW_DPN_FULL;
+ dpn[i].simple_ch_prep_sm = true;
+ dpn[i].ch_prep_timeout = 10;
+ i++;
+ }
+
+ /* do this again for sink now */
+ nval = hweight32(prop->sink_ports);
+ prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+ if (!prop->sink_dpn_prop)
+ return -ENOMEM;
+
+ j = 0;
+ dpn = prop->sink_dpn_prop;
+ addr = prop->sink_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[j].num = bit;
+ dpn[j].type = SDW_DPN_FULL;
+ dpn[j].simple_ch_prep_sm = true;
+ dpn[j].ch_prep_timeout = 10;
+ j++;
+ }
+
+ /* set the timeout values */
+ prop->clk_stop_timeout = 20;
+
+ dev_dbg(&slave->dev, "%s\n", __func__);
+
+ return 0;
+}
+
+static int rt1316_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev);
+
+ if (rt1316->hw_init)
+ return 0;
+
+ if (rt1316->first_hw_init) {
+ regcache_cache_only(rt1316->regmap, false);
+ regcache_cache_bypass(rt1316->regmap, true);
+ } else {
+ /*
+ * PM runtime is only enabled when a Slave reports as Attached
+ */
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
+ pm_runtime_use_autosuspend(&slave->dev);
+
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(&slave->dev);
+
+ pm_runtime_enable(&slave->dev);
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+
+ /* sw reset */
+ regmap_write(rt1316->regmap, 0xc000, 0x02);
+
+ /* initial settings - blind write */
+ regmap_multi_reg_write(rt1316->regmap, rt1316_blind_write,
+ ARRAY_SIZE(rt1316_blind_write));
+
+ if (rt1316->first_hw_init) {
+ regcache_cache_bypass(rt1316->regmap, false);
+ regcache_mark_dirty(rt1316->regmap);
+ } else
+ rt1316->first_hw_init = true;
+
+ /* Mark Slave initialization complete */
+ rt1316->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 rt1316_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev);
+
+ /* Update the status */
+ rt1316->status = status;
+
+ if (status == SDW_SLAVE_UNATTACHED)
+ rt1316->hw_init = false;
+
+ /*
+ * Perform initialization only if slave status is present and
+ * hw_init flag is false
+ */
+ if (rt1316->hw_init || rt1316->status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt1316_io_init(&slave->dev, slave);
+}
+
+static int rt1316_classd_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt1316_sdw_priv *rt1316 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt1316->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE23,
+ RT1316_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ regmap_write(rt1316->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE27,
+ RT1316_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ regmap_write(rt1316->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE22,
+ RT1316_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt1316->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE23,
+ RT1316_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ regmap_write(rt1316->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE27,
+ RT1316_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ regmap_write(rt1316->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE22,
+ RT1316_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int rt1316_pde24_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 rt1316_sdw_priv *rt1316 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt1316->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE24,
+ RT1316_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt1316->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE24,
+ RT1316_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ break;
+ }
+ return 0;
+}
+
+static const char * const rt1316_rx_data_ch_select[] = {
+ "L,R",
+ "L,L",
+ "L,R",
+ "L,L+R",
+ "R,L",
+ "R,R",
+ "R,L+R",
+ "L+R,L",
+ "L+R,R",
+ "L+R,L+R",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1316_rx_data_ch_enum,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0,
+ rt1316_rx_data_ch_select);
+
+static const struct snd_kcontrol_new rt1316_snd_controls[] = {
+
+ /* I2S Data Channel Selection */
+ SOC_ENUM("RX Channel Select", rt1316_rx_data_ch_enum),
+
+ /* XU24 Bypass Control */
+ SOC_SINGLE("XU24 Bypass Switch",
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_XU24, RT1316_SDCA_CTL_BYPASS, 0), 0, 1, 0),
+
+ /* Left/Right IV tag */
+ SOC_SINGLE("Left V Tag Select", 0x3004, 0, 7, 0),
+ SOC_SINGLE("Left I Tag Select", 0x3004, 4, 7, 0),
+ SOC_SINGLE("Right V Tag Select", 0x3005, 0, 7, 0),
+ SOC_SINGLE("Right I Tag Select", 0x3005, 4, 7, 0),
+
+ /* IV mixer Control */
+ SOC_DOUBLE("Isense Mixer Switch", 0xc605, 2, 0, 1, 1),
+ SOC_DOUBLE("Vsense Mixer Switch", 0xc605, 3, 1, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt1316_sto_dac =
+ SOC_DAPM_DOUBLE_R("Switch",
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_R),
+ 0, 1, 1);
+
+static const struct snd_soc_dapm_widget rt1316_dapm_widgets[] = {
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Digital Interface */
+ SND_SOC_DAPM_SWITCH("DAC", SND_SOC_NOPM, 0, 0, &rt1316_sto_dac),
+
+ /* Output Lines */
+ SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0,
+ rt1316_classd_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_OUTPUT("SPOL"),
+ SND_SOC_DAPM_OUTPUT("SPOR"),
+
+ SND_SOC_DAPM_SUPPLY("PDE 24", SND_SOC_NOPM, 0, 0,
+ rt1316_pde24_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA("I Sense", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("V Sense", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SIGGEN("I Gen"),
+ SND_SOC_DAPM_SIGGEN("V Gen"),
+};
+
+static const struct snd_soc_dapm_route rt1316_dapm_routes[] = {
+ { "DAC", "Switch", "DP1RX" },
+ { "CLASS D", NULL, "DAC" },
+ { "SPOL", NULL, "CLASS D" },
+ { "SPOR", NULL, "CLASS D" },
+
+ { "I Sense", NULL, "I Gen" },
+ { "V Sense", NULL, "V Gen" },
+ { "I Sense", NULL, "PDE 24" },
+ { "V Sense", NULL, "PDE 24" },
+ { "DP2TX", NULL, "I Sense" },
+ { "DP2TX", NULL, "V Sense" },
+};
+
+static int rt1316_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+ int direction)
+{
+ struct sdw_stream_data *stream;
+
+ if (!sdw_stream)
+ return 0;
+
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (!stream)
+ return -ENOMEM;
+
+ stream->sdw_stream = sdw_stream;
+
+ /* Use tx_mask or rx_mask to configure stream tag and set dma_data */
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ dai->playback_dma_data = stream;
+ else
+ dai->capture_dma_data = stream;
+
+ return 0;
+}
+
+static void rt1316_sdw_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct sdw_stream_data *stream;
+
+ stream = snd_soc_dai_get_dma_data(dai, substream);
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+ kfree(stream);
+}
+
+static int rt1316_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 rt1316_sdw_priv *rt1316 =
+ snd_soc_component_get_drvdata(component);
+ struct sdw_stream_config stream_config;
+ struct sdw_port_config port_config;
+ enum sdw_data_direction direction;
+ struct sdw_stream_data *stream;
+ int retval, port, num_channels, ch_mask;
+
+ dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+ stream = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!stream)
+ return -EINVAL;
+
+ if (!rt1316->sdw_slave)
+ return -EINVAL;
+
+ /* SoundWire specific configuration */
+ /* port 1 for playback */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ direction = SDW_DATA_DIR_RX;
+ port = 1;
+ } else {
+ direction = SDW_DATA_DIR_TX;
+ port = 2;
+ }
+
+ num_channels = params_channels(params);
+ ch_mask = (1 << num_channels) - 1;
+
+ stream_config.frame_rate = params_rate(params);
+ stream_config.ch_count = num_channels;
+ stream_config.bps = snd_pcm_format_width(params_format(params));
+ stream_config.direction = direction;
+
+ port_config.ch_mask = ch_mask;
+ port_config.num = port;
+
+ retval = sdw_stream_add_slave(rt1316->sdw_slave, &stream_config,
+ &port_config, 1, stream->sdw_stream);
+ if (retval) {
+ dev_err(dai->dev, "Unable to configure port\n");
+ return retval;
+ }
+
+ return 0;
+}
+
+static int rt1316_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1316_sdw_priv *rt1316 =
+ snd_soc_component_get_drvdata(component);
+ struct sdw_stream_data *stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt1316->sdw_slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt1316->sdw_slave, stream->sdw_stream);
+ return 0;
+}
+
+/*
+ * slave_ops: callbacks for get_clock_stop_mode, clock_stop and
+ * port_prep are not defined for now
+ */
+static struct sdw_slave_ops rt1316_slave_ops = {
+ .read_prop = rt1316_read_prop,
+ .update_status = rt1316_update_status,
+};
+
+static const struct snd_soc_component_driver soc_component_sdw_rt1316 = {
+ .controls = rt1316_snd_controls,
+ .num_controls = ARRAY_SIZE(rt1316_snd_controls),
+ .dapm_widgets = rt1316_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt1316_dapm_widgets),
+ .dapm_routes = rt1316_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt1316_dapm_routes),
+};
+
+static const struct snd_soc_dai_ops rt1316_aif_dai_ops = {
+ .hw_params = rt1316_sdw_hw_params,
+ .hw_free = rt1316_sdw_pcm_hw_free,
+ .set_sdw_stream = rt1316_set_sdw_stream,
+ .shutdown = rt1316_sdw_shutdown,
+};
+
+#define RT1316_STEREO_RATES SNDRV_PCM_RATE_48000
+#define RT1316_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver rt1316_sdw_dai[] = {
+ {
+ .name = "rt1316-aif",
+ .playback = {
+ .stream_name = "DP1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT1316_STEREO_RATES,
+ .formats = RT1316_FORMATS,
+ },
+ .capture = {
+ .stream_name = "DP2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT1316_STEREO_RATES,
+ .formats = RT1316_FORMATS,
+ },
+ .ops = &rt1316_aif_dai_ops,
+ },
+};
+
+static int rt1316_sdw_init(struct device *dev, struct regmap *regmap,
+ struct sdw_slave *slave)
+{
+ struct rt1316_sdw_priv *rt1316;
+ int ret;
+
+ rt1316 = devm_kzalloc(dev, sizeof(*rt1316), GFP_KERNEL);
+ if (!rt1316)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt1316);
+ rt1316->sdw_slave = slave;
+ rt1316->regmap = regmap;
+
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt1316->hw_init = false;
+ rt1316->first_hw_init = false;
+
+ ret = devm_snd_soc_register_component(dev,
+ &soc_component_sdw_rt1316,
+ rt1316_sdw_dai,
+ ARRAY_SIZE(rt1316_sdw_dai));
+
+ dev_dbg(&slave->dev, "%s\n", __func__);
+
+ return ret;
+}
+
+static int rt1316_sdw_probe(struct sdw_slave *slave,
+ const struct sdw_device_id *id)
+{
+ struct regmap *regmap;
+
+ /* Regmap Initialization */
+ regmap = devm_regmap_init_sdw(slave, &rt1316_sdw_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt1316_sdw_init(&slave->dev, regmap, slave);
+}
+
+static const struct sdw_device_id rt1316_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x1316, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt1316_id);
+
+static int __maybe_unused rt1316_dev_suspend(struct device *dev)
+{
+ struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev);
+
+ if (!rt1316->hw_init)
+ return 0;
+
+ regcache_cache_only(rt1316->regmap, true);
+
+ return 0;
+}
+
+#define RT1316_PROBE_TIMEOUT 5000
+
+static int __maybe_unused rt1316_dev_resume(struct device *dev)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev);
+ unsigned long time;
+
+ if (!rt1316->hw_init)
+ return 0;
+
+ if (!slave->unattach_request)
+ goto regmap_sync;
+
+ time = wait_for_completion_timeout(&slave->initialization_complete,
+ msecs_to_jiffies(RT1316_PROBE_TIMEOUT));
+ if (!time) {
+ dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ return -ETIMEDOUT;
+ }
+
+regmap_sync:
+ slave->unattach_request = 0;
+ regcache_cache_only(rt1316->regmap, false);
+ regcache_sync(rt1316->regmap);
+
+ return 0;
+}
+
+static const struct dev_pm_ops rt1316_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rt1316_dev_suspend, rt1316_dev_resume)
+ SET_RUNTIME_PM_OPS(rt1316_dev_suspend, rt1316_dev_resume, NULL)
+};
+
+static struct sdw_driver rt1316_sdw_driver = {
+ .driver = {
+ .name = "rt1316-sdca",
+ .owner = THIS_MODULE,
+ .pm = &rt1316_pm,
+ },
+ .probe = rt1316_sdw_probe,
+ .ops = &rt1316_slave_ops,
+ .id_table = rt1316_id,
+};
+module_sdw_driver(rt1316_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT1316 driver SDCA SDW");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt1316-sdw.h b/sound/soc/codecs/rt1316-sdw.h
new file mode 100644
index 000000000000..cbcdaa8f8cfa
--- /dev/null
+++ b/sound/soc/codecs/rt1316-sdw.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt1316-sdw.h -- RT1316 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2021 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT1316_SDW_H__
+#define __RT1316_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>
+
+/* RT1316 SDCA Control - function number */
+#define FUNC_NUM_SMART_AMP 0x04
+
+/* RT1316 SDCA entity */
+#define RT1316_SDCA_ENT_PDE23 0x31
+#define RT1316_SDCA_ENT_PDE27 0x32
+#define RT1316_SDCA_ENT_PDE22 0x33
+#define RT1316_SDCA_ENT_PDE24 0x34
+#define RT1316_SDCA_ENT_XU24 0x24
+#define RT1316_SDCA_ENT_FU21 0x03
+#define RT1316_SDCA_ENT_UDMPU21 0x02
+
+/* RT1316 SDCA control */
+#define RT1316_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10
+#define RT1316_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT1316_SDCA_CTL_BYPASS 0x01
+#define RT1316_SDCA_CTL_FU_MUTE 0x01
+#define RT1316_SDCA_CTL_FU_VOLUME 0x02
+#define RT1316_SDCA_CTL_UDMPU_CLUSTER 0x10
+
+/* RT1316 SDCA channel */
+#define CH_L 0x01
+#define CH_R 0x02
+
+struct rt1316_sdw_priv {
+ struct snd_soc_component *component;
+ struct regmap *regmap;
+ struct sdw_slave *sdw_slave;
+ enum sdw_slave_status status;
+ struct sdw_bus_params params;
+ bool hw_init;
+ bool first_hw_init;
+};
+
+struct sdw_stream_data {
+ struct sdw_stream_runtime *sdw_stream;
+};
+
+#endif /* __RT1316_SDW_H__ */
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index e16e7237156f..802f4851c3df 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -255,11 +255,16 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
msleep(300);
regmap_read(rt286->regmap,
RT286_CBJ_CTRL2, &val);
- if (0x0070 == (val & 0x0070))
+ if (0x0070 == (val & 0x0070)) {
*mic = true;
- else
+ } else {
*mic = false;
+ regmap_update_bits(rt286->regmap,
+ RT286_CBJ_CTRL1,
+ 0xfcc0, 0xc400);
+ }
}
+
regmap_update_bits(rt286->regmap,
RT286_DC_GAIN, 0x200, 0x0);
@@ -1120,12 +1125,11 @@ static const struct dmi_system_id force_combo_jack_table[] = {
{ }
};
-static const struct dmi_system_id dmi_dell_dino[] = {
+static const struct dmi_system_id dmi_dell[] = {
{
- .ident = "Dell Dino",
+ .ident = "Dell",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343")
}
},
{ }
@@ -1136,7 +1140,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
{
struct rt286_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt286_priv *rt286;
- int i, ret, val;
+ int i, ret, vendor_id;
rt286 = devm_kzalloc(&i2c->dev, sizeof(*rt286),
GFP_KERNEL);
@@ -1152,14 +1156,15 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
}
ret = regmap_read(rt286->regmap,
- RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &val);
+ RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &vendor_id);
if (ret != 0) {
dev_err(&i2c->dev, "I2C error %d\n", ret);
return ret;
}
- if (val != RT286_VENDOR_ID && val != RT288_VENDOR_ID) {
+ if (vendor_id != RT286_VENDOR_ID && vendor_id != RT288_VENDOR_ID) {
dev_err(&i2c->dev,
- "Device with ID register %#x is not rt286\n", val);
+ "Device with ID register %#x is not rt286\n",
+ vendor_id);
return -ENODEV;
}
@@ -1183,8 +1188,8 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
if (pdata)
rt286->pdata = *pdata;
- if (dmi_check_system(force_combo_jack_table) ||
- dmi_check_system(dmi_dell_dino))
+ if ((vendor_id == RT288_VENDOR_ID && dmi_check_system(dmi_dell)) ||
+ dmi_check_system(force_combo_jack_table))
rt286->pdata.cbj_en = true;
regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3);
@@ -1223,7 +1228,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737);
regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f);
- if (dmi_check_system(dmi_dell_dino)) {
+ if (vendor_id == RT288_VENDOR_ID && dmi_check_system(dmi_dell)) {
regmap_update_bits(rt286->regmap,
RT286_SET_GPIO_MASK, 0x40, 0x40);
regmap_update_bits(rt286->regmap,
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index 32cc9b6287d2..c592c40a7ab3 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -267,11 +267,16 @@ static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic)
msleep(300);
regmap_read(rt298->regmap,
RT298_CBJ_CTRL2, &val);
- if (0x0070 == (val & 0x0070))
+ if (0x0070 == (val & 0x0070)) {
*mic = true;
- else
+ } else {
*mic = false;
+ regmap_update_bits(rt298->regmap,
+ RT298_CBJ_CTRL1,
+ 0xfcc0, 0xc400);
+ }
}
+
regmap_update_bits(rt298->regmap,
RT298_DC_GAIN, 0x200, 0x0);
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 653da3eaf355..3000bc128b5b 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -436,7 +436,7 @@ static void onebit_depop_mute_stage(struct snd_soc_component *component, int ena
}
/**
- * onebit_depop_power_stage - step by step depop sequence in power stage.
+ * depop_seq_power_stage - step by step depop sequence in power stage.
* @component: ASoC component
* @enable: power on/off
*
@@ -1283,7 +1283,7 @@ static const struct pll_div codec_slave_pll_div[] = {
{3072000, 12288000, 0x0a90},
};
-static struct coeff_clk_div coeff_div[] = {
+static const struct coeff_clk_div coeff_div[] = {
/* sysclk is 256fs */
{2048000, 8000 * 32, 8000, 0x1000},
{2048000, 8000 * 64, 8000, 0x0000},
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index a5674c227b3a..9523f4b5c800 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -400,6 +400,9 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {
/* DAC Digital Volume */
SOC_DOUBLE("DAC2 Playback Switch", RT5640_DAC2_CTRL,
RT5640_M_DAC_L2_VOL_SFT, RT5640_M_DAC_R2_VOL_SFT, 1, 1),
+ SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5640_DAC2_DIG_VOL,
+ RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
+ 175, 0, dac_vol_tlv),
SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5640_DAC1_DIG_VOL,
RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
175, 0, dac_vol_tlv),
@@ -443,9 +446,6 @@ static const struct snd_kcontrol_new rt5640_specific_snd_controls[] = {
/* MONO Output Control */
SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT, RT5640_L_MUTE_SFT,
1, 1),
-
- SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL,
- RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 175, 0, dac_vol_tlv),
};
/**
@@ -1918,10 +1918,10 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
pll_code.n_code, pll_code.k_code);
snd_soc_component_write(component, RT5640_PLL_CTRL1,
- pll_code.n_code << RT5640_PLL_N_SFT | pll_code.k_code);
+ (pll_code.n_code << RT5640_PLL_N_SFT) | pll_code.k_code);
snd_soc_component_write(component, RT5640_PLL_CTRL2,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT5640_PLL_M_SFT |
- pll_code.m_bp << RT5640_PLL_M_BP_SFT);
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5640_PLL_M_SFT) |
+ (pll_code.m_bp << RT5640_PLL_M_BP_SFT));
rt5640->pll_in = freq_in;
rt5640->pll_out = freq_out;
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 63a7e052eaa0..9408ee63cb26 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -411,6 +411,30 @@ static const char *const rt5645_supply_names[] = {
"cpvdd",
};
+struct rt5645_platform_data {
+ /* IN2 can optionally be differential */
+ bool in2_diff;
+
+ unsigned int dmic1_data_pin;
+ /* 0 = IN2N; 1 = GPIO5; 2 = GPIO11 */
+ unsigned int dmic2_data_pin;
+ /* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */
+
+ unsigned int jd_mode;
+ /* Use level triggered irq */
+ bool level_trigger_irq;
+ /* Invert JD1_1 status polarity */
+ bool inv_jd1_1;
+ /* Invert HP detect status polarity */
+ bool inv_hp_pol;
+
+ /* Value to assign to snd_soc_card.long_name */
+ const char *long_name;
+
+ /* Some (package) variants have the headset-mic pin not-connected */
+ bool no_headset_mic;
+};
+
struct rt5645_priv {
struct snd_soc_component *component;
struct rt5645_platform_data pdata;
@@ -690,7 +714,7 @@ static int rt5645_hweq_get(struct snd_kcontrol *kcontrol,
static bool rt5645_validate_hweq(unsigned short reg)
{
- if ((reg >= 0x1a4 && reg <= 0x1cd) | (reg >= 0x1e5 && reg <= 0x1f8) |
+ if ((reg >= 0x1a4 && reg <= 0x1cd) || (reg >= 0x1e5 && reg <= 0x1f8) ||
(reg == RT5645_EQ_CTRL2))
return true;
@@ -2956,8 +2980,8 @@ static int rt5645_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
snd_soc_component_write(component, RT5645_PLL_CTRL1,
pll_code.n_code << RT5645_PLL_N_SFT | pll_code.k_code);
snd_soc_component_write(component, RT5645_PLL_CTRL2,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT5645_PLL_M_SFT |
- pll_code.m_bp << RT5645_PLL_M_BP_SFT);
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5645_PLL_M_SFT) |
+ (pll_code.m_bp << RT5645_PLL_M_BP_SFT));
rt5645->pll_in = freq_in;
rt5645->pll_out = freq_out;
@@ -3159,7 +3183,7 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse
val &= 0x7;
dev_dbg(component->dev, "val = %d\n", val);
- if (val == 1 || val == 2) {
+ if ((val == 1 || val == 2) && !rt5645->pdata.no_headset_mic) {
rt5645->jack_type = SND_JACK_HEADSET;
if (rt5645->en_button_func) {
rt5645_enable_push_button_irq(component, true);
@@ -3834,7 +3858,7 @@ static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev)
static int rt5645_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- struct rt5645_platform_data *pdata = dev_get_platdata(&i2c->dev);
+ struct rt5645_platform_data *pdata = NULL;
const struct dmi_system_id *dmi_data;
struct rt5645_priv *rt5645;
int ret, i;
@@ -3872,9 +3896,16 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
rt5645->pdata.dmic2_data_pin = QUIRK_DMIC2_DATA_PIN(quirk);
}
- if (cht_rt5645_gpios && has_acpi_companion(&i2c->dev))
- if (devm_acpi_dev_add_driver_gpios(&i2c->dev, cht_rt5645_gpios))
- dev_dbg(&i2c->dev, "Failed to add driver gpios\n");
+ if (has_acpi_companion(&i2c->dev)) {
+ if (cht_rt5645_gpios) {
+ if (devm_acpi_dev_add_driver_gpios(&i2c->dev, cht_rt5645_gpios))
+ dev_dbg(&i2c->dev, "Failed to add driver gpios\n");
+ }
+
+ /* The ALC3270 package has the headset-mic pin not-connected */
+ if (acpi_dev_hid_uid_match(ACPI_COMPANION(&i2c->dev), "10EC3270", NULL))
+ rt5645->pdata.no_headset_mic = true;
+ }
rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect",
GPIOD_IN);
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
index e2d72ae17484..ac3de6f3bc2f 100644
--- a/sound/soc/codecs/rt5645.h
+++ b/sound/soc/codecs/rt5645.h
@@ -9,8 +9,6 @@
#ifndef __RT5645_H__
#define __RT5645_H__
-#include <sound/rt5645.h>
-
/* Info */
#define RT5645_RESET 0x00
#define RT5645_VENDOR_ID 0xfd
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index e59fdc81dbd4..fc0c83b73f09 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -1498,8 +1498,8 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
snd_soc_component_write(component, RT5651_PLL_CTRL1,
pll_code.n_code << RT5651_PLL_N_SFT | pll_code.k_code);
snd_soc_component_write(component, RT5651_PLL_CTRL2,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT5651_PLL_M_SFT |
- pll_code.m_bp << RT5651_PLL_M_BP_SFT);
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5651_PLL_M_SFT) |
+ (pll_code.m_bp << RT5651_PLL_M_BP_SFT));
rt5651->pll_in = freq_in;
rt5651->pll_out = freq_out;
@@ -1783,7 +1783,7 @@ static void rt5651_jack_detect_work(struct work_struct *work)
struct rt5651_priv *rt5651 =
container_of(work, struct rt5651_priv, jack_detect_work);
struct snd_soc_component *component = rt5651->component;
- int report = 0;
+ int report;
if (!rt5651_jack_inserted(component)) {
/* Jack removed, or spurious IRQ? */
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
index 91a4ef7f620c..87f5709fe2cc 100644
--- a/sound/soc/codecs/rt5659.c
+++ b/sound/soc/codecs/rt5659.c
@@ -3517,8 +3517,8 @@ static int rt5659_set_component_pll(struct snd_soc_component *component, int pll
snd_soc_component_write(component, RT5659_PLL_CTRL_1,
pll_code.n_code << RT5659_PLL_N_SFT | pll_code.k_code);
snd_soc_component_write(component, RT5659_PLL_CTRL_2,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT5659_PLL_M_SFT |
- pll_code.m_bp << RT5659_PLL_M_BP_SFT);
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5659_PLL_M_SFT) |
+ (pll_code.m_bp << RT5659_PLL_M_BP_SFT));
rt5659->pll_in = freq_in;
rt5659->pll_out = freq_out;
diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c
index 0edf09d3a499..33ff9156358b 100644
--- a/sound/soc/codecs/rt5660.c
+++ b/sound/soc/codecs/rt5660.c
@@ -1057,8 +1057,8 @@ static int rt5660_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
snd_soc_component_write(component, RT5660_PLL_CTRL1,
pll_code.n_code << RT5660_PLL_N_SFT | pll_code.k_code);
snd_soc_component_write(component, RT5660_PLL_CTRL2,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT5660_PLL_M_SFT |
- pll_code.m_bp << RT5660_PLL_M_BP_SFT);
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5660_PLL_M_SFT) |
+ (pll_code.m_bp << RT5660_PLL_M_BP_SFT));
rt5660->pll_in = freq_in;
rt5660->pll_out = freq_out;
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index 619fb9a031e3..be9fc58ff681 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -2952,8 +2952,8 @@ static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
snd_soc_component_write(component, RT5663_PLL_1,
pll_code.n_code << RT5663_PLL_N_SHIFT | pll_code.k_code);
snd_soc_component_write(component, RT5663_PLL_2,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT5663_PLL_M_SHIFT |
- pll_code.m_bp << RT5663_PLL_M_BP_SHIFT);
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5663_PLL_M_SHIFT) |
+ (pll_code.m_bp << RT5663_PLL_M_BP_SHIFT));
rt5663->pll_in = freq_in;
rt5663->pll_out = freq_out;
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index 8a915cdce0fe..e59323fd5bf2 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -4385,8 +4385,8 @@ static int rt5665_set_component_pll(struct snd_soc_component *component, int pll
snd_soc_component_write(component, RT5665_PLL_CTRL_1,
pll_code.n_code << RT5665_PLL_N_SFT | pll_code.k_code);
snd_soc_component_write(component, RT5665_PLL_CTRL_2,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT5665_PLL_M_SFT |
- pll_code.m_bp << RT5665_PLL_M_BP_SFT);
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5665_PLL_M_SFT) |
+ (pll_code.m_bp << RT5665_PLL_M_BP_SFT));
rt5665->pll_in = freq_in;
rt5665->pll_out = freq_out;
diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c
index bc69adc9c8b7..6ab1a8bc3735 100644
--- a/sound/soc/codecs/rt5668.c
+++ b/sound/soc/codecs/rt5668.c
@@ -1171,7 +1171,7 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
- int idx = -EINVAL;
+ int idx;
static const int div[] = {2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128};
idx = rt5668_div_sel(rt5668, 1500000, div, ARRAY_SIZE(div));
@@ -1188,7 +1188,7 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
- int ref, val, reg, idx = -EINVAL;
+ int ref, val, reg, idx;
static const int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48};
val = snd_soc_component_read(component, RT5668_GPIO_CTRL_1) &
@@ -2182,8 +2182,8 @@ static int rt5668_set_component_pll(struct snd_soc_component *component,
snd_soc_component_write(component, RT5668_PLL_CTRL_1,
pll_code.n_code << RT5668_PLL_N_SFT | pll_code.k_code);
snd_soc_component_write(component, RT5668_PLL_CTRL_2,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT5668_PLL_M_SFT |
- pll_code.m_bp << RT5668_PLL_M_BP_SFT);
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5668_PLL_M_SFT) |
+ (pll_code.m_bp << RT5668_PLL_M_BP_SFT));
rt5668->pll_in = freq_in;
rt5668->pll_out = freq_out;
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index 4063aac2a443..ecbaf129a6e3 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -2588,8 +2588,8 @@ static int rt5670_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
snd_soc_component_write(component, RT5670_PLL_CTRL1,
pll_code.n_code << RT5670_PLL_N_SFT | pll_code.k_code);
snd_soc_component_write(component, RT5670_PLL_CTRL2,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT5670_PLL_M_SFT |
- pll_code.m_bp << RT5670_PLL_M_BP_SFT);
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5670_PLL_M_SFT) |
+ (pll_code.m_bp << RT5670_PLL_M_BP_SFT));
rt5670->pll_in = freq_in;
rt5670->pll_out = freq_out;
@@ -2982,6 +2982,18 @@ static const struct dmi_system_id dmi_platform_intel_quirks[] = {
},
{
.callback = rt5670_quirk_cb,
+ .ident = "Dell Venue 10 Pro 5055",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Venue 10 Pro 5055"),
+ },
+ .driver_data = (unsigned long *)(RT5670_DMIC_EN |
+ RT5670_DMIC2_INR |
+ RT5670_GPIO1_IS_IRQ |
+ RT5670_JD_MODE1),
+ },
+ {
+ .callback = rt5670_quirk_cb,
.ident = "Aegex 10 tablet (RU2)",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "AEGEX"),
@@ -2995,6 +3007,45 @@ static const struct dmi_system_id dmi_platform_intel_quirks[] = {
{}
};
+const char *rt5670_components(void)
+{
+ unsigned long quirk;
+ bool dmic1 = false;
+ bool dmic2 = false;
+ bool dmic3 = false;
+
+ if (quirk_override) {
+ quirk = quirk_override;
+ } else {
+ dmi_check_system(dmi_platform_intel_quirks);
+ quirk = rt5670_quirk;
+ }
+
+ if ((quirk & RT5670_DMIC1_IN2P) ||
+ (quirk & RT5670_DMIC1_GPIO6) ||
+ (quirk & RT5670_DMIC1_GPIO7))
+ dmic1 = true;
+
+ if ((quirk & RT5670_DMIC2_INR) ||
+ (quirk & RT5670_DMIC2_GPIO8))
+ dmic2 = true;
+
+ if (quirk & RT5670_DMIC3_GPIO5)
+ dmic3 = true;
+
+ if (dmic1 && dmic2)
+ return "cfg-spk:2 cfg-mic:dmics12";
+ else if (dmic1)
+ return "cfg-spk:2 cfg-mic:dmic1";
+ else if (dmic2)
+ return "cfg-spk:2 cfg-mic:dmic2";
+ else if (dmic3)
+ return "cfg-spk:2 cfg-mic:dmic3";
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(rt5670_components);
+
static int rt5670_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h
index 6fb3c369ee98..5b230897f630 100644
--- a/sound/soc/codecs/rt5670.h
+++ b/sound/soc/codecs/rt5670.h
@@ -2024,4 +2024,6 @@ void rt5670_jack_suspend(struct snd_soc_component *component);
void rt5670_jack_resume(struct snd_soc_component *component);
int rt5670_set_jack_detect(struct snd_soc_component *component,
struct snd_soc_jack *jack);
+const char *rt5670_components(void);
+
#endif /* __RT5670_H__ */
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 9e449d35fc28..f655228c8c4b 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -4568,8 +4568,8 @@ static int rt5677_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
regmap_write(rt5677->regmap, RT5677_PLL1_CTRL1,
pll_code.n_code << RT5677_PLL_N_SFT | pll_code.k_code);
regmap_write(rt5677->regmap, RT5677_PLL1_CTRL2,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT5677_PLL_M_SFT |
- pll_code.m_bp << RT5677_PLL_M_BP_SFT);
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5677_PLL_M_SFT) |
+ (pll_code.m_bp << RT5677_PLL_M_BP_SFT));
rt5677->pll_in = freq_in;
rt5677->pll_out = freq_out;
@@ -5332,7 +5332,7 @@ static bool rt5677_check_hotword(struct rt5677_priv *rt5677)
static irqreturn_t rt5677_irq(int unused, void *data)
{
struct rt5677_priv *rt5677 = data;
- int ret = 0, loop, i, reg_irq, virq;
+ int ret, loop, i, reg_irq, virq;
bool irq_fired = false;
mutex_lock(&rt5677->irq_lock);
diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c
index 93c1603b42f1..8ea9f1d9fec0 100644
--- a/sound/soc/codecs/rt5682-i2c.c
+++ b/sound/soc/codecs/rt5682-i2c.c
@@ -78,7 +78,7 @@ static irqreturn_t rt5682_irq(int irq, void *data)
struct rt5682_priv *rt5682 = data;
mod_delayed_work(system_power_efficient_wq,
- &rt5682->jack_detect_work, msecs_to_jiffies(250));
+ &rt5682->jack_detect_work, msecs_to_jiffies(rt5682->irq_work_delay_time));
return IRQ_HANDLED;
}
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index b49f1e16125d..fed80c8f994f 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -269,7 +269,7 @@ static int rt5682_sdw_hw_free(struct snd_pcm_substream *substream,
return 0;
}
-static struct snd_soc_dai_ops rt5682_sdw_ops = {
+static const struct snd_soc_dai_ops rt5682_sdw_ops = {
.hw_params = rt5682_sdw_hw_params,
.hw_free = rt5682_sdw_hw_free,
.set_sdw_stream = rt5682_set_sdw_stream,
@@ -677,13 +677,13 @@ static int rt5682_interrupt_callback(struct sdw_slave *slave,
if (status->control_port & 0x4) {
mod_delayed_work(system_power_efficient_wq,
- &rt5682->jack_detect_work, msecs_to_jiffies(250));
+ &rt5682->jack_detect_work, msecs_to_jiffies(rt5682->irq_work_delay_time));
}
return 0;
}
-static struct sdw_slave_ops rt5682_slave_ops = {
+static const struct sdw_slave_ops rt5682_slave_ops = {
.read_prop = rt5682_read_prop,
.interrupt_callback = rt5682_interrupt_callback,
.update_status = rt5682_update_status,
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index b306ac4b9b2e..e4c91571abae 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -1094,6 +1094,7 @@ void rt5682_jack_detect_handler(struct work_struct *work)
/* jack was out, report jack type */
rt5682->jack_type =
rt5682_headset_detect(rt5682->component, 1);
+ rt5682->irq_work_delay_time = 0;
} else if ((rt5682->jack_type & SND_JACK_HEADSET) ==
SND_JACK_HEADSET) {
/* jack is already in, report button event */
@@ -1139,6 +1140,7 @@ void rt5682_jack_detect_handler(struct work_struct *work)
} else {
/* jack out */
rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
+ rt5682->irq_work_delay_time = 50;
}
snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
@@ -1225,7 +1227,7 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
- int idx = -EINVAL, dmic_clk_rate = 3072000;
+ int idx, dmic_clk_rate = 3072000;
static const int div[] = {2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128};
if (rt5682->pdata.dmic_clk_rate)
@@ -1245,7 +1247,7 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
- int ref, val, reg, idx = -EINVAL;
+ int ref, val, reg, idx;
static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48};
static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48};
@@ -2396,10 +2398,10 @@ static int rt5682_set_component_pll(struct snd_soc_component *component,
pll_code.n_code, pll_code.k_code);
snd_soc_component_write(component, RT5682_PLL_CTRL_1,
- pll_code.n_code << RT5682_PLL_N_SFT | pll_code.k_code);
+ (pll_code.n_code << RT5682_PLL_N_SFT) | pll_code.k_code);
snd_soc_component_write(component, RT5682_PLL_CTRL_2,
- (pll_code.m_bp ? 0 : pll_code.m_code) << RT5682_PLL_M_SFT |
- pll_code.m_bp << RT5682_PLL_M_BP_SFT | RT5682_PLL_RST);
+ ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5682_PLL_M_SFT) |
+ ((pll_code.m_bp << RT5682_PLL_M_BP_SFT) | RT5682_PLL_RST));
}
rt5682->pll_in[pll_id] = freq_in;
@@ -2632,7 +2634,7 @@ static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate,
container_of(hw, struct rt5682_priv,
dai_clks_hw[RT5682_DAI_WCLK_IDX]);
struct snd_soc_component *component = rt5682->component;
- struct clk *parent_clk;
+ struct clk_hw *parent_hw;
const char * const clk_name = clk_hw_get_name(hw);
int pre_div;
unsigned int clk_pll2_out;
@@ -2647,8 +2649,8 @@ static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate,
*
* It will set the codec anyway by assuming mclk is 48MHz.
*/
- parent_clk = clk_get_parent(hw->clk);
- if (!parent_clk)
+ parent_hw = clk_hw_get_parent(hw);
+ if (!parent_hw)
dev_warn(component->dev,
"Parent mclk of wclk not acquired in driver. Please ensure mclk was provided as %d Hz.\n",
CLK_PLL2_FIN);
@@ -2751,7 +2753,7 @@ static int rt5682_bclk_set_rate(struct clk_hw *hw, unsigned long rate,
container_of(hw, struct rt5682_priv,
dai_clks_hw[RT5682_DAI_BCLK_IDX]);
struct snd_soc_component *component = rt5682->component;
- struct snd_soc_dai *dai = NULL;
+ struct snd_soc_dai *dai;
unsigned long factor;
if (!rt5682_clk_check(rt5682))
diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
index 1f9c51a5b9bf..74ff66767016 100644
--- a/sound/soc/codecs/rt5682.h
+++ b/sound/soc/codecs/rt5682.h
@@ -1439,6 +1439,7 @@ struct rt5682_priv {
int pll_out[RT5682_PLLS];
int jack_type;
+ int irq_work_delay_time;
};
extern const char *rt5682_supply_names[RT5682_NUM_SUPPLIES];
diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c
index 4001612dfd73..ff9c081fd52a 100644
--- a/sound/soc/codecs/rt700-sdw.c
+++ b/sound/soc/codecs/rt700-sdw.c
@@ -430,7 +430,7 @@ static int rt700_interrupt_callback(struct sdw_slave *slave,
* slave_ops: callbacks for get_clock_stop_mode, clock_stop and
* port_prep are not defined for now
*/
-static struct sdw_slave_ops rt700_slave_ops = {
+static const struct sdw_slave_ops rt700_slave_ops = {
.read_prop = rt700_read_prop,
.interrupt_callback = rt700_interrupt_callback,
.update_status = rt700_update_status,
diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c
index 66ec395dbbcd..01af9d9dd3ca 100644
--- a/sound/soc/codecs/rt700.c
+++ b/sound/soc/codecs/rt700.c
@@ -1002,7 +1002,7 @@ static int rt700_pcm_hw_free(struct snd_pcm_substream *substream,
#define RT700_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
-static struct snd_soc_dai_ops rt700_ops = {
+static const struct snd_soc_dai_ops rt700_ops = {
.hw_params = rt700_pcm_hw_params,
.hw_free = rt700_pcm_hw_free,
.set_sdw_stream = rt700_set_sdw_stream,
diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c
new file mode 100644
index 000000000000..9685c8905468
--- /dev/null
+++ b/sound/soc/codecs/rt711-sdca-sdw.c
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt711-sdw-sdca.c -- rt711 SDCA ALSA SoC audio driver
+//
+// Copyright(c) 2021 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/module.h>
+
+#include "rt711-sdca.h"
+#include "rt711-sdca-sdw.h"
+
+static bool rt711_sdca_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x201a ... 0x2027:
+ case 0x2029 ... 0x202a:
+ case 0x202d ... 0x2034:
+ case 0x2200 ... 0x2204:
+ case 0x2206 ... 0x2212:
+ case 0x2220 ... 0x2223:
+ case 0x2230 ... 0x2239:
+ case 0x2f01 ... 0x2f0f:
+ case 0x2f30 ... 0x2f36:
+ case 0x2f50 ... 0x2f5a:
+ case 0x2f60:
+ case 0x3200 ... 0x3212:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_SELECTED_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_DETECTED_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ...
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case RT711_BUF_ADDR_HID1 ... RT711_BUF_ADDR_HID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt711_sdca_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x201b:
+ case 0x201c:
+ case 0x201d:
+ case 0x201f:
+ case 0x2021:
+ case 0x2023:
+ case 0x2230:
+ case 0x202d ... 0x202f: /* BRA */
+ case 0x2200 ... 0x2212: /* i2c debug */
+ case RT711_RC_CAL_STATUS:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_DETECTED_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ...
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case RT711_BUF_ADDR_HID1 ... RT711_BUF_ADDR_HID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt711_sdca_mbq_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2000000 ... 0x20000ff:
+ case 0x5600000 ... 0x56000ff:
+ case 0x5700000 ... 0x57000ff:
+ case 0x5800000 ... 0x58000ff:
+ case 0x5900000 ... 0x59000ff:
+ case 0x5b00000 ... 0x5b000ff:
+ case 0x5f00000 ... 0x5f000ff:
+ case 0x6100000 ... 0x61000ff:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt711_sdca_mbq_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2000000:
+ case 0x200001a:
+ case 0x2000046:
+ case 0x2000080:
+ case 0x2000081:
+ case 0x2000083:
+ case 0x5800000:
+ case 0x5800001:
+ case 0x5f00001:
+ case 0x6100008:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rt711_sdca_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt711_sdca_readable_register,
+ .volatile_reg = rt711_sdca_volatile_register,
+ .max_register = 0x44ffffff,
+ .reg_defaults = rt711_sdca_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt711_sdca_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static const struct regmap_config rt711_sdca_mbq_regmap = {
+ .name = "sdw-mbq",
+ .reg_bits = 32,
+ .val_bits = 16,
+ .readable_reg = rt711_sdca_mbq_readable_register,
+ .volatile_reg = rt711_sdca_mbq_volatile_register,
+ .max_register = 0x40800f12,
+ .reg_defaults = rt711_sdca_mbq_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt711_sdca_mbq_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt711_sdca_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt711_sdca_priv *rt711 = dev_get_drvdata(&slave->dev);
+
+ /* Update the status */
+ rt711->status = status;
+
+ if (status == SDW_SLAVE_UNATTACHED)
+ rt711->hw_init = false;
+
+ if (status == SDW_SLAVE_ATTACHED) {
+ if (rt711->hs_jack) {
+ /*
+ * Due to the SCP_SDCA_INTMASK will be cleared by any reset, and then
+ * if the device attached again, we will need to set the setting back.
+ * It could avoid losing the jack detection interrupt.
+ * This also could sync with the cache value as the rt711_sdca_jack_init set.
+ */
+ sdw_write_no_pm(rt711->slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0);
+ sdw_write_no_pm(rt711->slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8);
+ }
+ }
+
+ /*
+ * Perform initialization only if slave status is present and
+ * hw_init flag is false
+ */
+ if (rt711->hw_init || rt711->status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt711_sdca_io_init(&slave->dev, slave);
+}
+
+static int rt711_sdca_read_prop(struct sdw_slave *slave)
+{
+ struct sdw_slave_prop *prop = &slave->prop;
+ int nval;
+ int i, j;
+ u32 bit;
+ unsigned long addr;
+ struct sdw_dpn_prop *dpn;
+
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+ prop->is_sdca = true;
+
+ prop->paging_support = true;
+
+ /* first we need to allocate memory for set bits in port lists */
+ prop->source_ports = 0x14; /* BITMAP: 00010100 */
+ prop->sink_ports = 0x8; /* BITMAP: 00001000 */
+
+ nval = hweight32(prop->source_ports);
+ prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->src_dpn_prop), GFP_KERNEL);
+ if (!prop->src_dpn_prop)
+ return -ENOMEM;
+
+ i = 0;
+ dpn = prop->src_dpn_prop;
+ addr = prop->source_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[i].num = bit;
+ dpn[i].type = SDW_DPN_FULL;
+ dpn[i].simple_ch_prep_sm = true;
+ dpn[i].ch_prep_timeout = 10;
+ i++;
+ }
+
+ /* do this again for sink now */
+ nval = hweight32(prop->sink_ports);
+ prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+ if (!prop->sink_dpn_prop)
+ return -ENOMEM;
+
+ j = 0;
+ dpn = prop->sink_dpn_prop;
+ addr = prop->sink_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[j].num = bit;
+ dpn[j].type = SDW_DPN_FULL;
+ dpn[j].simple_ch_prep_sm = true;
+ dpn[j].ch_prep_timeout = 10;
+ j++;
+ }
+
+ /* set the timeout values */
+ prop->clk_stop_timeout = 20;
+
+ /* wake-up event */
+ prop->wake_capable = 1;
+
+ return 0;
+}
+
+static int rt711_sdca_interrupt_callback(struct sdw_slave *slave,
+ struct sdw_slave_intr_status *status)
+{
+ struct rt711_sdca_priv *rt711 = dev_get_drvdata(&slave->dev);
+ int ret, stat;
+ int count = 0, retry = 3;
+ unsigned int sdca_cascade, scp_sdca_stat1, scp_sdca_stat2 = 0;
+
+ dev_dbg(&slave->dev,
+ "%s control_port_stat=%x, sdca_cascade=%x", __func__,
+ status->control_port, status->sdca_cascade);
+
+ if (cancel_delayed_work_sync(&rt711->jack_detect_work)) {
+ dev_warn(&slave->dev, "%s the pending delayed_work was cancelled", __func__);
+ /* avoid the HID owner doesn't change to device */
+ if (rt711->scp_sdca_stat2)
+ scp_sdca_stat2 = rt711->scp_sdca_stat2;
+ }
+
+ ret = sdw_read_no_pm(rt711->slave, SDW_SCP_SDCA_INT1);
+ if (ret < 0)
+ goto io_error;
+ rt711->scp_sdca_stat1 = ret;
+ ret = sdw_read_no_pm(rt711->slave, SDW_SCP_SDCA_INT2);
+ if (ret < 0)
+ goto io_error;
+ rt711->scp_sdca_stat2 = ret;
+ if (scp_sdca_stat2)
+ rt711->scp_sdca_stat2 |= scp_sdca_stat2;
+
+ do {
+ /* clear flag */
+ ret = sdw_read_no_pm(rt711->slave, SDW_SCP_SDCA_INT1);
+ if (ret < 0)
+ goto io_error;
+ if (ret & SDW_SCP_SDCA_INTMASK_SDCA_0) {
+ ret = sdw_write_no_pm(rt711->slave, SDW_SCP_SDCA_INT1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0);
+ if (ret < 0)
+ goto io_error;
+ }
+ ret = sdw_read_no_pm(rt711->slave, SDW_SCP_SDCA_INT2);
+ if (ret < 0)
+ goto io_error;
+ if (ret & SDW_SCP_SDCA_INTMASK_SDCA_8) {
+ ret = sdw_write_no_pm(rt711->slave, SDW_SCP_SDCA_INT2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8);
+ if (ret < 0)
+ goto io_error;
+ }
+
+ /* check if flag clear or not */
+ ret = sdw_read_no_pm(rt711->slave, SDW_DP0_INT);
+ if (ret < 0)
+ goto io_error;
+ sdca_cascade = ret & SDW_DP0_SDCA_CASCADE;
+
+ ret = sdw_read_no_pm(rt711->slave, SDW_SCP_SDCA_INT1);
+ if (ret < 0)
+ goto io_error;
+ scp_sdca_stat1 = ret & SDW_SCP_SDCA_INTMASK_SDCA_0;
+
+ ret = sdw_read_no_pm(rt711->slave, SDW_SCP_SDCA_INT2);
+ if (ret < 0)
+ goto io_error;
+ scp_sdca_stat2 = ret & SDW_SCP_SDCA_INTMASK_SDCA_8;
+
+ stat = scp_sdca_stat1 || scp_sdca_stat2 || sdca_cascade;
+
+ count++;
+ } while (stat != 0 && count < retry);
+
+ if (stat)
+ dev_warn(&slave->dev,
+ "%s scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__,
+ rt711->scp_sdca_stat1, rt711->scp_sdca_stat2);
+
+ if (status->sdca_cascade)
+ mod_delayed_work(system_power_efficient_wq,
+ &rt711->jack_detect_work, msecs_to_jiffies(30));
+
+ return 0;
+
+io_error:
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+ return ret;
+}
+
+static struct sdw_slave_ops rt711_sdca_slave_ops = {
+ .read_prop = rt711_sdca_read_prop,
+ .interrupt_callback = rt711_sdca_interrupt_callback,
+ .update_status = rt711_sdca_update_status,
+};
+
+static int rt711_sdca_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, &rt711_sdca_mbq_regmap);
+ if (IS_ERR(mbq_regmap))
+ return PTR_ERR(mbq_regmap);
+
+ regmap = devm_regmap_init_sdw(slave, &rt711_sdca_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt711_sdca_init(&slave->dev, regmap, mbq_regmap, slave);
+}
+
+static int rt711_sdca_sdw_remove(struct sdw_slave *slave)
+{
+ struct rt711_sdca_priv *rt711 = dev_get_drvdata(&slave->dev);
+
+ if (rt711 && rt711->hw_init) {
+ cancel_delayed_work_sync(&rt711->jack_detect_work);
+ cancel_delayed_work_sync(&rt711->jack_btn_check_work);
+ }
+
+ return 0;
+}
+
+static const struct sdw_device_id rt711_sdca_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x711, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt711_sdca_id);
+
+static int __maybe_unused rt711_sdca_dev_suspend(struct device *dev)
+{
+ struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev);
+
+ if (!rt711->hw_init)
+ return 0;
+
+ cancel_delayed_work_sync(&rt711->jack_detect_work);
+ cancel_delayed_work_sync(&rt711->jack_btn_check_work);
+
+ regcache_cache_only(rt711->regmap, true);
+ regcache_cache_only(rt711->mbq_regmap, true);
+
+ return 0;
+}
+
+#define RT711_PROBE_TIMEOUT 5000
+
+static int __maybe_unused rt711_sdca_dev_resume(struct device *dev)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev);
+ unsigned long time;
+
+ if (!rt711->hw_init)
+ return 0;
+
+ if (!slave->unattach_request)
+ goto regmap_sync;
+
+ time = wait_for_completion_timeout(&slave->initialization_complete,
+ msecs_to_jiffies(RT711_PROBE_TIMEOUT));
+ if (!time) {
+ dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ return -ETIMEDOUT;
+ }
+
+regmap_sync:
+ slave->unattach_request = 0;
+ regcache_cache_only(rt711->regmap, false);
+ regcache_sync(rt711->regmap);
+ regcache_cache_only(rt711->mbq_regmap, false);
+ regcache_sync(rt711->mbq_regmap);
+ return 0;
+}
+
+static const struct dev_pm_ops rt711_sdca_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rt711_sdca_dev_suspend, rt711_sdca_dev_resume)
+ SET_RUNTIME_PM_OPS(rt711_sdca_dev_suspend, rt711_sdca_dev_resume, NULL)
+};
+
+static struct sdw_driver rt711_sdca_sdw_driver = {
+ .driver = {
+ .name = "rt711-sdca",
+ .owner = THIS_MODULE,
+ .pm = &rt711_sdca_pm,
+ },
+ .probe = rt711_sdca_sdw_probe,
+ .remove = rt711_sdca_sdw_remove,
+ .ops = &rt711_sdca_slave_ops,
+ .id_table = rt711_sdca_id,
+};
+module_sdw_driver(rt711_sdca_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT711 SDCA SDW driver");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt711-sdca-sdw.h b/sound/soc/codecs/rt711-sdca-sdw.h
new file mode 100644
index 000000000000..0d774e473ab9
--- /dev/null
+++ b/sound/soc/codecs/rt711-sdca-sdw.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt711-sdw-sdca.h -- RT711 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2021 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT711_SDW_SDCA_H__
+#define __RT711_SDW_SDCA_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw_registers.h>
+
+static const struct reg_default rt711_sdca_reg_defaults[] = {
+ { 0x201a, 0x00 },
+ { 0x201e, 0x00 },
+ { 0x201f, 0x00 },
+ { 0x2020, 0x00 },
+ { 0x2021, 0x00 },
+ { 0x2022, 0x00 },
+ { 0x2023, 0x00 },
+ { 0x2024, 0x00 },
+ { 0x2025, 0x01 },
+ { 0x2026, 0x00 },
+ { 0x2027, 0x00 },
+ { 0x2029, 0x00 },
+ { 0x202a, 0x00 },
+ { 0x202d, 0x00 },
+ { 0x202e, 0x00 },
+ { 0x202f, 0x00 },
+ { 0x2030, 0x00 },
+ { 0x2031, 0x00 },
+ { 0x2032, 0x00 },
+ { 0x2033, 0x00 },
+ { 0x2230, 0x00 },
+ { 0x2231, 0x2f },
+ { 0x2232, 0x80 },
+ { 0x2233, 0x00 },
+ { 0x2234, 0x00 },
+ { 0x2235, 0x00 },
+ { 0x2236, 0x00 },
+ { 0x2237, 0x00 },
+ { 0x2238, 0x00 },
+ { 0x2239, 0x00 },
+ { 0x2f01, 0x00 },
+ { 0x2f02, 0x09 },
+ { 0x2f03, 0x00 },
+ { 0x2f04, 0x00 },
+ { 0x2f05, 0x0b },
+ { 0x2f06, 0x01 },
+ { 0x2f08, 0x00 },
+ { 0x2f09, 0x00 },
+ { 0x2f0a, 0x00 },
+ { 0x2f0b, 0x00 },
+ { 0x2f0c, 0x00 },
+ { 0x2f0d, 0x00 },
+ { 0x2f0e, 0x14 },
+ { 0x2f0f, 0x00 },
+ { 0x2f50, 0x03 },
+ { 0x2f5a, 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_CS01, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDE28, RT711_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+};
+
+static const struct reg_default rt711_sdca_mbq_defaults[] = {
+ { 0x2000009, 0x1029 },
+ { 0x2000011, 0x007a },
+ { 0x200001a, 0x8003 },
+ { 0x2000045, 0x5289 },
+ { 0x2000048, 0x8049 },
+ { 0x200004a, 0xa83b },
+ { 0x200006b, 0x5064 },
+ { 0x200006f, 0x058b },
+ { 0x5800000, 0x0008 },
+ { 0x5800001, 0x0000 },
+ { 0x5f00001, 0x000a },
+ { 0x6100000, 0x6100 },
+ { 0x6100035, 0x0060 },
+ { 0x6100036, 0x0029 },
+ { 0x610003f, 0xff12 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_L), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_L), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), 0x00 },
+};
+
+#endif /* __RT711_SDW_SDCA_H__ */
diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c
new file mode 100644
index 000000000000..cc36739f7fcf
--- /dev/null
+++ b/sound/soc/codecs/rt711-sdca.c
@@ -0,0 +1,1583 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt711-sdca.c -- rt711 SDCA ALSA SoC audio driver
+//
+// Copyright(c) 2021 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/slab.h>
+#include <linux/bitops.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/jack.h>
+
+#include "rt711-sdca.h"
+
+static int rt711_sdca_index_write(struct rt711_sdca_priv *rt711,
+ unsigned int nid, unsigned int reg, unsigned int value)
+{
+ int ret;
+ struct regmap *regmap = rt711->mbq_regmap;
+ unsigned int addr = (nid << 20) | reg;
+
+ ret = regmap_write(regmap, addr, value);
+ if (ret < 0)
+ dev_err(rt711->component->dev,
+ "Failed to set private value: %06x <= %04x ret=%d\n",
+ addr, value, ret);
+
+ return ret;
+}
+
+static int rt711_sdca_index_read(struct rt711_sdca_priv *rt711,
+ unsigned int nid, unsigned int reg, unsigned int *value)
+{
+ int ret;
+ struct regmap *regmap = rt711->mbq_regmap;
+ unsigned int addr = (nid << 20) | reg;
+
+ ret = regmap_read(regmap, addr, value);
+ if (ret < 0)
+ dev_err(rt711->component->dev,
+ "Failed to get private value: %06x => %04x ret=%d\n",
+ addr, *value, ret);
+
+ return ret;
+}
+
+static int rt711_sdca_index_update_bits(struct rt711_sdca_priv *rt711,
+ unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val)
+{
+ unsigned int tmp;
+ int ret;
+
+ ret = rt711_sdca_index_read(rt711, nid, reg, &tmp);
+ if (ret < 0)
+ return ret;
+
+ set_mask_bits(&tmp, mask, val);
+ return rt711_sdca_index_write(rt711, nid, reg, tmp);
+}
+
+static void rt711_sdca_reset(struct rt711_sdca_priv *rt711)
+{
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG,
+ RT711_PARA_VERB_CTL, RT711_HIDDEN_REG_SW_RESET,
+ RT711_HIDDEN_REG_SW_RESET);
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_HDA_LEGACY_RESET_CTL, 0x1, 0x1);
+}
+
+static int rt711_sdca_calibration(struct rt711_sdca_priv *rt711)
+{
+ unsigned int val, loop_rc = 0, loop_dc = 0;
+ struct device *dev;
+ struct regmap *regmap = rt711->regmap;
+ int chk_cnt = 100;
+ int ret = 0;
+
+ mutex_lock(&rt711->calibrate_mutex);
+ dev = regmap_get_device(regmap);
+
+ regmap_read(rt711->regmap, RT711_RC_CAL_STATUS, &val);
+ /* RC calibration */
+ if (!(val & 0x40))
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_ANALOG_CTL,
+ RT711_MISC_POWER_CTL0, 0x0010, 0x0010);
+
+ for (loop_rc = 0; loop_rc < chk_cnt && !(val & 0x40); loop_rc++) {
+ usleep_range(10000, 11000);
+ ret = regmap_read(rt711->regmap, RT711_RC_CAL_STATUS, &val);
+ if (ret < 0)
+ goto _cali_fail_;
+ }
+ if (loop_rc == chk_cnt)
+ dev_err(dev, "%s, RC calibration time-out!\n", __func__);
+
+ /* HP calibration by manual mode setting */
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG,
+ RT711_FSM_CTL, 0x2000, 0x2000);
+
+ /* Calibration manual mode */
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG,
+ RT711_FSM_CTL, 0xf, RT711_CALI_CTL);
+
+ /* reset HP calibration */
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_CALI,
+ RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_FORCE_CALI_RST, 0x00);
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_CALI,
+ RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_FORCE_CALI_RST,
+ RT711_DAC_DC_FORCE_CALI_RST);
+
+ /* cal_clk_en_reg */
+ if (rt711->hw_ver == RT711_VER_VD0)
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_CALI,
+ RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_CLK_EN,
+ RT711_DAC_DC_CALI_CLK_EN);
+
+ /* trigger */
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_CALI,
+ RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER,
+ RT711_DAC_DC_CALI_TRIGGER);
+
+ /* wait for calibration process */
+ rt711_sdca_index_read(rt711, RT711_VENDOR_CALI,
+ RT711_DAC_DC_CALI_CTL1, &val);
+
+ for (loop_dc = 0; loop_dc < chk_cnt &&
+ (val & RT711_DAC_DC_CALI_TRIGGER); loop_dc++) {
+ usleep_range(10000, 11000);
+ ret = rt711_sdca_index_read(rt711, RT711_VENDOR_CALI,
+ RT711_DAC_DC_CALI_CTL1, &val);
+ if (ret < 0)
+ goto _cali_fail_;
+ }
+ if (loop_dc == chk_cnt)
+ dev_err(dev, "%s, calibration time-out!\n", __func__);
+
+ if (loop_dc == chk_cnt || loop_rc == chk_cnt)
+ ret = -ETIMEDOUT;
+
+_cali_fail_:
+ /* enable impedance sense */
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG,
+ RT711_FSM_CTL, RT711_FSM_IMP_EN, RT711_FSM_IMP_EN);
+
+ /* release HP-JD and trigger FSM */
+ rt711_sdca_index_write(rt711, RT711_VENDOR_REG,
+ RT711_DIGITAL_MISC_CTRL4, 0x201b);
+
+ mutex_unlock(&rt711->calibrate_mutex);
+ dev_dbg(dev, "%s calibration complete, ret=%d\n", __func__, ret);
+ return ret;
+}
+
+static unsigned int rt711_sdca_button_detect(struct rt711_sdca_priv *rt711)
+{
+ unsigned int btn_type = 0, offset, idx, val, owner;
+ int ret;
+ unsigned char buf[3];
+
+ /* get current UMP message owner */
+ ret = regmap_read(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_CURRENT_OWNER, 0),
+ &owner);
+ if (ret < 0)
+ return 0;
+
+ /* if owner is device then there is no button event from device */
+ if (owner == 1)
+ return 0;
+
+ /* read UMP message offset */
+ ret = regmap_read(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0),
+ &offset);
+ if (ret < 0)
+ goto _end_btn_det_;
+
+ for (idx = 0; idx < sizeof(buf); idx++) {
+ ret = regmap_read(rt711->regmap,
+ RT711_BUF_ADDR_HID1 + offset + idx, &val);
+ if (ret < 0)
+ goto _end_btn_det_;
+ buf[idx] = val & 0xff;
+ }
+
+ if (buf[0] == 0x11) {
+ switch (buf[1] & 0xf0) {
+ case 0x10:
+ btn_type |= SND_JACK_BTN_2;
+ break;
+ case 0x20:
+ btn_type |= SND_JACK_BTN_3;
+ break;
+ case 0x40:
+ btn_type |= SND_JACK_BTN_0;
+ break;
+ case 0x80:
+ btn_type |= SND_JACK_BTN_1;
+ break;
+ }
+ switch (buf[2]) {
+ case 0x01:
+ case 0x10:
+ btn_type |= SND_JACK_BTN_2;
+ break;
+ case 0x02:
+ case 0x20:
+ btn_type |= SND_JACK_BTN_3;
+ break;
+ case 0x04:
+ case 0x40:
+ btn_type |= SND_JACK_BTN_0;
+ break;
+ case 0x08:
+ case 0x80:
+ btn_type |= SND_JACK_BTN_1;
+ break;
+ }
+ }
+
+_end_btn_det_:
+ /* Host is owner, so set back to device */
+ if (owner == 0)
+ /* set owner to device */
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01,
+ RT711_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE, 0), 0x01);
+
+ return btn_type;
+}
+
+static int rt711_sdca_headset_detect(struct rt711_sdca_priv *rt711)
+{
+ unsigned int det_mode;
+ int ret;
+
+ /* 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),
+ &det_mode);
+ if (ret < 0)
+ goto io_error;
+
+ switch (det_mode) {
+ case 0x00:
+ rt711->jack_type = 0;
+ break;
+ case 0x03:
+ rt711->jack_type = SND_JACK_HEADPHONE;
+ break;
+ case 0x05:
+ rt711->jack_type = SND_JACK_HEADSET;
+ break;
+ }
+
+ /* write selected_mode */
+ if (det_mode) {
+ ret = regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_SELECTED_MODE, 0),
+ det_mode);
+ if (ret < 0)
+ goto io_error;
+ }
+
+ dev_dbg(&rt711->slave->dev,
+ "%s, detected_mode=0x%x\n", __func__, det_mode);
+
+ return 0;
+
+io_error:
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+ return ret;
+}
+
+static void rt711_sdca_jack_detect_handler(struct work_struct *work)
+{
+ struct rt711_sdca_priv *rt711 =
+ container_of(work, struct rt711_sdca_priv, jack_detect_work.work);
+ int btn_type = 0, ret;
+
+ if (!rt711->hs_jack)
+ return;
+
+ if (!rt711->component->card->instantiated)
+ return;
+
+ /* SDW_SCP_SDCA_INT_SDCA_0 is used for jack detection */
+ if (rt711->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) {
+ ret = rt711_sdca_headset_detect(rt711);
+ if (ret < 0)
+ return;
+ }
+
+ /* SDW_SCP_SDCA_INT_SDCA_8 is used for button detection */
+ if (rt711->scp_sdca_stat2 & SDW_SCP_SDCA_INT_SDCA_8)
+ btn_type = rt711_sdca_button_detect(rt711);
+
+ if (rt711->jack_type == 0)
+ btn_type = 0;
+
+ dev_dbg(&rt711->slave->dev,
+ "in %s, jack_type=0x%x\n", __func__, rt711->jack_type);
+ dev_dbg(&rt711->slave->dev,
+ "in %s, btn_type=0x%x\n", __func__, btn_type);
+ dev_dbg(&rt711->slave->dev,
+ "in %s, scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__,
+ rt711->scp_sdca_stat1, rt711->scp_sdca_stat2);
+
+ snd_soc_jack_report(rt711->hs_jack, rt711->jack_type | btn_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+ if (btn_type) {
+ /* button released */
+ snd_soc_jack_report(rt711->hs_jack, rt711->jack_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+ mod_delayed_work(system_power_efficient_wq,
+ &rt711->jack_btn_check_work, msecs_to_jiffies(200));
+ }
+}
+
+static void rt711_sdca_btn_check_handler(struct work_struct *work)
+{
+ struct rt711_sdca_priv *rt711 =
+ container_of(work, struct rt711_sdca_priv, jack_btn_check_work.work);
+ int btn_type = 0, ret, idx;
+ unsigned int det_mode, offset, val;
+ unsigned char buf[3];
+
+ ret = regmap_read(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_DETECTED_MODE, 0),
+ &det_mode);
+ if (ret < 0)
+ goto io_error;
+
+ /* pin attached */
+ if (det_mode) {
+ /* read UMP message offset */
+ ret = regmap_read(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0),
+ &offset);
+ if (ret < 0)
+ goto io_error;
+
+ for (idx = 0; idx < sizeof(buf); idx++) {
+ ret = regmap_read(rt711->regmap,
+ RT711_BUF_ADDR_HID1 + offset + idx, &val);
+ if (ret < 0)
+ goto io_error;
+ buf[idx] = val & 0xff;
+ }
+
+ if (buf[0] == 0x11) {
+ switch (buf[1] & 0xf0) {
+ case 0x10:
+ btn_type |= SND_JACK_BTN_2;
+ break;
+ case 0x20:
+ btn_type |= SND_JACK_BTN_3;
+ break;
+ case 0x40:
+ btn_type |= SND_JACK_BTN_0;
+ break;
+ case 0x80:
+ btn_type |= SND_JACK_BTN_1;
+ break;
+ }
+ switch (buf[2]) {
+ case 0x01:
+ case 0x10:
+ btn_type |= SND_JACK_BTN_2;
+ break;
+ case 0x02:
+ case 0x20:
+ btn_type |= SND_JACK_BTN_3;
+ break;
+ case 0x04:
+ case 0x40:
+ btn_type |= SND_JACK_BTN_0;
+ break;
+ case 0x08:
+ case 0x80:
+ btn_type |= SND_JACK_BTN_1;
+ break;
+ }
+ }
+ } else
+ rt711->jack_type = 0;
+
+ dev_dbg(&rt711->slave->dev, "%s, btn_type=0x%x\n", __func__, btn_type);
+ snd_soc_jack_report(rt711->hs_jack, rt711->jack_type | btn_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+ if (btn_type) {
+ /* button released */
+ snd_soc_jack_report(rt711->hs_jack, rt711->jack_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+ mod_delayed_work(system_power_efficient_wq,
+ &rt711->jack_btn_check_work, msecs_to_jiffies(200));
+ }
+
+ return;
+
+io_error:
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+}
+
+static void rt711_sdca_jack_init(struct rt711_sdca_priv *rt711)
+{
+ mutex_lock(&rt711->calibrate_mutex);
+
+ if (rt711->hs_jack) {
+ /* Enable HID1 event & set button RTC mode */
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_PUSH_BTN_INT_CTL6, 0x80f0, 0x8000);
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_PUSH_BTN_INT_CTL2, 0x11dd, 0x11dd);
+ rt711_sdca_index_write(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_PUSH_BTN_INT_CTL7, 0xffff);
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_PUSH_BTN_INT_CTL9, 0xf000, 0x0000);
+
+ /* GE_mode_change_event_en & Hid1_push_button_event_en */
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_GE_MODE_RELATED_CTL, 0x0c00, 0x0c00);
+
+ switch (rt711->jd_src) {
+ case RT711_JD1:
+ /* default settings was already for JD1 */
+ break;
+ case RT711_JD2:
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG,
+ RT711_JD_CTL1, RT711_JD2_DIGITAL_MODE_SEL,
+ RT711_JD2_DIGITAL_MODE_SEL);
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG,
+ RT711_JD_CTL2, RT711_JD2_2PORT_200K_DECODE_HP | RT711_HP_JD_SEL_JD2,
+ RT711_JD2_2PORT_200K_DECODE_HP | RT711_HP_JD_SEL_JD2);
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG,
+ RT711_CC_DET1,
+ RT711_HP_JD_FINAL_RESULT_CTL_JD12,
+ RT711_HP_JD_FINAL_RESULT_CTL_JD12);
+ break;
+ default:
+ dev_warn(rt711->component->dev, "Wrong JD source\n");
+ break;
+ }
+
+ /* set SCP_SDCA_IntMask1[0]=1 */
+ sdw_write_no_pm(rt711->slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0);
+ /* set SCP_SDCA_IntMask2[0]=1 */
+ sdw_write_no_pm(rt711->slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8);
+ dev_dbg(&rt711->slave->dev, "in %s enable\n", __func__);
+ } else {
+ /* disable HID 1/2 event */
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_GE_MODE_RELATED_CTL, 0x0c00, 0x0000);
+
+ dev_dbg(&rt711->slave->dev, "in %s disable\n", __func__);
+ }
+
+ mutex_unlock(&rt711->calibrate_mutex);
+}
+
+static int rt711_sdca_set_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *hs_jack, void *data)
+{
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+
+ rt711->hs_jack = hs_jack;
+
+ if (!rt711->hw_init) {
+ dev_dbg(&rt711->slave->dev,
+ "%s hw_init not ready yet\n", __func__);
+ return 0;
+ }
+
+ rt711_sdca_jack_init(rt711);
+ return 0;
+}
+
+/* For SDCA control DAC/ADC Gain */
+static int rt711_sdca_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 rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ unsigned int read_l, read_r, gain_l_val, gain_r_val;
+ unsigned int i, adc_vol_flag = 0, changed = 0;
+ unsigned int lvalue, rvalue;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume") ||
+ strstr(ucontrol->id.name, "FU0F Capture Volume"))
+ adc_vol_flag = 1;
+
+ regmap_read(rt711->mbq_regmap, mc->reg, &lvalue);
+ regmap_read(rt711->mbq_regmap, mc->rreg, &rvalue);
+
+ /* control value to 2's complement value */
+ /* L Channel */
+ gain_l_val = ucontrol->value.integer.value[0];
+ if (gain_l_val > mc->max)
+ gain_l_val = mc->max;
+ read_l = gain_l_val;
+
+ if (mc->shift == 8) /* boost gain */
+ gain_l_val = (gain_l_val * 10) << mc->shift;
+ else { /* ADC/DAC gain */
+ if (adc_vol_flag && gain_l_val > mc->shift)
+ gain_l_val = (gain_l_val - mc->shift) * 75;
+ else
+ gain_l_val = (mc->shift - gain_l_val) * 75;
+ gain_l_val <<= 8;
+ gain_l_val /= 100;
+ if (!(adc_vol_flag && read_l > mc->shift)) {
+ gain_l_val = ~gain_l_val;
+ gain_l_val += 1;
+ }
+ 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;
+ read_r = gain_r_val;
+
+ if (mc->shift == 8) /* boost gain */
+ gain_r_val = (gain_r_val * 10) << mc->shift;
+ else { /* ADC/DAC gain */
+ if (adc_vol_flag && gain_r_val > mc->shift)
+ gain_r_val = (gain_r_val - mc->shift) * 75;
+ else
+ gain_r_val = (mc->shift - gain_r_val) * 75;
+ gain_r_val <<= 8;
+ gain_r_val /= 100;
+ if (!(adc_vol_flag && read_r > mc->shift)) {
+ gain_r_val = ~gain_r_val;
+ gain_r_val += 1;
+ }
+ gain_r_val &= 0xffff;
+ }
+
+ if (lvalue != gain_l_val || rvalue != gain_r_val)
+ changed = 1;
+ else
+ return 0;
+
+ for (i = 0; i < 3; i++) { /* retry 3 times at most */
+ /* Lch*/
+ regmap_write(rt711->mbq_regmap, mc->reg, gain_l_val);
+
+ /* Rch */
+ regmap_write(rt711->mbq_regmap, mc->rreg, gain_r_val);
+
+ regmap_read(rt711->mbq_regmap, mc->reg, &read_l);
+ regmap_read(rt711->mbq_regmap, mc->rreg, &read_r);
+ if (read_r == gain_r_val && read_l == gain_l_val)
+ break;
+ }
+
+ return i == 3 ? -EIO : changed;
+}
+
+static int rt711_sdca_set_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt711_sdca_priv *rt711 = 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;
+ unsigned int adc_vol_flag = 0, neg_flag = 0;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume") ||
+ strstr(ucontrol->id.name, "FU0F Capture Volume"))
+ adc_vol_flag = 1;
+
+ regmap_read(rt711->mbq_regmap, mc->reg, &read_l);
+ regmap_read(rt711->mbq_regmap, mc->rreg, &read_r);
+
+ /* 2's complement value to control value */
+ if (mc->shift == 8) /* boost gain */
+ ctl_l = (read_l >> mc->shift) / 10;
+ else { /* ADC/DAC gain */
+ ctl_l = read_l;
+ if (read_l & BIT(15)) {
+ ctl_l = 0xffff & ~(read_l - 1);
+ neg_flag = 1;
+ }
+ ctl_l *= 100;
+ ctl_l >>= 8;
+ if (adc_vol_flag) {
+ if (neg_flag)
+ ctl_l = mc->shift - (ctl_l / 75);
+ else
+ ctl_l = mc->shift + (ctl_l / 75);
+ } else
+ ctl_l = mc->max - (ctl_l / 75);
+ }
+
+ neg_flag = 0;
+ if (read_l != read_r) {
+ if (mc->shift == 8) /* boost gain */
+ ctl_r = (read_r >> mc->shift) / 10;
+ else { /* ADC/DAC gain */
+ ctl_r = read_r;
+ if (read_r & BIT(15)) {
+ ctl_r = 0xffff & ~(read_r - 1);
+ neg_flag = 1;
+ }
+ ctl_r *= 100;
+ ctl_r >>= 8;
+ if (adc_vol_flag) {
+ if (neg_flag)
+ ctl_r = mc->shift - (ctl_r / 75);
+ else
+ ctl_r = mc->shift + (ctl_r / 75);
+ } else
+ ctl_r = mc->max - (ctl_r / 75);
+ }
+ } else
+ ctl_r = ctl_l;
+
+ ucontrol->value.integer.value[0] = ctl_l;
+ ucontrol->value.integer.value[1] = ctl_r;
+
+ return 0;
+}
+
+static int rt711_sdca_set_fu0f_capture_ctl(struct rt711_sdca_priv *rt711)
+{
+ int err;
+ unsigned int ch_l, ch_r;
+
+ ch_l = (rt711->fu0f_dapm_mute || rt711->fu0f_mixer_l_mute) ? 0x01 : 0x00;
+ ch_r = (rt711->fu0f_dapm_mute || rt711->fu0f_mixer_r_mute) ? 0x01 : 0x00;
+
+ err = regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F,
+ RT711_SDCA_CTL_FU_MUTE, CH_L), ch_l);
+ if (err < 0)
+ return err;
+
+ err = regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F,
+ RT711_SDCA_CTL_FU_MUTE, CH_R), ch_r);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int rt711_sdca_set_fu1e_capture_ctl(struct rt711_sdca_priv *rt711)
+{
+ int err;
+ unsigned int ch_l, ch_r;
+
+ ch_l = (rt711->fu1e_dapm_mute || rt711->fu1e_mixer_l_mute) ? 0x01 : 0x00;
+ ch_r = (rt711->fu1e_dapm_mute || rt711->fu1e_mixer_r_mute) ? 0x01 : 0x00;
+
+ err = regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU1E,
+ RT711_SDCA_CTL_FU_MUTE, CH_L), ch_l);
+ if (err < 0)
+ return err;
+
+ err = regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU1E,
+ RT711_SDCA_CTL_FU_MUTE, CH_R), ch_r);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int rt711_sdca_fu1e_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = !rt711->fu1e_mixer_l_mute;
+ ucontrol->value.integer.value[1] = !rt711->fu1e_mixer_r_mute;
+ return 0;
+}
+
+static int rt711_sdca_fu1e_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ int err, changed = 0;
+
+ if (rt711->fu1e_mixer_l_mute != !ucontrol->value.integer.value[0] ||
+ rt711->fu1e_mixer_r_mute != !ucontrol->value.integer.value[1])
+ changed = 1;
+
+ rt711->fu1e_mixer_l_mute = !ucontrol->value.integer.value[0];
+ rt711->fu1e_mixer_r_mute = !ucontrol->value.integer.value[1];
+ err = rt711_sdca_set_fu1e_capture_ctl(rt711);
+ if (err < 0)
+ return err;
+
+ return changed;
+}
+
+static int rt711_sdca_fu0f_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = !rt711->fu0f_mixer_l_mute;
+ ucontrol->value.integer.value[1] = !rt711->fu0f_mixer_r_mute;
+ return 0;
+}
+
+static int rt711_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ int err, changed = 0;
+
+ if (rt711->fu0f_mixer_l_mute != !ucontrol->value.integer.value[0] ||
+ rt711->fu0f_mixer_r_mute != !ucontrol->value.integer.value[1])
+ changed = 1;
+
+ rt711->fu0f_mixer_l_mute = !ucontrol->value.integer.value[0];
+ rt711->fu0f_mixer_r_mute = !ucontrol->value.integer.value[1];
+ err = rt711_sdca_set_fu0f_capture_ctl(rt711);
+ if (err < 0)
+ return err;
+
+ return changed;
+}
+
+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);
+
+static const struct snd_kcontrol_new rt711_sdca_snd_controls[] = {
+ SOC_DOUBLE_R_EXT_TLV("FU05 Playback Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_R),
+ 0x57, 0x57, 0,
+ rt711_sdca_set_gain_get, rt711_sdca_set_gain_put, out_vol_tlv),
+ SOC_DOUBLE_EXT("FU1E Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0,
+ rt711_sdca_fu1e_capture_get, rt711_sdca_fu1e_capture_put),
+ SOC_DOUBLE_EXT("FU0F Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0,
+ rt711_sdca_fu0f_capture_get, rt711_sdca_fu0f_capture_put),
+ SOC_DOUBLE_R_EXT_TLV("FU1E Capture Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R),
+ 0x17, 0x3f, 0,
+ rt711_sdca_set_gain_get, rt711_sdca_set_gain_put, in_vol_tlv),
+ SOC_DOUBLE_R_EXT_TLV("FU0F Capture Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_R),
+ 0x17, 0x3f, 0,
+ rt711_sdca_set_gain_get, rt711_sdca_set_gain_put, in_vol_tlv),
+ SOC_DOUBLE_R_EXT_TLV("FU44 Gain Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, 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_DOUBLE_R_EXT_TLV("FU15 Gain Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_L),
+ 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),
+};
+
+static int rt711_sdca_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_kcontrol_component(kcontrol);
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ unsigned int val = 0, mask_sft;
+
+ if (strstr(ucontrol->id.name, "ADC 22 Mux"))
+ mask_sft = 10;
+ else if (strstr(ucontrol->id.name, "ADC 23 Mux"))
+ mask_sft = 13;
+ else
+ return -EINVAL;
+
+ rt711_sdca_index_read(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_HDA_LEGACY_MUX_CTL1, &val);
+
+ ucontrol->value.enumerated.item[0] = (val >> mask_sft) & 0x7;
+
+ return 0;
+}
+
+static int rt711_sdca_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 rt711_sdca_priv *rt711 = 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 22 Mux"))
+ mask_sft = 10;
+ else if (strstr(ucontrol->id.name, "ADC 23 Mux"))
+ mask_sft = 13;
+ else
+ return -EINVAL;
+
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+
+ rt711_sdca_index_read(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_HDA_LEGACY_MUX_CTL1, &val2);
+ val2 = (val2 >> mask_sft) & 0x7;
+
+ if (val == val2)
+ change = 0;
+ else
+ change = 1;
+
+ if (change)
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_HDA_LEGACY_MUX_CTL1, 0x7 << mask_sft,
+ val << mask_sft);
+
+ snd_soc_dapm_mux_update_power(dapm, kcontrol,
+ item[0], e, NULL);
+
+ return change;
+}
+
+static const char * const adc_mux_text[] = {
+ "MIC2",
+ "LINE1",
+ "LINE2",
+ "DMIC",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt711_adc22_enum, SND_SOC_NOPM, 0, adc_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt711_adc23_enum, SND_SOC_NOPM, 0, adc_mux_text);
+
+static const struct snd_kcontrol_new rt711_sdca_adc22_mux =
+ SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt711_adc22_enum,
+ rt711_sdca_mux_get, rt711_sdca_mux_put);
+
+static const struct snd_kcontrol_new rt711_sdca_adc23_mux =
+ SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt711_adc23_enum,
+ rt711_sdca_mux_get, rt711_sdca_mux_put);
+
+static int rt711_sdca_fu05_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 rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ unsigned char unmute = 0x0, mute = 0x1;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05,
+ RT711_SDCA_CTL_FU_MUTE, CH_L),
+ unmute);
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05,
+ RT711_SDCA_CTL_FU_MUTE, CH_R),
+ unmute);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05,
+ RT711_SDCA_CTL_FU_MUTE, CH_L),
+ mute);
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05,
+ RT711_SDCA_CTL_FU_MUTE, CH_R),
+ mute);
+ break;
+ }
+ return 0;
+}
+
+static int rt711_sdca_fu0f_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 rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt711->fu0f_dapm_mute = false;
+ rt711_sdca_set_fu0f_capture_ctl(rt711);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt711->fu0f_dapm_mute = true;
+ rt711_sdca_set_fu0f_capture_ctl(rt711);
+ break;
+ }
+ return 0;
+}
+
+static int rt711_sdca_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 rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt711->fu1e_dapm_mute = false;
+ rt711_sdca_set_fu1e_capture_ctl(rt711);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt711->fu1e_dapm_mute = true;
+ rt711_sdca_set_fu1e_capture_ctl(rt711);
+ break;
+ }
+ return 0;
+}
+
+static int rt711_sdca_pde28_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 rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDE28,
+ RT711_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDE28,
+ RT711_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt711_sdca_pde29_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 rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDE29,
+ RT711_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDE29,
+ RT711_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt711_sdca_pde2a_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 rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PDE2A,
+ RT711_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PDE2A,
+ RT711_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt711_sdca_line1_power_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 rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ static unsigned int sel_mode = 0xffff;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_read(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49,
+ RT711_SDCA_CTL_SELECTED_MODE, 0),
+ &sel_mode);
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_LINE1,
+ RT711_SDCA_CTL_VENDOR_DEF, 0),
+ 0x1);
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49,
+ RT711_SDCA_CTL_SELECTED_MODE, 0),
+ 0x7);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_LINE1,
+ RT711_SDCA_CTL_VENDOR_DEF, 0),
+ 0x0);
+ if (sel_mode != 0xffff)
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49,
+ RT711_SDCA_CTL_SELECTED_MODE, 0),
+ sel_mode);
+ break;
+ }
+
+ return 0;
+}
+
+static int rt711_sdca_line2_power_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 rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDELINE2,
+ RT711_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_LINE2,
+ RT711_SDCA_CTL_VENDOR_DEF, 0),
+ 0x1);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_LINE2,
+ RT711_SDCA_CTL_VENDOR_DEF, 0),
+ 0x0);
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDELINE2,
+ RT711_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt711_sdca_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("HP"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("DMIC1"),
+ SND_SOC_DAPM_INPUT("DMIC2"),
+ SND_SOC_DAPM_INPUT("LINE1"),
+ SND_SOC_DAPM_INPUT("LINE2"),
+
+ SND_SOC_DAPM_PGA_E("LINE1 Power", SND_SOC_NOPM,
+ 0, 0, NULL, 0, rt711_sdca_line1_power_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA_E("LINE2 Power", SND_SOC_NOPM,
+ 0, 0, NULL, 0, rt711_sdca_line2_power_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_SUPPLY("PDE 28", SND_SOC_NOPM, 0, 0,
+ rt711_sdca_pde28_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 29", SND_SOC_NOPM, 0, 0,
+ rt711_sdca_pde29_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 2A", SND_SOC_NOPM, 0, 0,
+ rt711_sdca_pde2a_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_DAC_E("FU 05", NULL, SND_SOC_NOPM, 0, 0,
+ rt711_sdca_fu05_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("FU 0F", NULL, SND_SOC_NOPM, 0, 0,
+ rt711_sdca_fu0f_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("FU 1E", NULL, SND_SOC_NOPM, 0, 0,
+ rt711_sdca_fu1e_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0,
+ &rt711_sdca_adc22_mux),
+ SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0,
+ &rt711_sdca_adc23_mux),
+
+ SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt711_sdca_audio_map[] = {
+ {"FU 05", NULL, "DP3RX"},
+ {"DP2TX", NULL, "FU 0F"},
+ {"DP4TX", NULL, "FU 1E"},
+
+ {"LINE1 Power", NULL, "LINE1"},
+ {"LINE2 Power", NULL, "LINE2"},
+ {"HP", NULL, "PDE 28"},
+ {"FU 0F", NULL, "PDE 29"},
+ {"FU 1E", NULL, "PDE 2A"},
+
+ {"FU 0F", NULL, "ADC 22 Mux"},
+ {"FU 1E", NULL, "ADC 23 Mux"},
+ {"ADC 22 Mux", "DMIC", "DMIC1"},
+ {"ADC 22 Mux", "LINE1", "LINE1 Power"},
+ {"ADC 22 Mux", "LINE2", "LINE2 Power"},
+ {"ADC 22 Mux", "MIC2", "MIC2"},
+ {"ADC 23 Mux", "DMIC", "DMIC2"},
+ {"ADC 23 Mux", "LINE1", "LINE1 Power"},
+ {"ADC 23 Mux", "LINE2", "LINE2 Power"},
+ {"ADC 23 Mux", "MIC2", "MIC2"},
+
+ {"HP", NULL, "FU 05"},
+};
+
+static int rt711_sdca_parse_dt(struct rt711_sdca_priv *rt711, struct device *dev)
+{
+ device_property_read_u32(dev, "realtek,jd-src", &rt711->jd_src);
+
+ return 0;
+}
+
+static int rt711_sdca_probe(struct snd_soc_component *component)
+{
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+
+ rt711_sdca_parse_dt(rt711, &rt711->slave->dev);
+ rt711->component = component;
+
+ return 0;
+}
+
+static void rt711_sdca_remove(struct snd_soc_component *component)
+{
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(rt711->regmap, true);
+ regcache_cache_only(rt711->mbq_regmap, true);
+}
+
+static const struct snd_soc_component_driver soc_sdca_dev_rt711 = {
+ .probe = rt711_sdca_probe,
+ .controls = rt711_sdca_snd_controls,
+ .num_controls = ARRAY_SIZE(rt711_sdca_snd_controls),
+ .dapm_widgets = rt711_sdca_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt711_sdca_dapm_widgets),
+ .dapm_routes = rt711_sdca_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rt711_sdca_audio_map),
+ .set_jack = rt711_sdca_set_jack_detect,
+ .remove = rt711_sdca_remove,
+};
+
+static int rt711_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+ int direction)
+{
+ struct sdw_stream_data *stream;
+
+ if (!sdw_stream)
+ return 0;
+
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (!stream)
+ return -ENOMEM;
+
+ stream->sdw_stream = sdw_stream;
+
+ /* Use tx_mask or rx_mask to configure stream tag and set dma_data */
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ dai->playback_dma_data = stream;
+ else
+ dai->capture_dma_data = stream;
+
+ return 0;
+}
+
+static void rt711_sdca_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct sdw_stream_data *stream;
+
+ stream = snd_soc_dai_get_dma_data(dai, substream);
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+ kfree(stream);
+}
+
+static int rt711_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_config stream_config;
+ struct sdw_port_config port_config;
+ enum sdw_data_direction direction;
+ struct sdw_stream_data *stream;
+ int retval, port, num_channels;
+ unsigned int sampling_rate;
+
+ dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+ stream = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!stream)
+ return -EINVAL;
+
+ if (!rt711->slave)
+ return -EINVAL;
+
+ /* SoundWire specific configuration */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ direction = SDW_DATA_DIR_RX;
+ port = 3;
+ } else {
+ direction = SDW_DATA_DIR_TX;
+ if (dai->id == RT711_AIF1)
+ port = 2;
+ else if (dai->id == RT711_AIF2)
+ port = 4;
+ else
+ return -EINVAL;
+ }
+
+ stream_config.frame_rate = params_rate(params);
+ stream_config.ch_count = params_channels(params);
+ stream_config.bps = snd_pcm_format_width(params_format(params));
+ stream_config.direction = direction;
+
+ num_channels = params_channels(params);
+ port_config.ch_mask = GENMASK(num_channels - 1, 0);
+ port_config.num = port;
+
+ retval = sdw_stream_add_slave(rt711->slave, &stream_config,
+ &port_config, 1, stream->sdw_stream);
+ if (retval) {
+ dev_err(dai->dev, "Unable to configure port\n");
+ return retval;
+ }
+
+ if (params_channels(params) > 16) {
+ dev_err(component->dev, "Unsupported channels %d\n",
+ params_channels(params));
+ return -EINVAL;
+ }
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 44100:
+ sampling_rate = RT711_SDCA_RATE_44100HZ;
+ break;
+ case 48000:
+ sampling_rate = RT711_SDCA_RATE_48000HZ;
+ break;
+ case 96000:
+ sampling_rate = RT711_SDCA_RATE_96000HZ;
+ break;
+ case 192000:
+ sampling_rate = RT711_SDCA_RATE_192000HZ;
+ break;
+ default:
+ dev_err(component->dev, "Rate %d is not supported\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ /* set sampling frequency */
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_CS01, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_CS11, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_CS1F, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+
+ return 0;
+}
+
+static int rt711_sdca_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_data *stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt711->slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt711->slave, stream->sdw_stream);
+ return 0;
+}
+
+#define RT711_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_192000)
+#define RT711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops rt711_sdca_ops = {
+ .hw_params = rt711_sdca_pcm_hw_params,
+ .hw_free = rt711_sdca_pcm_hw_free,
+ .set_sdw_stream = rt711_sdca_set_sdw_stream,
+ .shutdown = rt711_sdca_shutdown,
+};
+
+static struct snd_soc_dai_driver rt711_sdca_dai[] = {
+ {
+ .name = "rt711-sdca-aif1",
+ .id = RT711_AIF1,
+ .playback = {
+ .stream_name = "DP3 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT711_STEREO_RATES,
+ .formats = RT711_FORMATS,
+ },
+ .capture = {
+ .stream_name = "DP2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT711_STEREO_RATES,
+ .formats = RT711_FORMATS,
+ },
+ .ops = &rt711_sdca_ops,
+ },
+ {
+ .name = "rt711-sdca-aif2",
+ .id = RT711_AIF2,
+ .capture = {
+ .stream_name = "DP4 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT711_STEREO_RATES,
+ .formats = RT711_FORMATS,
+ },
+ .ops = &rt711_sdca_ops,
+ }
+};
+
+int rt711_sdca_init(struct device *dev, struct regmap *regmap,
+ struct regmap *mbq_regmap, struct sdw_slave *slave)
+{
+ struct rt711_sdca_priv *rt711;
+ int ret;
+
+ rt711 = devm_kzalloc(dev, sizeof(*rt711), GFP_KERNEL);
+ if (!rt711)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt711);
+ rt711->slave = slave;
+ rt711->regmap = regmap;
+ rt711->mbq_regmap = mbq_regmap;
+
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt711->hw_init = false;
+ rt711->first_hw_init = false;
+ rt711->fu0f_dapm_mute = true;
+ rt711->fu1e_dapm_mute = true;
+ rt711->fu0f_mixer_l_mute = rt711->fu0f_mixer_r_mute = true;
+ rt711->fu1e_mixer_l_mute = rt711->fu1e_mixer_r_mute = true;
+
+ /* JD source uses JD2 in default */
+ rt711->jd_src = RT711_JD2;
+
+ ret = devm_snd_soc_register_component(dev,
+ &soc_sdca_dev_rt711,
+ rt711_sdca_dai,
+ ARRAY_SIZE(rt711_sdca_dai));
+
+ dev_dbg(&slave->dev, "%s\n", __func__);
+
+ return ret;
+}
+
+static void rt711_sdca_vd0_io_init(struct rt711_sdca_priv *rt711)
+{
+ rt711_sdca_index_write(rt711, RT711_VENDOR_REG,
+ RT711_GPIO_TEST_MODE_CTL2, 0x0e00);
+ rt711_sdca_index_write(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_HDA_LEGACY_GPIO_CTL, 0x0008);
+
+ regmap_write(rt711->regmap, 0x2f5a, 0x01);
+
+ rt711_sdca_index_write(rt711, RT711_VENDOR_REG,
+ RT711_ADC27_VOL_SET, 0x8728);
+
+ rt711_sdca_index_write(rt711, RT711_VENDOR_REG,
+ RT711_COMBO_JACK_AUTO_CTL3, 0xa472);
+
+ regmap_write(rt711->regmap, 0x2f50, 0x02);
+
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_ANALOG_CTL,
+ RT711_MISC_POWER_CTL4, 0x6000, 0x6000);
+
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG,
+ RT711_COMBO_JACK_AUTO_CTL3, 0x000c, 0x000c);
+
+ rt711_sdca_index_write(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_HDA_LEGACY_CONFIG_CTL, 0x0000);
+
+ rt711_sdca_index_write(rt711, RT711_VENDOR_VAD,
+ RT711_VAD_SRAM_CTL1, 0x0050);
+}
+
+static void rt711_sdca_vd1_io_init(struct rt711_sdca_priv *rt711)
+{
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_HDA_LEGACY_UNSOLICITED_CTL, 0x0300, 0x0000);
+
+ rt711_sdca_index_write(rt711, RT711_VENDOR_REG,
+ RT711_COMBO_JACK_AUTO_CTL3, 0xa43e);
+
+ regmap_write(rt711->regmap, 0x2f5a, 0x05);
+
+ rt711_sdca_index_write(rt711, RT711_VENDOR_REG,
+ RT711_JD_CTRL6, 0x0500);
+
+ rt711_sdca_index_write(rt711, RT711_VENDOR_REG,
+ RT711_DMIC_CTL1, 0x6173);
+
+ rt711_sdca_index_write(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_HDA_LEGACY_CONFIG_CTL, 0x0000);
+
+ rt711_sdca_index_write(rt711, RT711_VENDOR_VAD,
+ RT711_VAD_SRAM_CTL1, 0x0050);
+}
+
+int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev);
+ int ret = 0;
+ unsigned int val;
+
+ if (rt711->hw_init)
+ return 0;
+
+ if (rt711->first_hw_init) {
+ regcache_cache_only(rt711->regmap, false);
+ regcache_cache_bypass(rt711->regmap, true);
+ } else {
+ /*
+ * PM runtime is only enabled when a Slave reports as Attached
+ */
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
+ pm_runtime_use_autosuspend(&slave->dev);
+
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(&slave->dev);
+
+ pm_runtime_enable(&slave->dev);
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+
+ rt711_sdca_reset(rt711);
+
+ rt711_sdca_index_read(rt711, RT711_VENDOR_REG, RT711_JD_PRODUCT_NUM, &val);
+ rt711->hw_ver = val & 0xf;
+
+ if (rt711->hw_ver == RT711_VER_VD0)
+ rt711_sdca_vd0_io_init(rt711);
+ else
+ rt711_sdca_vd1_io_init(rt711);
+
+ /* DP4 mux select from 08_filter_Out_pri */
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG,
+ RT711_FILTER_SRC_SEL, 0x1800, 0x0800);
+
+ /* ge_exclusive_inbox_en disable */
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL,
+ RT711_PUSH_BTN_INT_CTL0, 0x20, 0x00);
+
+ if (!rt711->first_hw_init) {
+ INIT_DELAYED_WORK(&rt711->jack_detect_work,
+ rt711_sdca_jack_detect_handler);
+ INIT_DELAYED_WORK(&rt711->jack_btn_check_work,
+ rt711_sdca_btn_check_handler);
+ mutex_init(&rt711->calibrate_mutex);
+ }
+
+ /* calibration */
+ ret = rt711_sdca_calibration(rt711);
+ if (ret < 0)
+ dev_err(dev, "%s, calibration failed!\n", __func__);
+
+ /* HP output enable */
+ regmap_write(rt711->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_OT1, RT711_SDCA_CTL_VENDOR_DEF, 0), 0x4);
+
+ /*
+ * if set_jack callback occurred early than io_init,
+ * we set up the jack detection function now
+ */
+ if (rt711->hs_jack)
+ rt711_sdca_jack_init(rt711);
+
+ if (rt711->first_hw_init) {
+ regcache_cache_bypass(rt711->regmap, false);
+ regcache_mark_dirty(rt711->regmap);
+ } else
+ rt711->first_hw_init = true;
+
+ /* Mark Slave initialization complete */
+ rt711->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;
+}
+
+MODULE_DESCRIPTION("ASoC RT711 SDCA SDW driver");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt711-sdca.h b/sound/soc/codecs/rt711-sdca.h
new file mode 100644
index 000000000000..43ae82b7fdb3
--- /dev/null
+++ b/sound/soc/codecs/rt711-sdca.h
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt711-sdca.h -- RT711 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2021 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT711_SDCA_H__
+#define __RT711_SDCA_H__
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc.h>
+#include <linux/workqueue.h>
+
+struct rt711_sdca_priv {
+ struct regmap *regmap, *mbq_regmap;
+ struct snd_soc_component *component;
+ struct sdw_slave *slave;
+ enum sdw_slave_status status;
+ struct sdw_bus_params params;
+ bool hw_init;
+ bool first_hw_init;
+ struct snd_soc_jack *hs_jack;
+ struct delayed_work jack_detect_work;
+ struct delayed_work jack_btn_check_work;
+ struct mutex calibrate_mutex; /* for headset calibration */
+ int jack_type, jd_src;
+ unsigned int scp_sdca_stat1, scp_sdca_stat2;
+ 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;
+};
+
+struct sdw_stream_data {
+ struct sdw_stream_runtime *sdw_stream;
+};
+
+/* NID */
+#define RT711_AUDIO_FUNCTION_GROUP 0x01
+#define RT711_DAC_OUT2 0x03
+#define RT711_ADC_IN1 0x09
+#define RT711_ADC_IN2 0x08
+#define RT711_DMIC1 0x12
+#define RT711_DMIC2 0x13
+#define RT711_MIC2 0x19
+#define RT711_LINE1 0x1a
+#define RT711_LINE2 0x1b
+#define RT711_BEEP 0x1d
+#define RT711_VENDOR_REG 0x20
+#define RT711_HP_OUT 0x21
+#define RT711_MIXER_IN1 0x22
+#define RT711_MIXER_IN2 0x23
+#define RT711_INLINE_CMD 0x55
+#define RT711_VENDOR_CALI 0x58
+#define RT711_VENDOR_IMS_DRE 0x5b
+#define RT711_VENDOR_VAD 0x5e
+#define RT711_VENDOR_ANALOG_CTL 0x5f
+#define RT711_VENDOR_HDA_CTL 0x61
+
+/* Index (NID:20h) */
+#define RT711_JD_PRODUCT_NUM 0x00
+#define RT711_DMIC_CTL1 0x06
+#define RT711_JD_CTL1 0x08
+#define RT711_JD_CTL2 0x09
+#define RT711_CC_DET1 0x11
+#define RT711_PARA_VERB_CTL 0x1a
+#define RT711_COMBO_JACK_AUTO_CTL1 0x45
+#define RT711_COMBO_JACK_AUTO_CTL2 0x46
+#define RT711_COMBO_JACK_AUTO_CTL3 0x47
+#define RT711_INLINE_CMD_CTL 0x48
+#define RT711_DIGITAL_MISC_CTRL4 0x4a
+#define RT711_JD_CTRL6 0x6a
+#define RT711_VREFOUT_CTL 0x6b
+#define RT711_GPIO_TEST_MODE_CTL2 0x6d
+#define RT711_FSM_CTL 0x6f
+#define RT711_IRQ_FLAG_TABLE1 0x80
+#define RT711_IRQ_FLAG_TABLE2 0x81
+#define RT711_IRQ_FLAG_TABLE3 0x82
+#define RT711_HP_FSM_CTL 0x83
+#define RT711_TX_RX_MUX_CTL 0x91
+#define RT711_FILTER_SRC_SEL 0xb0
+#define RT711_ADC27_VOL_SET 0xb7
+
+/* Index (NID:58h) */
+#define RT711_DAC_DC_CALI_CTL1 0x00
+#define RT711_DAC_DC_CALI_CTL2 0x01
+
+/* Index (NID:5bh) */
+#define RT711_IMS_DIGITAL_CTL1 0x00
+#define RT711_HP_IMS_RESULT_L 0x20
+#define RT711_HP_IMS_RESULT_R 0x21
+
+/* Index (NID:5eh) */
+#define RT711_VAD_SRAM_CTL1 0x10
+
+/* Index (NID:5fh) */
+#define RT711_MISC_POWER_CTL0 0x01
+#define RT711_MISC_POWER_CTL4 0x05
+
+/* Index (NID:61h) */
+#define RT711_HDA_LEGACY_MUX_CTL1 0x00
+#define RT711_HDA_LEGACY_UNSOLICITED_CTL 0x03
+#define RT711_HDA_LEGACY_CONFIG_CTL 0x06
+#define RT711_HDA_LEGACY_RESET_CTL 0x08
+#define RT711_HDA_LEGACY_GPIO_CTL 0x0a
+#define RT711_ADC08_09_PDE_CTL 0x24
+#define RT711_GE_MODE_RELATED_CTL 0x35
+#define RT711_PUSH_BTN_INT_CTL0 0x36
+#define RT711_PUSH_BTN_INT_CTL1 0x37
+#define RT711_PUSH_BTN_INT_CTL2 0x38
+#define RT711_PUSH_BTN_INT_CTL6 0x3c
+#define RT711_PUSH_BTN_INT_CTL7 0x3d
+#define RT711_PUSH_BTN_INT_CTL9 0x3f
+
+/* DAC DC offset calibration control-1 (0x00)(NID:20h) */
+#define RT711_DAC_DC_CALI_TRIGGER (0x1 << 15)
+#define RT711_DAC_DC_CALI_CLK_EN (0x1 << 14)
+#define RT711_DAC_DC_FORCE_CALI_RST (0x1 << 3)
+
+/* jack detect control 1 (0x08)(NID:20h) */
+#define RT711_JD2_DIGITAL_MODE_SEL (0x1 << 1)
+
+/* jack detect control 2 (0x09)(NID:20h) */
+#define RT711_JD2_2PORT_200K_DECODE_HP (0x1 << 13)
+#define RT711_HP_JD_SEL_JD1 (0x0 << 1)
+#define RT711_HP_JD_SEL_JD2 (0x1 << 1)
+
+/* CC DET1 (0x11)(NID:20h) */
+#define RT711_HP_JD_FINAL_RESULT_CTL_JD12 (0x1 << 10)
+#define RT711_HP_JD_FINAL_RESULT_CTL_CCDET (0x0 << 10)
+
+/* Parameter & Verb control (0x1a)(NID:20h) */
+#define RT711_HIDDEN_REG_SW_RESET (0x1 << 14)
+
+/* combo jack auto switch control 2 (0x46)(NID:20h) */
+#define RT711_COMBOJACK_AUTO_DET_STATUS (0x1 << 11)
+#define RT711_COMBOJACK_AUTO_DET_TRS (0x1 << 10)
+#define RT711_COMBOJACK_AUTO_DET_CTIA (0x1 << 9)
+#define RT711_COMBOJACK_AUTO_DET_OMTP (0x1 << 8)
+
+/* FSM control (0x6f)(NID:20h) */
+#define RT711_CALI_CTL (0x0 << 0)
+#define RT711_COMBOJACK_CTL (0x1 << 0)
+#define RT711_IMS_CTL (0x2 << 0)
+#define RT711_DEPOP_CTL (0x3 << 0)
+#define RT711_FSM_IMP_EN (0x1 << 6)
+
+/* Impedance Sense Digital Control 1 (0x00)(NID:5bh) */
+#define RT711_TRIGGER_IMS (0x1 << 15)
+#define RT711_IMS_EN (0x1 << 6)
+
+#define RT711_EAPD_HIGH 0x2
+#define RT711_EAPD_LOW 0x0
+#define RT711_MUTE_SFT 7
+/* set input/output mapping to payload[14][15] separately */
+#define RT711_DIR_IN_SFT 6
+#define RT711_DIR_OUT_SFT 7
+
+/* RC Calibration register */
+#define RT711_RC_CAL_STATUS 0x320c
+
+/* Buffer address for HID */
+#define RT711_BUF_ADDR_HID1 0x44030000
+#define RT711_BUF_ADDR_HID2 0x44030020
+
+/* RT711 SDCA Control - function number */
+#define FUNC_NUM_JACK_CODEC 0x01
+#define FUNC_NUM_MIC_ARRAY 0x02
+#define FUNC_NUM_HID 0x03
+
+/* RT711 SDCA entity */
+#define RT711_SDCA_ENT_HID01 0x01
+#define RT711_SDCA_ENT_GE49 0x49
+#define RT711_SDCA_ENT_USER_FU05 0x05
+#define RT711_SDCA_ENT_USER_FU0F 0x0f
+#define RT711_SDCA_ENT_USER_FU1E 0x1e
+#define RT711_SDCA_ENT_PLATFORM_FU15 0x15
+#define RT711_SDCA_ENT_PLATFORM_FU44 0x44
+#define RT711_SDCA_ENT_PDE28 0x28
+#define RT711_SDCA_ENT_PDE29 0x29
+#define RT711_SDCA_ENT_PDE2A 0x2a
+#define RT711_SDCA_ENT_CS01 0x01
+#define RT711_SDCA_ENT_CS11 0x11
+#define RT711_SDCA_ENT_CS1F 0x1f
+#define RT711_SDCA_ENT_OT1 0x06
+#define RT711_SDCA_ENT_LINE1 0x09
+#define RT711_SDCA_ENT_LINE2 0x31
+#define RT711_SDCA_ENT_PDELINE2 0x36
+#define RT711_SDCA_ENT_USER_FU9 0x41
+
+/* RT711 SDCA control */
+#define RT711_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10
+#define RT711_SDCA_CTL_FU_CH_GAIN 0x0b
+#define RT711_SDCA_CTL_FU_MUTE 0x01
+#define RT711_SDCA_CTL_FU_VOLUME 0x02
+#define RT711_SDCA_CTL_HIDTX_CURRENT_OWNER 0x10
+#define RT711_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE 0x11
+#define RT711_SDCA_CTL_HIDTX_MESSAGE_OFFSET 0x12
+#define RT711_SDCA_CTL_HIDTX_MESSAGE_LENGTH 0x13
+#define RT711_SDCA_CTL_SELECTED_MODE 0x01
+#define RT711_SDCA_CTL_DETECTED_MODE 0x02
+#define RT711_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT711_SDCA_CTL_VENDOR_DEF 0x30
+
+/* RT711 SDCA channel */
+#define CH_L 0x01
+#define CH_R 0x02
+
+/* sample frequency index */
+#define RT711_SDCA_RATE_44100HZ 0x08
+#define RT711_SDCA_RATE_48000HZ 0x09
+#define RT711_SDCA_RATE_96000HZ 0x0b
+#define RT711_SDCA_RATE_192000HZ 0x0d
+
+enum {
+ RT711_AIF1,
+ RT711_AIF2,
+ RT711_AIFS,
+};
+
+enum rt711_sdca_jd_src {
+ RT711_JD_NULL,
+ RT711_JD1,
+ RT711_JD2
+};
+
+enum rt711_sdca_ver {
+ RT711_VER_VD0,
+ RT711_VER_VD1
+};
+
+int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave);
+int rt711_sdca_init(struct device *dev, struct regmap *regmap,
+ struct regmap *mbq_regmap, struct sdw_slave *slave);
+
+int rt711_sdca_jack_detect(struct rt711_sdca_priv *rt711, bool *hp, bool *mic);
+#endif /* __RT711_SDCA_H__ */
diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c
index 2beb4286d997..8f5ebe92d407 100644
--- a/sound/soc/codecs/rt711-sdw.c
+++ b/sound/soc/codecs/rt711-sdw.c
@@ -431,7 +431,7 @@ static int rt711_interrupt_callback(struct sdw_slave *slave,
return 0;
}
-static struct sdw_slave_ops rt711_slave_ops = {
+static const struct sdw_slave_ops rt711_slave_ops = {
.read_prop = rt711_read_prop,
.interrupt_callback = rt711_interrupt_callback,
.update_status = rt711_update_status,
diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c
index 047f4e677d78..9f5b2dc16c54 100644
--- a/sound/soc/codecs/rt711.c
+++ b/sound/soc/codecs/rt711.c
@@ -1056,7 +1056,7 @@ static int rt711_pcm_hw_free(struct snd_pcm_substream *substream,
#define RT711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
-static struct snd_soc_dai_ops rt711_ops = {
+static const struct snd_soc_dai_ops rt711_ops = {
.hw_params = rt711_pcm_hw_params,
.hw_free = rt711_pcm_hw_free,
.set_sdw_stream = rt711_set_sdw_stream,
diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c
new file mode 100644
index 000000000000..1350798406f0
--- /dev/null
+++ b/sound/soc/codecs/rt715-sdca-sdw.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt715-sdca-sdw.c -- rt715 ALSA SoC audio driver
+//
+// Copyright(c) 2020 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "rt715-sdca.h"
+#include "rt715-sdca-sdw.h"
+
+static bool rt715_sdca_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x201a ... 0x2027:
+ case 0x2029 ... 0x202a:
+ case 0x202d ... 0x2034:
+ case 0x2200 ... 0x2204:
+ case 0x2206 ... 0x2212:
+ case 0x2230 ... 0x2239:
+ case 0x2f5b:
+ case SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+ RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt715_sdca_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x201b:
+ case 0x201c:
+ case 0x201d:
+ case 0x201f:
+ case 0x2021:
+ case 0x2023:
+ case 0x2230:
+ case 0x202d ... 0x202f: /* BRA */
+ case 0x2200 ... 0x2212: /* i2c debug */
+ case 0x2f07:
+ case 0x2f1b ... 0x2f1e:
+ case 0x2f30 ... 0x2f34:
+ case 0x2f50 ... 0x2f51:
+ case 0x2f53 ... 0x2f59:
+ case 0x2f5c ... 0x2f5f:
+ case SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+ RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00): /* VAD Searching status */
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt715_sdca_mbq_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2000000:
+ case 0x200002b:
+ case 0x2000036:
+ case 0x2000037:
+ case 0x2000039:
+ case 0x6100000:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt715_sdca_mbq_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2000000:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rt715_sdca_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt715_sdca_readable_register,
+ .volatile_reg = rt715_sdca_volatile_register,
+ .max_register = 0x43ffffff,
+ .reg_defaults = rt715_reg_defaults_sdca,
+ .num_reg_defaults = ARRAY_SIZE(rt715_reg_defaults_sdca),
+ .cache_type = REGCACHE_RBTREE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static const struct regmap_config rt715_sdca_mbq_regmap = {
+ .name = "sdw-mbq",
+ .reg_bits = 32,
+ .val_bits = 16,
+ .readable_reg = rt715_sdca_mbq_readable_register,
+ .volatile_reg = rt715_sdca_mbq_volatile_register,
+ .max_register = 0x43ffffff,
+ .reg_defaults = rt715_mbq_reg_defaults_sdca,
+ .num_reg_defaults = ARRAY_SIZE(rt715_mbq_reg_defaults_sdca),
+ .cache_type = REGCACHE_RBTREE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt715_sdca_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev);
+
+ /* Update the status */
+ rt715->status = status;
+
+ /*
+ * Perform initialization only if slave status is present and
+ * hw_init flag is false
+ */
+ if (rt715->hw_init || rt715->status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt715_sdca_io_init(&slave->dev, slave);
+}
+
+static int rt715_sdca_read_prop(struct sdw_slave *slave)
+{
+ struct sdw_slave_prop *prop = &slave->prop;
+ int nval, i;
+ u32 bit;
+ unsigned long addr;
+ struct sdw_dpn_prop *dpn;
+
+ prop->paging_support = true;
+
+ /* first we need to allocate memory for set bits in port lists */
+ prop->source_ports = 0x50;/* BITMAP: 01010000 */
+ prop->sink_ports = 0x0; /* BITMAP: 00000000 */
+
+ 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;
+
+ dpn = prop->src_dpn_prop;
+ i = 0;
+ addr = prop->source_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[i].num = bit;
+ dpn[i].simple_ch_prep_sm = true;
+ dpn[i].ch_prep_timeout = 10;
+ i++;
+ }
+
+ /* set the timeout values */
+ prop->clk_stop_timeout = 20;
+
+ return 0;
+}
+
+static struct sdw_slave_ops rt715_sdca_slave_ops = {
+ .read_prop = rt715_sdca_read_prop,
+ .update_status = rt715_sdca_update_status,
+};
+
+static int rt715_sdca_sdw_probe(struct sdw_slave *slave,
+ const struct sdw_device_id *id)
+{
+ struct regmap *mbq_regmap, *regmap;
+
+ slave->ops = &rt715_sdca_slave_ops;
+
+ /* Regmap Initialization */
+ mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt715_sdca_mbq_regmap);
+ if (IS_ERR(mbq_regmap))
+ return PTR_ERR(mbq_regmap);
+
+ regmap = devm_regmap_init_sdw(slave, &rt715_sdca_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt715_sdca_init(&slave->dev, mbq_regmap, regmap, slave);
+}
+
+static const struct sdw_device_id rt715_sdca_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x3, 0x1, 0),
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt715_sdca_id);
+
+static int __maybe_unused rt715_dev_suspend(struct device *dev)
+{
+ struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev);
+
+ if (!rt715->hw_init)
+ return 0;
+
+ regcache_cache_only(rt715->regmap, true);
+ regcache_mark_dirty(rt715->regmap);
+ regcache_cache_only(rt715->mbq_regmap, true);
+ regcache_mark_dirty(rt715->mbq_regmap);
+
+ return 0;
+}
+
+#define RT715_PROBE_TIMEOUT 5000
+
+static int __maybe_unused rt715_dev_resume(struct device *dev)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev);
+ unsigned long time;
+
+ if (!rt715->hw_init)
+ return 0;
+
+ if (!slave->unattach_request)
+ goto regmap_sync;
+
+ time = wait_for_completion_timeout(&slave->enumeration_complete,
+ msecs_to_jiffies(RT715_PROBE_TIMEOUT));
+ if (!time) {
+ dev_err(&slave->dev, "Enumeration not complete, timed out\n");
+ return -ETIMEDOUT;
+ }
+
+regmap_sync:
+ slave->unattach_request = 0;
+ regcache_cache_only(rt715->regmap, false);
+ regcache_sync_region(rt715->regmap,
+ SDW_SDCA_CTL(FUN_JACK_CODEC, RT715_SDCA_ST_EN, RT715_SDCA_ST_CTRL,
+ CH_00),
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+ RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00));
+ regcache_cache_only(rt715->mbq_regmap, false);
+ regcache_sync_region(rt715->mbq_regmap, 0x2000000, 0x61020ff);
+ regcache_sync_region(rt715->mbq_regmap,
+ SDW_SDCA_CTL(FUN_JACK_CODEC, RT715_SDCA_ST_EN, RT715_SDCA_ST_CTRL,
+ CH_00),
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+ RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00));
+
+ return 0;
+}
+
+static const struct dev_pm_ops rt715_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume)
+ SET_RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL)
+};
+
+static struct sdw_driver rt715_sdw_driver = {
+ .driver = {
+ .name = "rt715-sdca",
+ .owner = THIS_MODULE,
+ .pm = &rt715_pm,
+ },
+ .probe = rt715_sdca_sdw_probe,
+ .ops = &rt715_sdca_slave_ops,
+ .id_table = rt715_sdca_id,
+};
+module_sdw_driver(rt715_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT715 driver SDW SDCA");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt715-sdca-sdw.h b/sound/soc/codecs/rt715-sdca-sdw.h
new file mode 100644
index 000000000000..cd365bb60747
--- /dev/null
+++ b/sound/soc/codecs/rt715-sdca-sdw.h
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt715-sdca-sdw.h -- RT715 ALSA SoC audio driver header
+ *
+ * Copyright(c) 2020 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT715_SDW_SDCA_H__
+#define __RT715_SDW_SDCA_H__
+
+#include <linux/soundwire/sdw_registers.h>
+
+static const struct reg_default rt715_reg_defaults_sdca[] = {
+ { 0x201a, 0x00 },
+ { 0x201e, 0x00 },
+ { 0x2020, 0x00 },
+ { 0x2021, 0x00 },
+ { 0x2022, 0x00 },
+ { 0x2023, 0x00 },
+ { 0x2024, 0x00 },
+ { 0x2025, 0x01 },
+ { 0x2026, 0x00 },
+ { 0x2027, 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 },
+ { 0x2233, 0x00 },
+ { 0x2234, 0x00 },
+ { 0x2235, 0x00 },
+ { 0x2236, 0x00 },
+ { 0x2237, 0x00 },
+ { 0x2238, 0x00 },
+ { 0x2239, 0x00 },
+ { 0x2f01, 0x00 },
+ { 0x2f02, 0x09 },
+ { 0x2f03, 0x0b },
+ { 0x2f04, 0x00 },
+ { 0x2f05, 0x0e },
+ { 0x2f06, 0x01 },
+ { 0x2f08, 0x00 },
+ { 0x2f09, 0x00 },
+ { 0x2f0a, 0x00 },
+ { 0x2f0b, 0x00 },
+ { 0x2f0c, 0x00 },
+ { 0x2f0d, 0x00 },
+ { 0x2f0e, 0x12 },
+ { 0x2f0f, 0x00 },
+ { 0x2f10, 0x00 },
+ { 0x2f11, 0x00 },
+ { 0x2f12, 0x00 },
+ { 0x2f13, 0x00 },
+ { 0x2f14, 0x00 },
+ { 0x2f15, 0x00 },
+ { 0x2f16, 0x00 },
+ { 0x2f17, 0x00 },
+ { 0x2f18, 0x00 },
+ { 0x2f19, 0x03 },
+ { 0x2f1a, 0x00 },
+ { 0x2f1f, 0x10 },
+ { 0x2f20, 0x00 },
+ { 0x2f21, 0x00 },
+ { 0x2f22, 0x00 },
+ { 0x2f23, 0x00 },
+ { 0x2f24, 0x00 },
+ { 0x2f25, 0x00 },
+ { 0x2f52, 0x01 },
+ { 0x2f5a, 0x02 },
+ { 0x2f5b, 0x05 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN,
+ RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_03), 0x01 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_04), 0x01 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_03), 0x01 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_04), 0x01 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+ RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x02 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+ RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+};
+
+static const struct reg_default rt715_mbq_reg_defaults_sdca[] = {
+ { 0x200002b, 0x0420 },
+ { 0x2000036, 0x0000 },
+ { 0x2000037, 0x0000 },
+ { 0x2000039, 0xaa81 },
+ { 0x6100000, 0x0100 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+ RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+ RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+ RT715_SDCA_FU_VOL_CTRL, CH_03), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+ RT715_SDCA_FU_VOL_CTRL, CH_04), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+ RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+ RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+ RT715_SDCA_FU_VOL_CTRL, CH_03), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+ RT715_SDCA_FU_VOL_CTRL, CH_04), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+ RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+ RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_02), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_03), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_04), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_05), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_02), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_03), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_04), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_05), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
+};
+#endif /* __RT715_SDW_SDCA_H__ */
diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c
new file mode 100644
index 000000000000..7db76c19e048
--- /dev/null
+++ b/sound/soc/codecs/rt715-sdca.c
@@ -0,0 +1,1075 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt715-sdca.c -- rt715 ALSA SoC audio driver
+//
+// Copyright(c) 2020 Realtek Semiconductor Corp.
+//
+//
+//
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/platform_device.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 <linux/soundwire/sdw_registers.h>
+
+#include "rt715-sdca.h"
+
+static int rt715_sdca_index_write(struct rt715_sdca_priv *rt715,
+ unsigned int nid, unsigned int reg, unsigned int value)
+{
+ struct regmap *regmap = rt715->mbq_regmap;
+ unsigned int addr;
+ int ret;
+
+ addr = (nid << 20) | reg;
+
+ ret = regmap_write(regmap, addr, value);
+ if (ret < 0)
+ dev_err(&rt715->slave->dev,
+ "Failed to set private value: %08x <= %04x %d\n", ret, addr,
+ value);
+
+ return ret;
+}
+
+static int rt715_sdca_index_read(struct rt715_sdca_priv *rt715,
+ unsigned int nid, unsigned int reg, unsigned int *value)
+{
+ struct regmap *regmap = rt715->mbq_regmap;
+ unsigned int addr;
+ int ret;
+
+ addr = (nid << 20) | reg;
+
+ ret = regmap_read(regmap, addr, value);
+ if (ret < 0)
+ dev_err(&rt715->slave->dev,
+ "Failed to get private value: %06x => %04x ret=%d\n",
+ addr, *value, ret);
+
+ return ret;
+}
+
+static int rt715_sdca_index_update_bits(struct rt715_sdca_priv *rt715,
+ unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val)
+{
+ unsigned int tmp;
+ int ret;
+
+ ret = rt715_sdca_index_read(rt715, nid, reg, &tmp);
+ if (ret < 0)
+ return ret;
+
+ set_mask_bits(&tmp, mask, val);
+
+ return rt715_sdca_index_write(rt715, nid, reg, tmp);
+}
+
+static inline unsigned int rt715_sdca_vol_gain(unsigned int u_ctrl_val,
+ unsigned int vol_max, unsigned int vol_gain_sft)
+{
+ unsigned int val;
+
+ if (u_ctrl_val > vol_max)
+ u_ctrl_val = vol_max;
+ val = u_ctrl_val;
+ u_ctrl_val =
+ ((abs(u_ctrl_val - vol_gain_sft) * RT715_SDCA_DB_STEP) << 8) / 1000;
+ if (val <= vol_gain_sft) {
+ u_ctrl_val = ~u_ctrl_val;
+ u_ctrl_val += 1;
+ }
+ u_ctrl_val &= 0xffff;
+
+ return u_ctrl_val;
+}
+
+static inline unsigned int rt715_sdca_boost_gain(unsigned int u_ctrl_val,
+ unsigned int b_max, unsigned int b_gain_sft)
+{
+ if (u_ctrl_val > b_max)
+ u_ctrl_val = b_max;
+
+ return (u_ctrl_val * 10) << b_gain_sft;
+}
+
+static inline unsigned int rt715_sdca_get_gain(unsigned int reg_val,
+ unsigned int gain_sft)
+{
+ unsigned int neg_flag = 0;
+
+ if (reg_val & BIT(15)) {
+ reg_val = ~(reg_val - 1) & 0xffff;
+ neg_flag = 1;
+ }
+ reg_val *= 1000;
+ reg_val >>= 8;
+ if (neg_flag)
+ reg_val = gain_sft - reg_val / RT715_SDCA_DB_STEP;
+ else
+ reg_val = gain_sft + reg_val / RT715_SDCA_DB_STEP;
+
+ return reg_val;
+}
+
+/* SDCA Volume/Boost control */
+static int rt715_sdca_set_amp_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 rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+ unsigned int gain_val, i, k_changed = 0;
+ int ret;
+
+ for (i = 0; i < 2; i++) {
+ if (ucontrol->value.integer.value[i] != rt715->kctl_2ch_orig[i]) {
+ k_changed = 1;
+ break;
+ }
+ }
+
+ for (i = 0; i < 2; i++) {
+ rt715->kctl_2ch_orig[i] = ucontrol->value.integer.value[i];
+ gain_val =
+ rt715_sdca_vol_gain(ucontrol->value.integer.value[i], mc->max,
+ mc->shift);
+ ret = regmap_write(rt715->mbq_regmap, mc->reg + i, gain_val);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to write 0x%x=0x%x\n",
+ mc->reg + i, gain_val);
+ return ret;
+ }
+ }
+
+ return k_changed;
+}
+
+static int rt715_sdca_set_amp_gain_4ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+ struct rt715_sdca_kcontrol_private *p =
+ (struct rt715_sdca_kcontrol_private *)kcontrol->private_value;
+ unsigned int reg_base = p->reg_base, k_changed = 0;
+ const unsigned int gain_sft = 0x2f;
+ unsigned int gain_val, i;
+ int ret;
+
+ for (i = 0; i < 4; i++) {
+ if (ucontrol->value.integer.value[i] != rt715->kctl_4ch_orig[i]) {
+ k_changed = 1;
+ break;
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ rt715->kctl_4ch_orig[i] = ucontrol->value.integer.value[i];
+ gain_val =
+ rt715_sdca_vol_gain(ucontrol->value.integer.value[i], p->max,
+ gain_sft);
+ ret = regmap_write(rt715->mbq_regmap, reg_base + i,
+ gain_val);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to write 0x%x=0x%x\n",
+ reg_base + i, gain_val);
+ return ret;
+ }
+ }
+
+ return k_changed;
+}
+
+static int rt715_sdca_set_amp_gain_8ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+ struct rt715_sdca_kcontrol_private *p =
+ (struct rt715_sdca_kcontrol_private *)kcontrol->private_value;
+ unsigned int reg_base = p->reg_base, i, k_changed = 0;
+ const unsigned int gain_sft = 8;
+ unsigned int gain_val, reg;
+ int ret;
+
+ for (i = 0; i < 8; i++) {
+ if (ucontrol->value.integer.value[i] != rt715->kctl_8ch_orig[i]) {
+ k_changed = 1;
+ break;
+ }
+ }
+
+ for (i = 0; i < 8; i++) {
+ rt715->kctl_8ch_orig[i] = ucontrol->value.integer.value[i];
+ gain_val =
+ rt715_sdca_boost_gain(ucontrol->value.integer.value[i], p->max,
+ gain_sft);
+ reg = i < 7 ? reg_base + i : (reg_base - 1) | BIT(15);
+ ret = regmap_write(rt715->mbq_regmap, reg, gain_val);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to write 0x%x=0x%x\n",
+ reg, gain_val);
+ return ret;
+ }
+ }
+
+ return k_changed;
+}
+
+static int rt715_sdca_set_amp_gain_get(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 rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+ unsigned int val, i;
+ int ret;
+
+ for (i = 0; i < 2; i++) {
+ ret = regmap_read(rt715->mbq_regmap, mc->reg + i, &val);
+ if (ret < 0) {
+ dev_err(component->dev, "Failed to read 0x%x, ret=%d\n",
+ mc->reg + i, ret);
+ return ret;
+ }
+ ucontrol->value.integer.value[i] = rt715_sdca_get_gain(val, mc->shift);
+ }
+
+ return 0;
+}
+
+static int rt715_sdca_set_amp_gain_4ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+ struct rt715_sdca_kcontrol_private *p =
+ (struct rt715_sdca_kcontrol_private *)kcontrol->private_value;
+ unsigned int reg_base = p->reg_base, i;
+ const unsigned int gain_sft = 0x2f;
+ unsigned int val;
+ int ret;
+
+ for (i = 0; i < 4; i++) {
+ ret = regmap_read(rt715->mbq_regmap, reg_base + i, &val);
+ if (ret < 0) {
+ dev_err(component->dev, "Failed to read 0x%x, ret=%d\n",
+ reg_base + i, ret);
+ return ret;
+ }
+ ucontrol->value.integer.value[i] = rt715_sdca_get_gain(val, gain_sft);
+ }
+
+ return 0;
+}
+
+static int rt715_sdca_set_amp_gain_8ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+ struct rt715_sdca_kcontrol_private *p =
+ (struct rt715_sdca_kcontrol_private *)kcontrol->private_value;
+ unsigned int reg_base = p->reg_base;
+ const unsigned int gain_sft = 8;
+ unsigned int val_l, val_r;
+ unsigned int i, reg;
+ int ret;
+
+ for (i = 0; i < 8; i += 2) {
+ ret = regmap_read(rt715->mbq_regmap, reg_base + i, &val_l);
+ if (ret < 0) {
+ dev_err(component->dev, "Failed to read 0x%x, ret=%d\n",
+ reg_base + i, ret);
+ return ret;
+ }
+ ucontrol->value.integer.value[i] = (val_l >> gain_sft) / 10;
+
+ reg = (i == 6) ? (reg_base - 1) | BIT(15) : reg_base + 1 + i;
+ ret = regmap_read(rt715->mbq_regmap, reg, &val_r);
+ if (ret < 0) {
+ dev_err(component->dev, "Failed to read 0x%x, ret=%d\n",
+ reg, ret);
+ return ret;
+ }
+ ucontrol->value.integer.value[i + 1] = (val_r >> gain_sft) / 10;
+ }
+
+ return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
+
+static int rt715_sdca_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt715_sdca_kcontrol_private *p =
+ (struct rt715_sdca_kcontrol_private *)kcontrol->private_value;
+ unsigned int reg_base = p->reg_base;
+ unsigned int invert = p->invert, i;
+ int val;
+
+ for (i = 0; i < p->count; i += 2) {
+ val = snd_soc_component_read(component, reg_base + i);
+ if (val < 0)
+ return -EINVAL;
+ ucontrol->value.integer.value[i] = invert ? p->max - val : val;
+
+ val = snd_soc_component_read(component, reg_base + 1 + i);
+ if (val < 0)
+ return -EINVAL;
+ ucontrol->value.integer.value[i + 1] =
+ invert ? p->max - val : val;
+ }
+
+ return 0;
+}
+
+static int rt715_sdca_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+ struct rt715_sdca_kcontrol_private *p =
+ (struct rt715_sdca_kcontrol_private *)kcontrol->private_value;
+ unsigned int val[4] = {0}, val_mask, i, k_changed = 0;
+ unsigned int reg = p->reg_base;
+ unsigned int shift = p->shift;
+ unsigned int max = p->max;
+ unsigned int mask = (1 << fls(max)) - 1;
+ unsigned int invert = p->invert;
+ int err;
+
+ for (i = 0; i < 4; i++) {
+ if (ucontrol->value.integer.value[i] != rt715->kctl_switch_orig[i]) {
+ k_changed = 1;
+ break;
+ }
+ }
+
+ for (i = 0; i < 2; i++) {
+ rt715->kctl_switch_orig[i * 2] = ucontrol->value.integer.value[i * 2];
+ val[i * 2] = ucontrol->value.integer.value[i * 2] & mask;
+ if (invert)
+ val[i * 2] = max - val[i * 2];
+ val_mask = mask << shift;
+ val[i * 2] <<= shift;
+
+ rt715->kctl_switch_orig[i * 2 + 1] =
+ ucontrol->value.integer.value[i * 2 + 1];
+ val[i * 2 + 1] =
+ ucontrol->value.integer.value[i * 2 + 1] & mask;
+ if (invert)
+ val[i * 2 + 1] = max - val[i * 2 + 1];
+
+ val[i * 2 + 1] <<= shift;
+
+ err = snd_soc_component_update_bits(component, reg + i * 2, val_mask,
+ val[i * 2]);
+ if (err < 0)
+ return err;
+
+ err = snd_soc_component_update_bits(component, reg + 1 + i * 2,
+ val_mask, val[i * 2 + 1]);
+ if (err < 0)
+ return err;
+ }
+
+ return k_changed;
+}
+
+static int rt715_sdca_fu_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct rt715_sdca_kcontrol_private *p =
+ (struct rt715_sdca_kcontrol_private *)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 RT715_SDCA_PR_VALUE(xreg_base, xcount, xmax, xshift, xinvert) \
+ ((unsigned long)&(struct rt715_sdca_kcontrol_private) \
+ {.reg_base = xreg_base, .count = xcount, .max = xmax, \
+ .shift = xshift, .invert = xinvert})
+
+#define RT715_SDCA_FU_CTRL(xname, reg_base, xshift, xmax, xinvert, xcount) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .info = rt715_sdca_fu_info, \
+ .get = rt715_sdca_get_volsw, \
+ .put = rt715_sdca_put_volsw, \
+ .private_value = RT715_SDCA_PR_VALUE(reg_base, xcount, xmax, \
+ xshift, xinvert)}
+
+#define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\
+ xhandler_get, xhandler_put) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .info = snd_soc_info_volsw, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
+ xmax, xinvert) }
+
+#define RT715_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\
+ xhandler_put, tlv_array, xcount, xmax) \
+{ .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 = rt715_sdca_fu_info, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = RT715_SDCA_PR_VALUE(reg_base, xcount, xmax, 0, 0) }
+
+#define RT715_SDCA_BOOST_EXT_TLV(xname, reg_base, xhandler_get,\
+ xhandler_put, tlv_array, xcount, xmax) \
+{ .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 = rt715_sdca_fu_info, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = RT715_SDCA_PR_VALUE(reg_base, xcount, xmax, 0, 0) }
+
+static const struct snd_kcontrol_new rt715_sdca_snd_controls[] = {
+ /* Capture switch */
+ SOC_DOUBLE_R("FU0A Capture Switch",
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_01),
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_02),
+ 0, 1, 1),
+ RT715_SDCA_FU_CTRL("FU02 Capture Switch",
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_01),
+ 0, 1, 1, 4),
+ RT715_SDCA_FU_CTRL("FU06 Capture Switch",
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+ RT715_SDCA_FU_MUTE_CTRL, CH_01),
+ 0, 1, 1, 4),
+ /* Volume Control */
+ SOC_DOUBLE_R_EXT_TLV("FU0A Capture Volume",
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+ RT715_SDCA_FU_VOL_CTRL, CH_01),
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
+ RT715_SDCA_FU_VOL_CTRL, CH_02),
+ 0x2f, 0x7f, 0,
+ rt715_sdca_set_amp_gain_get, rt715_sdca_set_amp_gain_put,
+ in_vol_tlv),
+ RT715_SDCA_EXT_TLV("FU02 Capture Volume",
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
+ RT715_SDCA_FU_VOL_CTRL, CH_01),
+ rt715_sdca_set_amp_gain_4ch_get,
+ rt715_sdca_set_amp_gain_4ch_put,
+ in_vol_tlv, 4, 0x7f),
+ RT715_SDCA_EXT_TLV("FU06 Capture Volume",
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
+ RT715_SDCA_FU_VOL_CTRL, CH_01),
+ rt715_sdca_set_amp_gain_4ch_get,
+ rt715_sdca_set_amp_gain_4ch_put,
+ in_vol_tlv, 4, 0x7f),
+ /* MIC Boost Control */
+ RT715_SDCA_BOOST_EXT_TLV("FU0E Boost",
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01),
+ rt715_sdca_set_amp_gain_8ch_get,
+ rt715_sdca_set_amp_gain_8ch_put,
+ mic_vol_tlv, 8, 3),
+ RT715_SDCA_BOOST_EXT_TLV("FU0C Boost",
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01),
+ rt715_sdca_set_amp_gain_8ch_get,
+ rt715_sdca_set_amp_gain_8ch_put,
+ mic_vol_tlv, 8, 3),
+};
+
+static int rt715_sdca_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_kcontrol_component(kcontrol);
+ struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+ unsigned int val, mask_sft;
+
+ if (strstr(ucontrol->id.name, "ADC 22 Mux"))
+ mask_sft = 12;
+ else if (strstr(ucontrol->id.name, "ADC 23 Mux"))
+ mask_sft = 8;
+ else if (strstr(ucontrol->id.name, "ADC 24 Mux"))
+ mask_sft = 4;
+ else if (strstr(ucontrol->id.name, "ADC 25 Mux"))
+ mask_sft = 0;
+ else
+ return -EINVAL;
+
+ rt715_sdca_index_read(rt715, RT715_VENDOR_HDA_CTL,
+ RT715_HDA_LEGACY_MUX_CTL1, &val);
+ val = (val >> mask_sft) & 0xf;
+
+ /*
+ * The first two indices of ADC Mux 24/25 are routed to the same
+ * hardware source. ie, ADC Mux 24 0/1 will both connect to MIC2.
+ * To have a unique set of inputs, we skip the index1 of the muxes.
+ */
+ if ((strstr(ucontrol->id.name, "ADC 24 Mux") ||
+ strstr(ucontrol->id.name, "ADC 25 Mux")) && val > 0)
+ val -= 1;
+ ucontrol->value.enumerated.item[0] = val;
+
+ return 0;
+}
+
+static int rt715_sdca_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 rt715_sdca_priv *rt715 = 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 22 Mux"))
+ mask_sft = 12;
+ else if (strstr(ucontrol->id.name, "ADC 23 Mux"))
+ mask_sft = 8;
+ else if (strstr(ucontrol->id.name, "ADC 24 Mux"))
+ mask_sft = 4;
+ else if (strstr(ucontrol->id.name, "ADC 25 Mux"))
+ mask_sft = 0;
+ else
+ return -EINVAL;
+
+ /* Verb ID = 0x701h, nid = e->reg */
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+
+ rt715_sdca_index_read(rt715, RT715_VENDOR_HDA_CTL,
+ RT715_HDA_LEGACY_MUX_CTL1, &val2);
+ val2 = (val2 >> mask_sft) & 0xf;
+
+ change = val != val2;
+
+ if (change)
+ rt715_sdca_index_update_bits(rt715, RT715_VENDOR_HDA_CTL,
+ RT715_HDA_LEGACY_MUX_CTL1, 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_22_23_mux_text[] = {
+ "MIC1",
+ "MIC2",
+ "LINE1",
+ "LINE2",
+ "DMIC1",
+ "DMIC2",
+ "DMIC3",
+ "DMIC4",
+};
+
+/*
+ * Due to mux design for nid 24 (MUX_IN3)/25 (MUX_IN4), connection index 0 and
+ * 1 will be connected to the same dmic source, therefore we skip index 1 to
+ * avoid misunderstanding on usage of dapm routing.
+ */
+static int rt715_adc_24_25_values[] = {
+ 0,
+ 2,
+ 3,
+ 4,
+ 5,
+};
+
+static const char * const adc_24_mux_text[] = {
+ "MIC2",
+ "DMIC1",
+ "DMIC2",
+ "DMIC3",
+ "DMIC4",
+};
+
+static const char * const adc_25_mux_text[] = {
+ "MIC1",
+ "DMIC1",
+ "DMIC2",
+ "DMIC3",
+ "DMIC4",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt715_adc22_enum, SND_SOC_NOPM, 0,
+ adc_22_23_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(rt715_adc23_enum, SND_SOC_NOPM, 0,
+ adc_22_23_mux_text);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc24_enum,
+ SND_SOC_NOPM, 0, 0xf,
+ adc_24_mux_text, rt715_adc_24_25_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc25_enum,
+ SND_SOC_NOPM, 0, 0xf,
+ adc_25_mux_text, rt715_adc_24_25_values);
+
+static const struct snd_kcontrol_new rt715_adc22_mux =
+ SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt715_adc22_enum,
+ rt715_sdca_mux_get, rt715_sdca_mux_put);
+
+static const struct snd_kcontrol_new rt715_adc23_mux =
+ SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt715_adc23_enum,
+ rt715_sdca_mux_get, rt715_sdca_mux_put);
+
+static const struct snd_kcontrol_new rt715_adc24_mux =
+ SOC_DAPM_ENUM_EXT("ADC 24 Mux", rt715_adc24_enum,
+ rt715_sdca_mux_get, rt715_sdca_mux_put);
+
+static const struct snd_kcontrol_new rt715_adc25_mux =
+ SOC_DAPM_ENUM_EXT("ADC 25 Mux", rt715_adc25_enum,
+ rt715_sdca_mux_get, rt715_sdca_mux_put);
+
+static int rt715_sdca_pde23_24_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 rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt715->regmap,
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CREQ_POW_EN,
+ RT715_SDCA_REQ_POW_CTRL,
+ CH_00), 0x00);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt715->regmap,
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CREQ_POW_EN,
+ RT715_SDCA_REQ_POW_CTRL,
+ CH_00), 0x03);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt715_sdca_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("DMIC1"),
+ SND_SOC_DAPM_INPUT("DMIC2"),
+ SND_SOC_DAPM_INPUT("DMIC3"),
+ SND_SOC_DAPM_INPUT("DMIC4"),
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("LINE1"),
+ SND_SOC_DAPM_INPUT("LINE2"),
+
+ SND_SOC_DAPM_SUPPLY("PDE23_24", SND_SOC_NOPM, 0, 0,
+ rt715_sdca_pde23_24_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_ADC("ADC 07", NULL, SND_SOC_NOPM, 4, 0),
+ SND_SOC_DAPM_ADC("ADC 08", NULL, SND_SOC_NOPM, 4, 0),
+ SND_SOC_DAPM_ADC("ADC 09", NULL, SND_SOC_NOPM, 4, 0),
+ SND_SOC_DAPM_ADC("ADC 27", NULL, SND_SOC_NOPM, 4, 0),
+ SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0,
+ &rt715_adc22_mux),
+ SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0,
+ &rt715_adc23_mux),
+ SND_SOC_DAPM_MUX("ADC 24 Mux", SND_SOC_NOPM, 0, 0,
+ &rt715_adc24_mux),
+ SND_SOC_DAPM_MUX("ADC 25 Mux", SND_SOC_NOPM, 0, 0,
+ &rt715_adc25_mux),
+ SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP6TX", "DP6 Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt715_sdca_audio_map[] = {
+ {"DP6TX", NULL, "ADC 09"},
+ {"DP6TX", NULL, "ADC 08"},
+ {"DP4TX", NULL, "ADC 07"},
+ {"DP4TX", NULL, "ADC 27"},
+ {"DP4TX", NULL, "ADC 09"},
+ {"DP4TX", NULL, "ADC 08"},
+
+ {"LINE1", NULL, "PDE23_24"},
+ {"LINE2", NULL, "PDE23_24"},
+ {"MIC1", NULL, "PDE23_24"},
+ {"MIC2", NULL, "PDE23_24"},
+ {"DMIC1", NULL, "PDE23_24"},
+ {"DMIC2", NULL, "PDE23_24"},
+ {"DMIC3", NULL, "PDE23_24"},
+ {"DMIC4", NULL, "PDE23_24"},
+
+ {"ADC 09", NULL, "ADC 22 Mux"},
+ {"ADC 08", NULL, "ADC 23 Mux"},
+ {"ADC 07", NULL, "ADC 24 Mux"},
+ {"ADC 27", NULL, "ADC 25 Mux"},
+ {"ADC 22 Mux", "MIC1", "MIC1"},
+ {"ADC 22 Mux", "MIC2", "MIC2"},
+ {"ADC 22 Mux", "LINE1", "LINE1"},
+ {"ADC 22 Mux", "LINE2", "LINE2"},
+ {"ADC 22 Mux", "DMIC1", "DMIC1"},
+ {"ADC 22 Mux", "DMIC2", "DMIC2"},
+ {"ADC 22 Mux", "DMIC3", "DMIC3"},
+ {"ADC 22 Mux", "DMIC4", "DMIC4"},
+ {"ADC 23 Mux", "MIC1", "MIC1"},
+ {"ADC 23 Mux", "MIC2", "MIC2"},
+ {"ADC 23 Mux", "LINE1", "LINE1"},
+ {"ADC 23 Mux", "LINE2", "LINE2"},
+ {"ADC 23 Mux", "DMIC1", "DMIC1"},
+ {"ADC 23 Mux", "DMIC2", "DMIC2"},
+ {"ADC 23 Mux", "DMIC3", "DMIC3"},
+ {"ADC 23 Mux", "DMIC4", "DMIC4"},
+ {"ADC 24 Mux", "MIC2", "MIC2"},
+ {"ADC 24 Mux", "DMIC1", "DMIC1"},
+ {"ADC 24 Mux", "DMIC2", "DMIC2"},
+ {"ADC 24 Mux", "DMIC3", "DMIC3"},
+ {"ADC 24 Mux", "DMIC4", "DMIC4"},
+ {"ADC 25 Mux", "MIC1", "MIC1"},
+ {"ADC 25 Mux", "DMIC1", "DMIC1"},
+ {"ADC 25 Mux", "DMIC2", "DMIC2"},
+ {"ADC 25 Mux", "DMIC3", "DMIC3"},
+ {"ADC 25 Mux", "DMIC4", "DMIC4"},
+};
+
+static const struct snd_soc_component_driver soc_codec_dev_rt715_sdca = {
+ .controls = rt715_sdca_snd_controls,
+ .num_controls = ARRAY_SIZE(rt715_sdca_snd_controls),
+ .dapm_widgets = rt715_sdca_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt715_sdca_dapm_widgets),
+ .dapm_routes = rt715_sdca_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rt715_sdca_audio_map),
+};
+
+static int rt715_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+ int direction)
+{
+ struct rt715_sdw_stream_data *stream;
+
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (!stream)
+ return -ENOMEM;
+
+ stream->sdw_stream = sdw_stream;
+
+ /* Use tx_mask or rx_mask to configure stream tag and set dma_data */
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ dai->playback_dma_data = stream;
+ else
+ dai->capture_dma_data = stream;
+
+ return 0;
+}
+
+static void rt715_sdca_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+
+{
+ struct rt715_sdw_stream_data *stream;
+
+ stream = snd_soc_dai_get_dma_data(dai, substream);
+ if (!stream)
+ return;
+
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+ kfree(stream);
+}
+
+static int rt715_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_config stream_config;
+ struct sdw_port_config port_config;
+ enum sdw_data_direction direction;
+ struct rt715_sdw_stream_data *stream;
+ int retval, port, num_channels;
+ unsigned int val;
+
+ stream = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!stream)
+ return -EINVAL;
+
+ if (!rt715->slave)
+ return -EINVAL;
+
+ switch (dai->id) {
+ case RT715_AIF1:
+ direction = SDW_DATA_DIR_TX;
+ port = 6;
+ rt715_sdca_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL,
+ 0xa500);
+ break;
+ case RT715_AIF2:
+ direction = SDW_DATA_DIR_TX;
+ port = 4;
+ rt715_sdca_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL,
+ 0xaf00);
+ break;
+ default:
+ dev_err(component->dev, "Invalid DAI id %d\n", dai->id);
+ return -EINVAL;
+ }
+
+ stream_config.frame_rate = params_rate(params);
+ stream_config.ch_count = params_channels(params);
+ stream_config.bps = snd_pcm_format_width(params_format(params));
+ stream_config.direction = direction;
+
+ num_channels = params_channels(params);
+ port_config.ch_mask = GENMASK(num_channels - 1, 0);
+ port_config.num = port;
+
+ retval = sdw_stream_add_slave(rt715->slave, &stream_config,
+ &port_config, 1, stream->sdw_stream);
+ if (retval) {
+ dev_err(component->dev, "Unable to configure port, retval:%d\n",
+ retval);
+ return retval;
+ }
+
+ switch (params_rate(params)) {
+ case 8000:
+ val = 0x1;
+ break;
+ case 11025:
+ val = 0x2;
+ break;
+ case 12000:
+ val = 0x3;
+ break;
+ case 16000:
+ val = 0x4;
+ break;
+ case 22050:
+ val = 0x5;
+ break;
+ case 24000:
+ val = 0x6;
+ break;
+ case 32000:
+ val = 0x7;
+ break;
+ case 44100:
+ val = 0x8;
+ break;
+ case 48000:
+ val = 0x9;
+ break;
+ case 88200:
+ val = 0xa;
+ break;
+ case 96000:
+ val = 0xb;
+ break;
+ case 176400:
+ val = 0xc;
+ break;
+ case 192000:
+ val = 0xd;
+ break;
+ case 384000:
+ val = 0xe;
+ break;
+ case 768000:
+ val = 0xf;
+ break;
+ default:
+ dev_err(component->dev, "Unsupported sample rate %d\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ regmap_write(rt715->regmap,
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CS_FREQ_IND_EN,
+ RT715_SDCA_FREQ_IND_CTRL, CH_00), val);
+
+ return 0;
+}
+
+static int rt715_sdca_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
+ struct rt715_sdw_stream_data *stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt715->slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt715->slave, stream->sdw_stream);
+ return 0;
+}
+
+#define RT715_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define RT715_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 rt715_sdca_ops = {
+ .hw_params = rt715_sdca_pcm_hw_params,
+ .hw_free = rt715_sdca_pcm_hw_free,
+ .set_sdw_stream = rt715_sdca_set_sdw_stream,
+ .shutdown = rt715_sdca_shutdown,
+};
+
+static struct snd_soc_dai_driver rt715_sdca_dai[] = {
+ {
+ .name = "rt715-aif1",
+ .id = RT715_AIF1,
+ .capture = {
+ .stream_name = "DP6 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT715_STEREO_RATES,
+ .formats = RT715_FORMATS,
+ },
+ .ops = &rt715_sdca_ops,
+ },
+ {
+ .name = "rt715-aif2",
+ .id = RT715_AIF2,
+ .capture = {
+ .stream_name = "DP4 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT715_STEREO_RATES,
+ .formats = RT715_FORMATS,
+ },
+ .ops = &rt715_sdca_ops,
+ },
+};
+
+/* Bus clock frequency */
+#define RT715_CLK_FREQ_9600000HZ 9600000
+#define RT715_CLK_FREQ_12000000HZ 12000000
+#define RT715_CLK_FREQ_6000000HZ 6000000
+#define RT715_CLK_FREQ_4800000HZ 4800000
+#define RT715_CLK_FREQ_2400000HZ 2400000
+#define RT715_CLK_FREQ_12288000HZ 12288000
+
+int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap,
+ struct regmap *regmap, struct sdw_slave *slave)
+{
+ struct rt715_sdca_priv *rt715;
+ int ret;
+
+ rt715 = devm_kzalloc(dev, sizeof(*rt715), GFP_KERNEL);
+ if (!rt715)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt715);
+ rt715->slave = slave;
+ rt715->regmap = regmap;
+ rt715->mbq_regmap = mbq_regmap;
+ rt715->hw_sdw_ver = slave->id.sdw_version;
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt715->hw_init = false;
+ rt715->first_init = false;
+
+ ret = devm_snd_soc_register_component(dev,
+ &soc_codec_dev_rt715_sdca,
+ rt715_sdca_dai,
+ ARRAY_SIZE(rt715_sdca_dai));
+
+ return ret;
+}
+
+int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev);
+ unsigned int hw_ver;
+
+ if (rt715->hw_init)
+ return 0;
+
+ /*
+ * PM runtime is only enabled when a Slave reports as Attached
+ */
+ if (!rt715->first_init) {
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
+ pm_runtime_use_autosuspend(&slave->dev);
+
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(&slave->dev);
+
+ pm_runtime_enable(&slave->dev);
+
+ rt715->first_init = true;
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+
+ rt715_sdca_index_read(rt715, RT715_VENDOR_REG,
+ RT715_PRODUCT_NUM, &hw_ver);
+ hw_ver = hw_ver & 0x000f;
+
+ /* set clock selector = external */
+ regmap_write(rt715->regmap,
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN,
+ RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1);
+ /* set GPIO_4/5/6 to be 3rd/4th DMIC usage */
+ if (hw_ver == 0x0)
+ rt715_sdca_index_update_bits(rt715, RT715_VENDOR_REG,
+ RT715_AD_FUNC_EN, 0x54, 0x54);
+ else if (hw_ver == 0x1) {
+ rt715_sdca_index_update_bits(rt715, RT715_VENDOR_REG,
+ RT715_AD_FUNC_EN, 0x55, 0x55);
+ rt715_sdca_index_update_bits(rt715, RT715_VENDOR_REG,
+ RT715_REV_1, 0x40, 0x40);
+ }
+ /* trigger mode = VAD enable */
+ regmap_write(rt715->regmap,
+ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
+ RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x2);
+ /* SMPU-1 interrupt enable mask */
+ regmap_update_bits(rt715->regmap, RT715_INT_MASK, 0x1, 0x1);
+
+ /* Mark Slave initialization complete */
+ rt715->hw_init = true;
+
+ pm_runtime_mark_last_busy(&slave->dev);
+ pm_runtime_put_autosuspend(&slave->dev);
+
+ return 0;
+}
+
+MODULE_DESCRIPTION("ASoC rt715 driver SDW SDCA");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt715-sdca.h b/sound/soc/codecs/rt715-sdca.h
new file mode 100644
index 000000000000..85ce4d95e5eb
--- /dev/null
+++ b/sound/soc/codecs/rt715-sdca.h
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt715-sdca.h -- RT715 ALSA SoC audio driver header
+ *
+ * Copyright(c) 2020 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT715_SDCA_H__
+#define __RT715_SDCA_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+
+struct rt715_sdca_priv {
+ struct regmap *regmap;
+ struct regmap *mbq_regmap;
+ struct snd_soc_codec *codec;
+ struct sdw_slave *slave;
+ struct delayed_work adc_mute_work;
+ int dbg_nid;
+ int dbg_vid;
+ int dbg_payload;
+ enum sdw_slave_status status;
+ struct sdw_bus_params params;
+ bool hw_init;
+ bool first_init;
+ int l_is_unmute;
+ int r_is_unmute;
+ int hw_sdw_ver;
+ int kctl_switch_orig[4];
+ int kctl_2ch_orig[2];
+ int kctl_4ch_orig[4];
+ int kctl_8ch_orig[8];
+};
+
+struct rt715_sdw_stream_data {
+ struct sdw_stream_runtime *sdw_stream;
+};
+
+struct rt715_sdca_kcontrol_private {
+ unsigned int reg_base;
+ unsigned int count;
+ unsigned int max;
+ unsigned int shift;
+ unsigned int invert;
+};
+
+/* MIPI Register */
+#define RT715_INT_CTRL 0x005a
+#define RT715_INT_MASK 0x005e
+
+/* NID */
+#define RT715_AUDIO_FUNCTION_GROUP 0x01
+#define RT715_MIC_ADC 0x07
+#define RT715_LINE_ADC 0x08
+#define RT715_MIX_ADC 0x09
+#define RT715_DMIC1 0x12
+#define RT715_DMIC2 0x13
+#define RT715_MIC1 0x18
+#define RT715_MIC2 0x19
+#define RT715_LINE1 0x1a
+#define RT715_LINE2 0x1b
+#define RT715_DMIC3 0x1d
+#define RT715_DMIC4 0x29
+#define RT715_VENDOR_REG 0x20
+#define RT715_MUX_IN1 0x22
+#define RT715_MUX_IN2 0x23
+#define RT715_MUX_IN3 0x24
+#define RT715_MUX_IN4 0x25
+#define RT715_MIX_ADC2 0x27
+#define RT715_INLINE_CMD 0x55
+#define RT715_VENDOR_HDA_CTL 0x61
+
+/* Index (NID:20h) */
+#define RT715_PRODUCT_NUM 0x0
+#define RT715_IRQ_CTRL 0x2b
+#define RT715_AD_FUNC_EN 0x36
+#define RT715_REV_1 0x37
+#define RT715_SDW_INPUT_SEL 0x39
+#define RT715_EXT_DMIC_CLK_CTRL2 0x54
+
+/* Index (NID:61h) */
+#define RT715_HDA_LEGACY_MUX_CTL1 0x00
+
+/* SDCA (Function) */
+#define FUN_JACK_CODEC 0x01
+#define FUN_MIC_ARRAY 0x02
+#define FUN_HID 0x03
+/* SDCA (Entity) */
+#define RT715_SDCA_ST_EN 0x00
+#define RT715_SDCA_CS_FREQ_IND_EN 0x01
+#define RT715_SDCA_FU_ADC8_9_VOL 0x02
+#define RT715_SDCA_SMPU_TRIG_ST_EN 0x05
+#define RT715_SDCA_FU_ADC10_11_VOL 0x06
+#define RT715_SDCA_FU_ADC7_27_VOL 0x0a
+#define RT715_SDCA_FU_AMIC_GAIN_EN 0x0c
+#define RT715_SDCA_FU_DMIC_GAIN_EN 0x0e
+#define RT715_SDCA_CX_CLK_SEL_EN 0x10
+#define RT715_SDCA_CREQ_POW_EN 0x18
+/* SDCA (Control) */
+#define RT715_SDCA_ST_CTRL 0x00
+#define RT715_SDCA_CX_CLK_SEL_CTRL 0x01
+#define RT715_SDCA_REQ_POW_CTRL 0x01
+#define RT715_SDCA_FU_MUTE_CTRL 0x01
+#define RT715_SDCA_FU_VOL_CTRL 0x02
+#define RT715_SDCA_FU_DMIC_GAIN_CTRL 0x0b
+#define RT715_SDCA_FREQ_IND_CTRL 0x10
+#define RT715_SDCA_SMPU_TRIG_EN_CTRL 0x10
+#define RT715_SDCA_SMPU_TRIG_ST_CTRL 0x11
+/* SDCA (Channel) */
+#define CH_00 0x00
+#define CH_01 0x01
+#define CH_02 0x02
+#define CH_03 0x03
+#define CH_04 0x04
+#define CH_05 0x05
+#define CH_06 0x06
+#define CH_07 0x07
+#define CH_08 0x08
+
+#define RT715_SDCA_DB_STEP 375
+
+enum {
+ RT715_AIF1,
+ RT715_AIF2,
+};
+
+int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave);
+int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap,
+ struct regmap *regmap, struct sdw_slave *slave);
+
+#endif /* __RT715_SDCA_H__ */
diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c
index 71dd3b97a459..81a1dd77b6f6 100644
--- a/sound/soc/codecs/rt715-sdw.c
+++ b/sound/soc/codecs/rt715-sdw.c
@@ -488,7 +488,7 @@ static int rt715_bus_config(struct sdw_slave *slave,
return 0;
}
-static struct sdw_slave_ops rt715_slave_ops = {
+static const struct sdw_slave_ops rt715_slave_ops = {
.read_prop = rt715_read_prop,
.update_status = rt715_update_status,
.bus_config = rt715_bus_config,
diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c
index 9a7d393d424a..1352869cc086 100644
--- a/sound/soc/codecs/rt715.c
+++ b/sound/soc/codecs/rt715.c
@@ -57,14 +57,14 @@ static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h,
{
int ret;
/* R Channel */
- *r_val = (val_h << 8);
+ *r_val = val_h << 8;
ret = regmap_read(rt715->regmap, addr_l, r_val);
if (ret < 0)
pr_err("Failed to get R channel gain.\n");
/* L Channel */
val_h |= 0x20;
- *l_val = (val_h << 8);
+ *l_val = val_h << 8;
ret = regmap_read(rt715->regmap, addr_h, l_val);
if (ret < 0)
pr_err("Failed to get L channel gain.\n");
@@ -81,12 +81,20 @@ static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value;
struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
unsigned int addr_h, addr_l, val_h, val_ll, val_lr;
- unsigned int read_ll, read_rl;
- int i;
+ unsigned int read_ll, read_rl, i;
+ unsigned int k_vol_changed = 0;
+
+ for (i = 0; i < 2; i++) {
+ if (ucontrol->value.integer.value[i] != rt715->kctl_2ch_vol_ori[i]) {
+ k_vol_changed = 1;
+ break;
+ }
+ }
/* Can't use update bit function, so read the original value first */
addr_h = mc->reg;
addr_l = mc->rreg;
+
if (mc->shift == RT715_DIR_OUT_SFT) /* output */
val_h = 0x80;
else /* input */
@@ -94,41 +102,27 @@ static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol,
rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
+ if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ regmap_write(rt715->regmap,
+ RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
+
/* L Channel */
- if (mc->invert) {
- /* for mute */
- val_ll = (mc->max - ucontrol->value.integer.value[0]) << 7;
- /* keep gain */
- read_ll = read_ll & 0x7f;
- val_ll |= read_ll;
- } else {
- /* for gain */
- val_ll = ((ucontrol->value.integer.value[0]) & 0x7f);
- if (val_ll > mc->max)
- val_ll = mc->max;
- /* keep mute status */
- read_ll = read_ll & 0x80;
- val_ll |= read_ll;
- }
+ rt715->kctl_2ch_vol_ori[0] = ucontrol->value.integer.value[0];
+ /* for gain */
+ val_ll = ((ucontrol->value.integer.value[0]) & 0x7f);
+ if (val_ll > mc->max)
+ val_ll = mc->max;
+ /* keep mute status */
+ val_ll |= read_ll & 0x80;
/* R Channel */
- if (mc->invert) {
- regmap_write(rt715->regmap,
- RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
- /* for mute */
- val_lr = (mc->max - ucontrol->value.integer.value[1]) << 7;
- /* keep gain */
- read_rl = read_rl & 0x7f;
- val_lr |= read_rl;
- } else {
- /* for gain */
- val_lr = ((ucontrol->value.integer.value[1]) & 0x7f);
- if (val_lr > mc->max)
- val_lr = mc->max;
- /* keep mute status */
- read_rl = read_rl & 0x80;
- val_lr |= read_rl;
- }
+ rt715->kctl_2ch_vol_ori[1] = ucontrol->value.integer.value[1];
+ /* for gain */
+ val_lr = ((ucontrol->value.integer.value[1]) & 0x7f);
+ if (val_lr > mc->max)
+ val_lr = mc->max;
+ /* keep mute status */
+ val_lr |= read_rl & 0x80;
for (i = 0; i < 3; i++) { /* retry 3 times at most */
@@ -136,18 +130,18 @@ static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol,
/* Set both L/R channels at the same time */
val_h = (1 << mc->shift) | (3 << 4);
regmap_write(rt715->regmap, addr_h,
- (val_h << 8 | val_ll));
+ (val_h << 8) | val_ll);
regmap_write(rt715->regmap, addr_l,
- (val_h << 8 | val_ll));
+ (val_h << 8) | val_ll);
} else {
/* Lch*/
val_h = (1 << mc->shift) | (1 << 5);
regmap_write(rt715->regmap, addr_h,
- (val_h << 8 | val_ll));
+ (val_h << 8) | val_ll);
/* Rch */
val_h = (1 << mc->shift) | (1 << 4);
regmap_write(rt715->regmap, addr_l,
- (val_h << 8 | val_lr));
+ (val_h << 8) | val_lr);
}
/* check result */
if (mc->shift == RT715_DIR_OUT_SFT) /* output */
@@ -156,15 +150,16 @@ static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol,
val_h = 0x0;
rt715_get_gain(rt715, addr_h, addr_l, val_h,
- &read_rl, &read_ll);
+ &read_rl, &read_ll);
if (read_rl == val_lr && read_ll == val_ll)
break;
}
+
/* D0:power on state, D3: power saving mode */
if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
regmap_write(rt715->regmap,
RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
- return 0;
+ return k_vol_changed;
}
static int rt715_set_amp_gain_get(struct snd_kcontrol *kcontrol,
@@ -188,8 +183,8 @@ static int rt715_set_amp_gain_get(struct snd_kcontrol *kcontrol,
if (mc->invert) {
/* for mute status */
- read_ll = !((read_ll & 0x80) >> RT715_MUTE_SFT);
- read_rl = !((read_rl & 0x80) >> RT715_MUTE_SFT);
+ read_ll = !(read_ll & 0x80);
+ read_rl = !(read_rl & 0x80);
} else {
/* for gain */
read_ll = read_ll & 0x7f;
@@ -201,9 +196,246 @@ static int rt715_set_amp_gain_get(struct snd_kcontrol *kcontrol,
return 0;
}
+static int rt715_set_main_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
+ unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H,
+ RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H,
+ RT715_SET_GAIN_MIX_ADC2_H};
+ unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L,
+ RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L,
+ RT715_SET_GAIN_MIX_ADC2_L};
+ unsigned int addr_h, addr_l, val_h = 0x0, val_ll, val_lr;
+ unsigned int k_shift = RT715_DIR_IN_SFT, k_changed = 0;
+ unsigned int read_ll, read_rl, i, j, loop_cnt = 4;
+
+ for (i = 0; i < 8; i++) {
+ if (ucontrol->value.integer.value[i] != rt715->kctl_8ch_switch_ori[i])
+ k_changed = 1;
+ }
+
+ for (j = 0; j < loop_cnt; j++) {
+ /* Can't use update bit function, so read the original value first */
+ addr_h = capture_reg_H[j];
+ addr_l = capture_reg_L[j];
+ rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
+
+ if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ regmap_write(rt715->regmap,
+ RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
+
+ /* L Channel */
+ /* for mute */
+ rt715->kctl_8ch_switch_ori[j * 2] =
+ ucontrol->value.integer.value[j * 2];
+ val_ll = (!ucontrol->value.integer.value[j * 2]) << 7;
+ /* keep gain */
+ val_ll |= read_ll & 0x7f;
+
+ /* R Channel */
+ /* for mute */
+ rt715->kctl_8ch_switch_ori[j * 2 + 1] =
+ ucontrol->value.integer.value[j * 2 + 1];
+ val_lr = (!ucontrol->value.integer.value[j * 2 + 1]) << 7;
+ /* keep gain */
+ val_lr |= read_rl & 0x7f;
+
+ for (i = 0; i < 3; i++) { /* retry 3 times at most */
+
+ if (val_ll == val_lr) {
+ /* Set both L/R channels at the same time */
+ val_h = (1 << k_shift) | (3 << 4);
+ regmap_write(rt715->regmap, addr_h,
+ (val_h << 8) | val_ll);
+ regmap_write(rt715->regmap, addr_l,
+ (val_h << 8) | val_ll);
+ } else {
+ /* Lch*/
+ val_h = (1 << k_shift) | (1 << 5);
+ regmap_write(rt715->regmap, addr_h,
+ (val_h << 8) | val_ll);
+ /* Rch */
+ val_h = (1 << k_shift) | (1 << 4);
+ regmap_write(rt715->regmap, addr_l,
+ (val_h << 8) | val_lr);
+ }
+ val_h = 0x0;
+ rt715_get_gain(rt715, addr_h, addr_l, val_h,
+ &read_rl, &read_ll);
+ if (read_rl == val_lr && read_ll == val_ll)
+ break;
+ }
+ }
+
+ /* D0:power on state, D3: power saving mode */
+ if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ regmap_write(rt715->regmap,
+ RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
+ return k_changed;
+}
+
+static int rt715_set_main_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
+ unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H,
+ RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H,
+ RT715_SET_GAIN_MIX_ADC2_H};
+ unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L,
+ RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L,
+ RT715_SET_GAIN_MIX_ADC2_L};
+ unsigned int addr_h, addr_l, val_h = 0x0, i, loop_cnt = 4;
+ unsigned int read_ll, read_rl;
+
+ for (i = 0; i < loop_cnt; i++) {
+ addr_h = capture_reg_H[i];
+ addr_l = capture_reg_L[i];
+ rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
+
+ ucontrol->value.integer.value[i * 2] = !(read_ll & 0x80);
+ ucontrol->value.integer.value[i * 2 + 1] = !(read_rl & 0x80);
+ }
+
+ return 0;
+}
+
+static int rt715_set_main_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
+ unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H,
+ RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H,
+ RT715_SET_GAIN_MIX_ADC2_H};
+ unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L,
+ RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L,
+ RT715_SET_GAIN_MIX_ADC2_L};
+ unsigned int addr_h, addr_l, val_h = 0x0, val_ll, val_lr;
+ unsigned int read_ll, read_rl, i, j, loop_cnt = 4, k_changed = 0;
+ unsigned int k_shift = RT715_DIR_IN_SFT, k_max = 0x3f;
+
+ for (i = 0; i < 8; i++) {
+ if (ucontrol->value.integer.value[i] != rt715->kctl_8ch_vol_ori[i])
+ k_changed = 1;
+ }
+
+ for (j = 0; j < loop_cnt; j++) {
+ addr_h = capture_reg_H[j];
+ addr_l = capture_reg_L[j];
+ rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
+
+ if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ regmap_write(rt715->regmap,
+ RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
+
+ /* L Channel */
+ /* for gain */
+ rt715->kctl_8ch_vol_ori[j * 2] = ucontrol->value.integer.value[j * 2];
+ val_ll = ((ucontrol->value.integer.value[j * 2]) & 0x7f);
+ if (val_ll > k_max)
+ val_ll = k_max;
+ /* keep mute status */
+ val_ll |= read_ll & 0x80;
+
+ /* R Channel */
+ /* for gain */
+ rt715->kctl_8ch_vol_ori[j * 2 + 1] =
+ ucontrol->value.integer.value[j * 2 + 1];
+ val_lr = ((ucontrol->value.integer.value[j * 2 + 1]) & 0x7f);
+ if (val_lr > k_max)
+ val_lr = k_max;
+ /* keep mute status */
+ val_lr |= read_rl & 0x80;
+
+ for (i = 0; i < 3; i++) { /* retry 3 times at most */
+ if (val_ll == val_lr) {
+ /* Set both L/R channels at the same time */
+ val_h = (1 << k_shift) | (3 << 4);
+ regmap_write(rt715->regmap, addr_h,
+ (val_h << 8) | val_ll);
+ regmap_write(rt715->regmap, addr_l,
+ (val_h << 8) | val_ll);
+ } else {
+ /* Lch*/
+ val_h = (1 << k_shift) | (1 << 5);
+ regmap_write(rt715->regmap, addr_h,
+ (val_h << 8) | val_ll);
+ /* Rch */
+ val_h = (1 << k_shift) | (1 << 4);
+ regmap_write(rt715->regmap, addr_l,
+ (val_h << 8) | val_lr);
+ }
+ val_h = 0x0;
+ rt715_get_gain(rt715, addr_h, addr_l, val_h,
+ &read_rl, &read_ll);
+ if (read_rl == val_lr && read_ll == val_ll)
+ break;
+ }
+ }
+
+ /* D0:power on state, D3: power saving mode */
+ if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ regmap_write(rt715->regmap,
+ RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
+ return k_changed;
+}
+
+static int rt715_set_main_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
+ unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H,
+ RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H,
+ RT715_SET_GAIN_MIX_ADC2_H};
+ unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L,
+ RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L,
+ RT715_SET_GAIN_MIX_ADC2_L};
+ unsigned int addr_h, addr_l, val_h = 0x0, i, loop_cnt = 4;
+ unsigned int read_ll, read_rl;
+
+ for (i = 0; i < loop_cnt; i++) {
+ addr_h = capture_reg_H[i];
+ addr_l = capture_reg_L[i];
+ rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
+
+ ucontrol->value.integer.value[i * 2] = read_ll & 0x7f;
+ ucontrol->value.integer.value[i * 2 + 1] = read_rl & 0x7f;
+ }
+
+ return 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);
+static int rt715_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 8;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int rt715_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 8;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0x3f;
+ return 0;
+}
+
#define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\
xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
@@ -212,37 +444,28 @@ static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
xmax, xinvert) }
+#define RT715_MAIN_SWITCH_EXT(xname, xhandler_get, xhandler_put) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .info = rt715_switch_info, \
+ .get = xhandler_get, .put = xhandler_put, \
+}
+
+#define RT715_MAIN_VOL_EXT_TLV(xname, xhandler_get, xhandler_put, 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 = rt715_vol_info, \
+ .get = xhandler_get, .put = xhandler_put, \
+}
+
static const struct snd_kcontrol_new rt715_snd_controls[] = {
/* Capture switch */
- SOC_DOUBLE_R_EXT("ADC 07 Capture Switch", RT715_SET_GAIN_MIC_ADC_H,
- RT715_SET_GAIN_MIC_ADC_L, RT715_DIR_IN_SFT, 1, 1,
- rt715_set_amp_gain_get, rt715_set_amp_gain_put),
- SOC_DOUBLE_R_EXT("ADC 08 Capture Switch", RT715_SET_GAIN_LINE_ADC_H,
- RT715_SET_GAIN_LINE_ADC_L, RT715_DIR_IN_SFT, 1, 1,
- rt715_set_amp_gain_get, rt715_set_amp_gain_put),
- SOC_DOUBLE_R_EXT("ADC 09 Capture Switch", RT715_SET_GAIN_MIX_ADC_H,
- RT715_SET_GAIN_MIX_ADC_L, RT715_DIR_IN_SFT, 1, 1,
- rt715_set_amp_gain_get, rt715_set_amp_gain_put),
- SOC_DOUBLE_R_EXT("ADC 27 Capture Switch", RT715_SET_GAIN_MIX_ADC2_H,
- RT715_SET_GAIN_MIX_ADC2_L, RT715_DIR_IN_SFT, 1, 1,
- rt715_set_amp_gain_get, rt715_set_amp_gain_put),
+ RT715_MAIN_SWITCH_EXT("Capture Switch",
+ rt715_set_main_switch_get, rt715_set_main_switch_put),
/* Volume Control */
- SOC_DOUBLE_R_EXT_TLV("ADC 07 Capture Volume", RT715_SET_GAIN_MIC_ADC_H,
- RT715_SET_GAIN_MIC_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0,
- rt715_set_amp_gain_get, rt715_set_amp_gain_put,
- in_vol_tlv),
- SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume", RT715_SET_GAIN_LINE_ADC_H,
- RT715_SET_GAIN_LINE_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0,
- rt715_set_amp_gain_get, rt715_set_amp_gain_put,
- in_vol_tlv),
- SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume", RT715_SET_GAIN_MIX_ADC_H,
- RT715_SET_GAIN_MIX_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0,
- rt715_set_amp_gain_get, rt715_set_amp_gain_put,
- in_vol_tlv),
- SOC_DOUBLE_R_EXT_TLV("ADC 27 Capture Volume", RT715_SET_GAIN_MIX_ADC2_H,
- RT715_SET_GAIN_MIX_ADC2_L, RT715_DIR_IN_SFT, 0x3f, 0,
- rt715_set_amp_gain_get, rt715_set_amp_gain_put,
- in_vol_tlv),
+ RT715_MAIN_VOL_EXT_TLV("Capture Volume",
+ rt715_set_main_vol_get, rt715_set_main_vol_put, in_vol_tlv),
/* MIC Boost Control */
SOC_DOUBLE_R_EXT_TLV("DMIC1 Boost", RT715_SET_GAIN_DMIC1_H,
RT715_SET_GAIN_DMIC1_L, RT715_DIR_IN_SFT, 3, 0,
@@ -683,7 +906,7 @@ static int rt715_pcm_hw_free(struct snd_pcm_substream *substream,
#define RT715_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
-static struct snd_soc_dai_ops rt715_ops = {
+static const struct snd_soc_dai_ops rt715_ops = {
.hw_params = rt715_pcm_hw_params,
.hw_free = rt715_pcm_hw_free,
.set_sdw_stream = rt715_set_sdw_stream,
diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h
index 009a8266f606..25dba61f1760 100644
--- a/sound/soc/codecs/rt715.h
+++ b/sound/soc/codecs/rt715.h
@@ -22,6 +22,9 @@ struct rt715_priv {
struct sdw_bus_params params;
bool hw_init;
bool first_hw_init;
+ unsigned int kctl_2ch_vol_ori[2];
+ unsigned int kctl_8ch_switch_ori[8];
+ unsigned int kctl_8ch_vol_ori[8];
};
struct sdw_stream_data {
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 6d9bb256a2cf..97bf1f222805 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -1819,9 +1819,9 @@ MODULE_DEVICE_TABLE(of, sgtl5000_dt_ids);
static struct i2c_driver sgtl5000_i2c_driver = {
.driver = {
- .name = "sgtl5000",
- .of_match_table = sgtl5000_dt_ids,
- },
+ .name = "sgtl5000",
+ .of_match_table = sgtl5000_dt_ids,
+ },
.probe = sgtl5000_i2c_probe,
.remove = sgtl5000_i2c_remove,
.id_table = sgtl5000_id,
diff --git a/sound/soc/codecs/sigmadsp-regmap.c b/sound/soc/codecs/sigmadsp-regmap.c
index bf1c4086da9f..ba9a6795e470 100644
--- a/sound/soc/codecs/sigmadsp-regmap.c
+++ b/sound/soc/codecs/sigmadsp-regmap.c
@@ -26,7 +26,7 @@ static int sigmadsp_read_regmap(void *control_data,
}
/**
- * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance
+ * devm_sigmadsp_init_regmap() - Initialize SigmaDSP instance
* @dev: The parent device
* @regmap: Regmap instance to use
* @ops: The sigmadsp_ops to use for this instance
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c
index 76c77dc8ecf7..b992216aee55 100644
--- a/sound/soc/codecs/sigmadsp.c
+++ b/sound/soc/codecs/sigmadsp.c
@@ -24,6 +24,8 @@
#define SIGMA_FW_CHUNK_TYPE_CONTROL 1
#define SIGMA_FW_CHUNK_TYPE_SAMPLERATES 2
+#define READBACK_CTRL_NAME "ReadBack"
+
struct sigmadsp_control {
struct list_head head;
uint32_t samplerates;
@@ -31,6 +33,7 @@ struct sigmadsp_control {
unsigned int num_bytes;
const char *name;
struct snd_kcontrol *kcontrol;
+ bool is_readback;
bool cached;
uint8_t cache[];
};
@@ -141,7 +144,8 @@ static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol,
if (ret == 0) {
memcpy(ctrl->cache, data, ctrl->num_bytes);
- ctrl->cached = true;
+ if (!ctrl->is_readback)
+ ctrl->cached = true;
}
mutex_unlock(&sigmadsp->lock);
@@ -164,7 +168,8 @@ static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol,
}
if (ret == 0) {
- ctrl->cached = true;
+ if (!ctrl->is_readback)
+ ctrl->cached = true;
memcpy(ucontrol->value.bytes.data, ctrl->cache,
ctrl->num_bytes);
}
@@ -231,6 +236,15 @@ static int sigma_fw_load_control(struct sigmadsp *sigmadsp,
name[name_len] = '\0';
ctrl->name = name;
+ /*
+ * Readbacks doesn't work with non-volatile controls, since the
+ * firmware updates the control value without driver interaction. Mark
+ * the readbacks to ensure that the values are not cached.
+ */
+ if (ctrl->name && strncmp(ctrl->name, READBACK_CTRL_NAME,
+ (sizeof(READBACK_CTRL_NAME) - 1)) == 0)
+ ctrl->is_readback = true;
+
ctrl->addr = le16_to_cpu(ctrl_chunk->addr);
ctrl->num_bytes = num_bytes;
ctrl->samplerates = le32_to_cpu(chunk->samplerates);
diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h
index e3c9656e006d..d63b8c366efb 100644
--- a/sound/soc/codecs/sigmadsp.h
+++ b/sound/soc/codecs/sigmadsp.h
@@ -59,7 +59,7 @@ struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client,
int sigmadsp_attach(struct sigmadsp *sigmadsp,
struct snd_soc_component *component);
-int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int rate);
+int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int samplerate);
void sigmadsp_reset(struct sigmadsp *sigmadsp);
#endif
diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c
index ec9933b054ad..ffdf7e559515 100644
--- a/sound/soc/codecs/sti-sas.c
+++ b/sound/soc/codecs/sti-sas.c
@@ -51,14 +51,11 @@ static const struct reg_default stih407_sas_reg_defaults[] = {
struct sti_dac_audio {
struct regmap *regmap;
struct regmap *virt_regmap;
- struct regmap_field **field;
- struct reset_control *rst;
int mclk;
};
struct sti_spdif_audio {
struct regmap *regmap;
- struct regmap_field **field;
int mclk;
};
diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c
index 19965fabe949..10302552195e 100644
--- a/sound/soc/codecs/tas2562.c
+++ b/sound/soc/codecs/tas2562.c
@@ -200,7 +200,6 @@ static int tas2562_set_dai_tdm_slot(struct snd_soc_dai *dai,
right_slot = left_slot;
} else {
right_slot = __ffs(tx_mask);
- tx_mask &= ~(1 << right_slot);
}
}
@@ -527,7 +526,7 @@ static int tas2562_volume_control_put(struct snd_kcontrol *kcontrol,
tas2562->volume_lvl = ucontrol->value.integer.value[0];
- return ret;
+ return 0;
}
/* Digital Volume Control. From 0 dB to -110 dB in 1 dB steps */
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 8ff4d9e8d568..9265af41c235 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -457,7 +457,7 @@ static int tas2764_set_dai_tdm_slot(struct snd_soc_dai *dai,
return 0;
}
-static struct snd_soc_dai_ops tas2764_dai_ops = {
+static const struct snd_soc_dai_ops tas2764_dai_ops = {
.mute_stream = tas2764_mute,
.hw_params = tas2764_hw_params,
.set_fmt = tas2764_set_fmt,
diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index 15fca5109e14..172e79cbe0da 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -106,7 +106,7 @@ static int tas2770_codec_suspend(struct snd_soc_component *component)
static int tas2770_codec_resume(struct snd_soc_component *component)
{
struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component);
- int ret = 0;
+ int ret;
if (tas2770->sdz_gpio) {
gpiod_set_value_cansleep(tas2770->sdz_gpio, 1);
@@ -464,7 +464,7 @@ static int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai,
return 0;
}
-static struct snd_soc_dai_ops tas2770_dai_ops = {
+static const struct snd_soc_dai_ops tas2770_dai_ops = {
.mute_stream = tas2770_mute,
.hw_params = tas2770_hw_params,
.set_fmt = tas2770_set_fmt,
diff --git a/sound/soc/codecs/tlv320aic3x-i2c.c b/sound/soc/codecs/tlv320aic3x-i2c.c
new file mode 100644
index 000000000000..cd0558ed4dd4
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic3x-i2c.c
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * ALSA SoC TLV320AIC3x codec driver I2C interface
+ *
+ * Author: Arun KS, <arunks@mistralsolutions.com>
+ * Copyright: (C) 2008 Mistral Solutions Pvt Ltd.,
+ *
+ * Based on sound/soc/codecs/wm8731.c by Richard Purdie
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "tlv320aic3x.h"
+
+static int aic3x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+ struct regmap *regmap;
+ struct regmap_config config;
+
+ config = aic3x_regmap;
+ config.reg_bits = 8;
+ config.val_bits = 8;
+
+ regmap = devm_regmap_init_i2c(i2c, &config);
+ return aic3x_probe(&i2c->dev, regmap, id->driver_data);
+}
+
+static int aic3x_i2c_remove(struct i2c_client *i2c)
+{
+ return aic3x_remove(&i2c->dev);
+}
+
+static const struct i2c_device_id aic3x_i2c_id[] = {
+ { "tlv320aic3x", AIC3X_MODEL_3X },
+ { "tlv320aic33", AIC3X_MODEL_33 },
+ { "tlv320aic3007", AIC3X_MODEL_3007 },
+ { "tlv320aic3104", AIC3X_MODEL_3104 },
+ { "tlv320aic3106", AIC3X_MODEL_3106 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
+
+static const struct of_device_id aic3x_of_id[] = {
+ { .compatible = "ti,tlv320aic3x", },
+ { .compatible = "ti,tlv320aic33" },
+ { .compatible = "ti,tlv320aic3007" },
+ { .compatible = "ti,tlv320aic3104" },
+ { .compatible = "ti,tlv320aic3106" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, aic3x_of_id);
+
+static struct i2c_driver aic3x_i2c_driver = {
+ .driver = {
+ .name = "tlv320aic3x",
+ .of_match_table = aic3x_of_id,
+ },
+ .probe = aic3x_i2c_probe,
+ .remove = aic3x_i2c_remove,
+ .id_table = aic3x_i2c_id,
+};
+
+module_i2c_driver(aic3x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC3x codec driver I2C");
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic3x-spi.c b/sound/soc/codecs/tlv320aic3x-spi.c
new file mode 100644
index 000000000000..8c7b6bb9223f
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic3x-spi.c
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * ALSA SoC TLV320AIC3x codec driver SPI interface
+ *
+ * Author: Arun KS, <arunks@mistralsolutions.com>
+ * Copyright: (C) 2008 Mistral Solutions Pvt Ltd.,
+ *
+ * Based on sound/soc/codecs/wm8731.c by Richard Purdie
+ *
+ */
+
+#include <linux/spi/spi.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "tlv320aic3x.h"
+
+static int aic3x_spi_probe(struct spi_device *spi)
+{
+ struct regmap *regmap;
+ struct regmap_config config;
+ const struct spi_device_id *id = spi_get_device_id(spi);
+
+ config = aic3x_regmap;
+ config.reg_bits = 7;
+ config.pad_bits = 1;
+ config.val_bits = 8;
+ config.read_flag_mask = 0x01;
+
+ dev_dbg(&spi->dev, "probing tlv320aic3x spi device\n");
+
+ regmap = devm_regmap_init_spi(spi, &config);
+ return aic3x_probe(&spi->dev, regmap, id->driver_data);
+}
+
+static int aic3x_spi_remove(struct spi_device *spi)
+{
+ return aic3x_remove(&spi->dev);
+}
+
+static const struct spi_device_id aic3x_spi_id[] = {
+ { "tlv320aic3x", AIC3X_MODEL_3X },
+ { "tlv320aic33", AIC3X_MODEL_33 },
+ { "tlv320aic3007", AIC3X_MODEL_3007 },
+ { "tlv320aic3104", AIC3X_MODEL_3104 },
+ { "tlv320aic3106", AIC3X_MODEL_3106 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, aic3x_spi_id);
+
+static const struct of_device_id aic3x_of_id[] = {
+ { .compatible = "ti,tlv320aic3x", },
+ { .compatible = "ti,tlv320aic33" },
+ { .compatible = "ti,tlv320aic3007" },
+ { .compatible = "ti,tlv320aic3104" },
+ { .compatible = "ti,tlv320aic3106" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, aic3x_of_id);
+
+static struct spi_driver aic3x_spi_driver = {
+ .driver = {
+ .name = "tlv320aic3x",
+ .owner = THIS_MODULE,
+ .of_match_table = aic3x_of_id,
+ },
+ .probe = aic3x_spi_probe,
+ .remove = aic3x_spi_remove,
+ .id_table = aic3x_spi_id,
+};
+
+module_spi_driver(aic3x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC3x codec driver SPI");
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index db1444127444..7731593a5509 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/*
- * ALSA SoC TLV320AIC3X codec driver
+/* ALSA SoC TLV320AIC3X codec driver
*
* Author: Vladimir Barinov, <vbarinov@embeddedalley.com>
* Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com>
@@ -82,10 +81,6 @@ struct aic3x_priv {
int master;
int gpio_reset;
int power;
-#define AIC3X_MODEL_3X 0
-#define AIC3X_MODEL_33 1
-#define AIC3X_MODEL_3007 2
-#define AIC3X_MODEL_3104 3
u16 model;
/* Selects the micbias voltage */
@@ -135,10 +130,7 @@ static bool aic3x_volatile_reg(struct device *dev, unsigned int reg)
}
}
-static const struct regmap_config aic3x_regmap = {
- .reg_bits = 8,
- .val_bits = 8,
-
+const struct regmap_config aic3x_regmap = {
.max_register = DAC_ICC_ADJ,
.reg_defaults = aic3x_reg,
.num_reg_defaults = ARRAY_SIZE(aic3x_reg),
@@ -147,6 +139,7 @@ static const struct regmap_config aic3x_regmap = {
.cache_type = REGCACHE_RBTREE,
};
+EXPORT_SYMBOL_GPL(aic3x_regmap);
#define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
SOC_SINGLE_EXT(xname, reg, shift, mask, invert, \
@@ -1010,6 +1003,7 @@ static int aic3x_add_widgets(struct snd_soc_component *component)
switch (aic3x->model) {
case AIC3X_MODEL_3X:
case AIC3X_MODEL_33:
+ case AIC3X_MODEL_3106:
snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets,
ARRAY_SIZE(aic3x_extra_dapm_widgets));
snd_soc_dapm_add_routes(dapm, intercon_extra,
@@ -1587,6 +1581,7 @@ static int aic3x_init(struct snd_soc_component *component)
switch (aic3x->model) {
case AIC3X_MODEL_3X:
case AIC3X_MODEL_33:
+ case AIC3X_MODEL_3106:
aic3x_mono_init(component);
break;
case AIC3X_MODEL_3007:
@@ -1614,7 +1609,7 @@ static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x)
return false;
}
-static int aic3x_probe(struct snd_soc_component *component)
+static int aic3x_component_probe(struct snd_soc_component *component)
{
struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
int ret, i;
@@ -1653,6 +1648,7 @@ static int aic3x_probe(struct snd_soc_component *component)
switch (aic3x->model) {
case AIC3X_MODEL_3X:
case AIC3X_MODEL_33:
+ case AIC3X_MODEL_3106:
snd_soc_add_component_controls(component, aic3x_extra_snd_controls,
ARRAY_SIZE(aic3x_extra_snd_controls));
snd_soc_add_component_controls(component, aic3x_mono_controls,
@@ -1693,7 +1689,7 @@ static int aic3x_probe(struct snd_soc_component *component)
static const struct snd_soc_component_driver soc_component_dev_aic3x = {
.set_bias_level = aic3x_set_bias_level,
- .probe = aic3x_probe,
+ .probe = aic3x_component_probe,
.controls = aic3x_snd_controls,
.num_controls = ARRAY_SIZE(aic3x_snd_controls),
.dapm_widgets = aic3x_dapm_widgets,
@@ -1705,10 +1701,9 @@ static const struct snd_soc_component_driver soc_component_dev_aic3x = {
.non_legacy_dai_naming = 1,
};
-static void aic3x_configure_ocmv(struct i2c_client *client)
+static void aic3x_configure_ocmv(struct device *dev, struct aic3x_priv *aic3x)
{
- struct device_node *np = client->dev.of_node;
- struct aic3x_priv *aic3x = i2c_get_clientdata(client);
+ struct device_node *np = dev->of_node;
u32 value;
int dvdd, avdd;
@@ -1724,7 +1719,7 @@ static void aic3x_configure_ocmv(struct i2c_client *client)
avdd = regulator_get_voltage(aic3x->supplies[2].consumer);
if (avdd > 3600000 || dvdd > 1950000) {
- dev_warn(&client->dev,
+ dev_warn(dev,
"Too high supply voltage(s) AVDD: %d, DVDD: %d\n",
avdd, dvdd);
} else if (avdd == 3600000 && dvdd == 1950000) {
@@ -1736,26 +1731,12 @@ static void aic3x_configure_ocmv(struct i2c_client *client)
} else if (avdd >= 2700000 && dvdd >= 1525000) {
aic3x->ocmv = HPOUT_SC_OCMV_1_35V;
} else {
- dev_warn(&client->dev,
+ dev_warn(dev,
"Invalid supply voltage(s) AVDD: %d, DVDD: %d\n",
avdd, dvdd);
}
}
-/*
- * AIC3X 2 wire address can be up to 4 devices with device addresses
- * 0x18, 0x19, 0x1A, 0x1B
- */
-
-static const struct i2c_device_id aic3x_i2c_id[] = {
- { "tlv320aic3x", AIC3X_MODEL_3X },
- { "tlv320aic33", AIC3X_MODEL_33 },
- { "tlv320aic3007", AIC3X_MODEL_3007 },
- { "tlv320aic3106", AIC3X_MODEL_3X },
- { "tlv320aic3104", AIC3X_MODEL_3104 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
static const struct reg_sequence aic3007_class_d[] = {
/* Class-D speaker driver init; datasheet p. 46 */
@@ -1767,25 +1748,20 @@ static const struct reg_sequence aic3007_class_d[] = {
{ AIC3X_PAGE_SELECT, 0x00 },
};
-/*
- * If the i2c layer weren't so broken, we could pass this kind of data
- * around
- */
-static int aic3x_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver_data)
{
- struct aic3x_pdata *pdata = i2c->dev.platform_data;
+ struct aic3x_pdata *pdata = dev->platform_data;
struct aic3x_priv *aic3x;
struct aic3x_setup_data *ai3x_setup;
- struct device_node *np = i2c->dev.of_node;
+ struct device_node *np = dev->of_node;
int ret, i;
u32 value;
- aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL);
+ aic3x = devm_kzalloc(dev, sizeof(struct aic3x_priv), GFP_KERNEL);
if (!aic3x)
return -ENOMEM;
- aic3x->regmap = devm_regmap_init_i2c(i2c, &aic3x_regmap);
+ aic3x->regmap = regmap;
if (IS_ERR(aic3x->regmap)) {
ret = PTR_ERR(aic3x->regmap);
return ret;
@@ -1793,14 +1769,13 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
regcache_cache_only(aic3x->regmap, true);
- i2c_set_clientdata(i2c, aic3x);
+ dev_set_drvdata(dev, aic3x);
if (pdata) {
aic3x->gpio_reset = pdata->gpio_reset;
aic3x->setup = pdata->setup;
aic3x->micbias_vg = pdata->micbias_vg;
} else if (np) {
- ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup),
- GFP_KERNEL);
+ ai3x_setup = devm_kzalloc(dev, sizeof(*ai3x_setup), GFP_KERNEL);
if (!ai3x_setup)
return -ENOMEM;
@@ -1810,7 +1785,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
} else {
ret = of_get_named_gpio(np, "gpio-reset", 0);
if (ret > 0) {
- dev_warn(&i2c->dev, "Using deprecated property \"gpio-reset\", please update your DT");
+ dev_warn(dev, "Using deprecated property \"gpio-reset\", please update your DT");
aic3x->gpio_reset = ret;
} else {
aic3x->gpio_reset = -1;
@@ -1835,7 +1810,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
break;
default :
aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
- dev_err(&i2c->dev, "Unsuitable MicBias voltage "
+ dev_err(dev, "Unsuitable MicBias voltage "
"found in DT\n");
}
} else {
@@ -1846,7 +1821,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
aic3x->gpio_reset = -1;
}
- aic3x->model = id->driver_data;
+ aic3x->model = driver_data;
if (gpio_is_valid(aic3x->gpio_reset) &&
!aic3x_is_shared_reset(aic3x)) {
@@ -1859,25 +1834,24 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
aic3x->supplies[i].supply = aic3x_supply_names[i];
- ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(aic3x->supplies),
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(aic3x->supplies),
aic3x->supplies);
if (ret != 0) {
- dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+ dev_err(dev, "Failed to request supplies: %d\n", ret);
goto err_gpio;
}
- aic3x_configure_ocmv(i2c);
+ aic3x_configure_ocmv(dev, aic3x);
if (aic3x->model == AIC3X_MODEL_3007) {
ret = regmap_register_patch(aic3x->regmap, aic3007_class_d,
ARRAY_SIZE(aic3007_class_d));
if (ret != 0)
- dev_err(&i2c->dev, "Failed to init class D: %d\n",
+ dev_err(dev, "Failed to init class D: %d\n",
ret);
}
- ret = devm_snd_soc_register_component(&i2c->dev,
- &soc_component_dev_aic3x, &aic3x_dai, 1);
+ ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic3x, &aic3x_dai, 1);
if (ret != 0)
goto err_gpio;
@@ -1894,10 +1868,11 @@ err_gpio:
err:
return ret;
}
+EXPORT_SYMBOL(aic3x_probe);
-static int aic3x_i2c_remove(struct i2c_client *client)
+int aic3x_remove(struct device *dev)
{
- struct aic3x_priv *aic3x = i2c_get_clientdata(client);
+ struct aic3x_priv *aic3x = dev_get_drvdata(dev);
list_del(&aic3x->list);
@@ -1908,31 +1883,7 @@ static int aic3x_i2c_remove(struct i2c_client *client)
}
return 0;
}
-
-#if defined(CONFIG_OF)
-static const struct of_device_id tlv320aic3x_of_match[] = {
- { .compatible = "ti,tlv320aic3x", },
- { .compatible = "ti,tlv320aic33" },
- { .compatible = "ti,tlv320aic3007" },
- { .compatible = "ti,tlv320aic3106" },
- { .compatible = "ti,tlv320aic3104" },
- {},
-};
-MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match);
-#endif
-
-/* machine i2c codec control layer */
-static struct i2c_driver aic3x_i2c_driver = {
- .driver = {
- .name = "tlv320aic3x-codec",
- .of_match_table = of_match_ptr(tlv320aic3x_of_match),
- },
- .probe = aic3x_i2c_probe,
- .remove = aic3x_i2c_remove,
- .id_table = aic3x_i2c_id,
-};
-
-module_i2c_driver(aic3x_i2c_driver);
+EXPORT_SYMBOL(aic3x_remove);
MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver");
MODULE_AUTHOR("Vladimir Barinov");
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index 66d3580cf2b1..7e0063913017 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -9,6 +9,19 @@
#ifndef _AIC3X_H
#define _AIC3X_H
+struct device;
+struct regmap_config;
+
+extern const struct regmap_config aic3x_regmap;
+int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver_data);
+int aic3x_remove(struct device *dev);
+
+#define AIC3X_MODEL_3X 0
+#define AIC3X_MODEL_33 1
+#define AIC3X_MODEL_3007 2
+#define AIC3X_MODEL_3104 3
+#define AIC3X_MODEL_3106 4
+
/* AIC3X register space */
#define AIC3X_CACHEREGNUM 110
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index d905e03aaec7..48572d66cb3b 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -1071,7 +1071,7 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream,
*/
dac33->nsample = period_size *
((dac33->alarm_threshold / period_size) +
- (dac33->alarm_threshold % period_size ?
+ ((dac33->alarm_threshold % period_size) ?
1 : 0));
else if (period_size > nsample_limit)
dac33->nsample = nsample_limit;
diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c
index 1bafc9d1101c..43220bb36701 100644
--- a/sound/soc/codecs/tscs454.c
+++ b/sound/soc/codecs/tscs454.c
@@ -727,7 +727,12 @@ static int pll_power_event(struct snd_soc_dapm_widget *w,
if (enable)
val = pll1 ? FV_PLL1CLKEN_ENABLE : FV_PLL2CLKEN_ENABLE;
else
- val = pll1 ? FV_PLL1CLKEN_DISABLE : FV_PLL2CLKEN_DISABLE;
+ /*
+ * FV_PLL1CLKEN_DISABLE and FV_PLL2CLKEN_DISABLE are
+ * identical zero vzalues, there is no need to test
+ * the PLL index
+ */
+ val = FV_PLL1CLKEN_DISABLE;
ret = snd_soc_component_update_bits(component, R_PLLCTL, msk, val);
if (ret < 0) {
diff --git a/sound/soc/codecs/wcd-clsh-v2.h b/sound/soc/codecs/wcd-clsh-v2.h
index a902f9893467..a6d0f2d0e9e3 100644
--- a/sound/soc/codecs/wcd-clsh-v2.h
+++ b/sound/soc/codecs/wcd-clsh-v2.h
@@ -37,13 +37,13 @@ enum wcd_clsh_mode {
struct wcd_clsh_ctrl;
extern struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(
- struct snd_soc_component *component,
+ struct snd_soc_component *comp,
int version);
extern void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl);
extern int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl);
extern int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl,
- enum wcd_clsh_event event,
- int state,
+ enum wcd_clsh_event clsh_event,
+ int nstate,
enum wcd_clsh_mode mode);
#endif /* _WCD_CLSH_V2_H_ */
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 9ddfed797b7e..86c92e03ea5d 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -2058,7 +2058,7 @@ static int wcd9335_get_channel_map(struct snd_soc_dai *dai,
return 0;
}
-static struct snd_soc_dai_ops wcd9335_dai_ops = {
+static const struct snd_soc_dai_ops wcd9335_dai_ops = {
.hw_params = wcd9335_hw_params,
.trigger = wcd9335_trigger,
.set_channel_map = wcd9335_set_channel_map,
@@ -5213,7 +5213,7 @@ static int wcd9335_slim_status(struct slim_device *sdev,
wcd9335_probe(wcd);
- return ret;
+ return 0;
}
static const struct slim_device_id wcd9335_slim_id[] = {
diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c
index d18ae5e3ee80..046874ef490e 100644
--- a/sound/soc/codecs/wcd934x.c
+++ b/sound/soc/codecs/wcd934x.c
@@ -1565,8 +1565,6 @@ static int wcd934x_set_interpolator_rate(struct snd_soc_dai *dai,
return ret;
ret = wcd934x_set_mix_interpolator_rate(dai, (u8)rate_val,
sample_rate);
- if (ret)
- return ret;
return ret;
}
@@ -1948,7 +1946,7 @@ static int wcd934x_get_channel_map(struct snd_soc_dai *dai,
return 0;
}
-static struct snd_soc_dai_ops wcd934x_dai_ops = {
+static const struct snd_soc_dai_ops wcd934x_dai_ops = {
.hw_params = wcd934x_hw_params,
.hw_free = wcd934x_hw_free,
.trigger = wcd934x_trigger,
@@ -2118,11 +2116,13 @@ static struct clk *wcd934x_register_mclk_output(struct wcd934x_codec *wcd)
wcd->hw.init = &init;
hw = &wcd->hw;
- ret = clk_hw_register(wcd->dev->parent, hw);
+ ret = devm_clk_hw_register(wcd->dev->parent, hw);
if (ret)
return ERR_PTR(ret);
- of_clk_add_provider(np, of_clk_src_simple_get, hw->clk);
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
+ if (ret)
+ return ERR_PTR(ret);
return NULL;
}
@@ -5042,7 +5042,7 @@ static int wcd934x_codec_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(dev, irq, NULL,
wcd934x_slim_irq_handler,
- IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"slim", wcd);
if (ret) {
dev_err(dev, "Failed to request slimbus irq\n");
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index c62f7ad0022c..b0a6d31299bb 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -72,13 +72,6 @@ static const char *wm2200_core_supply_names[WM2200_NUM_CORE_SUPPLIES] = {
"LDOVDD",
};
-struct wm2200_fll {
- int fref;
- int fout;
- int src;
- struct completion lock;
-};
-
/* codec private data */
struct wm2200_priv {
struct wm_adsp dsp[2];
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index fe33f2d88f55..34b665895bdf 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -2004,6 +2004,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm5102 = {
.remove = wm5102_component_remove,
.set_sysclk = arizona_set_sysclk,
.set_pll = wm5102_set_fll,
+ .set_jack = arizona_jack_set_jack,
.name = DRV_NAME,
.compress_ops = &wm5102_compress_ops,
.controls = wm5102_snd_controls,
@@ -2057,6 +2058,11 @@ static int wm5102_probe(struct platform_device *pdev)
if (ret != 0)
return ret;
+ /* This may return -EPROBE_DEFER, so do this early on */
+ ret = arizona_jack_codec_dev_probe(&wm5102->core, &pdev->dev);
+ if (ret)
+ return ret;
+
for (i = 0; i < ARRAY_SIZE(wm5102->fll); i++)
wm5102->fll[i].vco_mult = 1;
@@ -2089,7 +2095,7 @@ static int wm5102_probe(struct platform_device *pdev)
wm5102);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret);
- return ret;
+ goto err_jack_codec_dev;
}
ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 1);
@@ -2123,6 +2129,8 @@ err_spk_irqs:
err_dsp_irq:
arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102);
+err_jack_codec_dev:
+ arizona_jack_codec_dev_remove(&wm5102->core);
return ret;
}
@@ -2141,6 +2149,8 @@ static int wm5102_remove(struct platform_device *pdev)
arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102);
+ arizona_jack_codec_dev_remove(&wm5102->core);
+
return 0;
}
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 52c0a575cc4f..76efca0fe515 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -2370,6 +2370,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm5110 = {
.remove = wm5110_component_remove,
.set_sysclk = arizona_set_sysclk,
.set_pll = wm5110_set_fll,
+ .set_jack = arizona_jack_set_jack,
.name = DRV_NAME,
.compress_ops = &wm5110_compress_ops,
.controls = wm5110_snd_controls,
@@ -2424,6 +2425,11 @@ static int wm5110_probe(struct platform_device *pdev)
return ret;
}
+ /* This may return -EPROBE_DEFER, so do this early on */
+ ret = arizona_jack_codec_dev_probe(&wm5110->core, &pdev->dev);
+ if (ret)
+ return ret;
+
for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++)
wm5110->fll[i].vco_mult = 3;
@@ -2456,7 +2462,7 @@ static int wm5110_probe(struct platform_device *pdev)
wm5110);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret);
- return ret;
+ goto err_jack_codec_dev;
}
ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 1);
@@ -2490,6 +2496,8 @@ err_spk_irqs:
err_dsp_irq:
arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110);
+err_jack_codec_dev:
+ arizona_jack_codec_dev_remove(&wm5110->core);
return ret;
}
@@ -2510,6 +2518,8 @@ static int wm5110_remove(struct platform_device *pdev)
arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110);
+ arizona_jack_codec_dev_remove(&wm5110->core);
+
return 0;
}
diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c
index 4e9ab542f648..81f858f6bd67 100644
--- a/sound/soc/codecs/wm8524.c
+++ b/sound/soc/codecs/wm8524.c
@@ -227,7 +227,7 @@ static int wm8524_codec_probe(struct platform_device *pdev)
wm8524->mute = devm_gpiod_get(&pdev->dev, "wlf,mute", GPIOD_OUT_LOW);
if (IS_ERR(wm8524->mute)) {
ret = PTR_ERR(wm8524->mute);
- dev_err(&pdev->dev, "Failed to get mute line: %d\n", ret);
+ dev_err_probe(&pdev->dev, ret, "Failed to get mute line\n");
return ret;
}
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 026603ae44ce..75f30154c809 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1549,14 +1549,12 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
* BCLKs to clock out the samples).
*/
bclk_div = 0;
- best_val = ((clk_sys * 10) / bclk_divs[0].ratio) - bclk;
i = 1;
while (i < ARRAY_SIZE(bclk_divs)) {
cur_val = ((clk_sys * 10) / bclk_divs[i].ratio) - bclk;
if (cur_val < 0) /* BCLK table is sorted */
break;
bclk_div = i;
- best_val = cur_val;
i++;
}
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
index 3bce9a14f0f3..536339e43dc7 100644
--- a/sound/soc/codecs/wm8958-dsp2.c
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -923,7 +923,7 @@ void wm8958_dsp2_init(struct snd_soc_component *component)
component, wm8958_enh_eq_loaded);
if (pdata->num_mbc_cfgs) {
- struct snd_kcontrol_new control[] = {
+ struct snd_kcontrol_new mbc_control[] = {
SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
wm8958_get_mbc_enum, wm8958_put_mbc_enum),
};
@@ -942,14 +942,14 @@ void wm8958_dsp2_init(struct snd_soc_component *component)
wm8994->mbc_enum.texts = wm8994->mbc_texts;
ret = snd_soc_add_component_controls(wm8994->hubs.component,
- control, 1);
+ mbc_control, 1);
if (ret != 0)
dev_err(wm8994->hubs.component->dev,
"Failed to add MBC mode controls: %d\n", ret);
}
if (pdata->num_vss_cfgs) {
- struct snd_kcontrol_new control[] = {
+ struct snd_kcontrol_new vss_control[] = {
SOC_ENUM_EXT("VSS Mode", wm8994->vss_enum,
wm8958_get_vss_enum, wm8958_put_vss_enum),
};
@@ -968,14 +968,14 @@ void wm8958_dsp2_init(struct snd_soc_component *component)
wm8994->vss_enum.texts = wm8994->vss_texts;
ret = snd_soc_add_component_controls(wm8994->hubs.component,
- control, 1);
+ vss_control, 1);
if (ret != 0)
dev_err(wm8994->hubs.component->dev,
"Failed to add VSS mode controls: %d\n", ret);
}
if (pdata->num_vss_hpf_cfgs) {
- struct snd_kcontrol_new control[] = {
+ struct snd_kcontrol_new hpf_control[] = {
SOC_ENUM_EXT("VSS HPF Mode", wm8994->vss_hpf_enum,
wm8958_get_vss_hpf_enum,
wm8958_put_vss_hpf_enum),
@@ -995,7 +995,7 @@ void wm8958_dsp2_init(struct snd_soc_component *component)
wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
ret = snd_soc_add_component_controls(wm8994->hubs.component,
- control, 1);
+ hpf_control, 1);
if (ret != 0)
dev_err(wm8994->hubs.component->dev,
"Failed to add VSS HPFmode controls: %d\n",
@@ -1003,7 +1003,7 @@ void wm8958_dsp2_init(struct snd_soc_component *component)
}
if (pdata->num_enh_eq_cfgs) {
- struct snd_kcontrol_new control[] = {
+ struct snd_kcontrol_new eq_control[] = {
SOC_ENUM_EXT("Enhanced EQ Mode", wm8994->enh_eq_enum,
wm8958_get_enh_eq_enum,
wm8958_put_enh_eq_enum),
@@ -1023,7 +1023,7 @@ void wm8958_dsp2_init(struct snd_soc_component *component)
wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
ret = snd_soc_add_component_controls(wm8994->hubs.component,
- control, 1);
+ eq_control, 1);
if (ret != 0)
dev_err(wm8994->hubs.component->dev,
"Failed to add enhanced EQ controls: %d\n",
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index cda9cd935d4f..9e621a254392 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -608,10 +608,6 @@ static const int bclk_divs[] = {
* - lrclk = sysclk / dac_divs
* - 10 * bclk = sysclk / bclk_divs
*
- * If we cannot find an exact match for (sysclk, lrclk, bclk)
- * triplet, we relax the bclk such that bclk is chosen as the
- * closest available frequency greater than expected bclk.
- *
* @wm8960: codec private data
* @mclk: MCLK used to derive sysclk
* @sysclk_idx: sysclk_divs index for found sysclk
@@ -629,7 +625,7 @@ int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk,
{
int sysclk, bclk, lrclk;
int i, j, k;
- int diff, closest = mclk;
+ int diff;
/* marker for no match */
*bclk_idx = -1;
@@ -653,12 +649,6 @@ int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk,
*bclk_idx = k;
break;
}
- if (diff > 0 && closest > diff) {
- *sysclk_idx = i;
- *dac_idx = j;
- *bclk_idx = k;
- closest = diff;
- }
}
if (k != ARRAY_SIZE(bclk_divs))
break;
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index ce4666a74793..34080f497584 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -2403,6 +2403,7 @@ static const int sysclk_rates[] = {
static void wm8962_configure_bclk(struct snd_soc_component *component)
{
struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+ int best, min_diff, diff;
int dspclk, i;
int clocking2 = 0;
int clocking4 = 0;
@@ -2473,23 +2474,25 @@ static void wm8962_configure_bclk(struct snd_soc_component *component)
dev_dbg(component->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk);
- /* We're expecting an exact match */
+ /* Search a proper bclk, not exact match. */
+ best = 0;
+ min_diff = INT_MAX;
for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
if (bclk_divs[i] < 0)
continue;
- if (dspclk / bclk_divs[i] == wm8962->bclk) {
- dev_dbg(component->dev, "Selected BCLK_DIV %d for %dHz\n",
- bclk_divs[i], wm8962->bclk);
- clocking2 |= i;
+ diff = (dspclk / bclk_divs[i]) - wm8962->bclk;
+ if (diff < 0) /* Table is sorted */
break;
+ if (diff < min_diff) {
+ best = i;
+ min_diff = diff;
}
}
- if (i == ARRAY_SIZE(bclk_divs)) {
- dev_err(component->dev, "Unsupported BCLK ratio %d\n",
- dspclk / wm8962->bclk);
- return;
- }
+ wm8962->bclk = dspclk / bclk_divs[best];
+ clocking2 |= best;
+ dev_dbg(component->dev, "Selected BCLK_DIV %d for %dHz\n",
+ bclk_divs[best], wm8962->bclk);
aif2 |= wm8962->bclk / wm8962->lrclk;
dev_dbg(component->dev, "Selected LRCLK divisor %d for %dHz\n",
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 4b5ecd142249..7091e1a9d516 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -724,7 +724,7 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream,
/* Sampling rate mask = 0xe (for filters) */
u16 add_ctl = snd_soc_component_read(component, WM8978_ADDITIONAL_CONTROL) & ~0xe;
u16 clking = snd_soc_component_read(component, WM8978_CLOCKING);
- enum wm8978_sysclk_src current_clk_id = clking & 0x100 ?
+ enum wm8978_sysclk_src current_clk_id = (clking & 0x100) ?
WM8978_PLL : WM8978_MCLK;
unsigned int f_sel, diff, diff_best = INT_MAX;
int i, best = 0;
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 41c4b126114d..bc584b17bf28 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -50,7 +50,7 @@ typedef void (*wm1811_mic_id_cb)(void *data, u16 status);
int wm8994_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
int micbias);
int wm8958_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
- wm1811_micdet_cb cb, void *det_cb_data,
+ wm1811_micdet_cb det_cb, void *det_cb_data,
wm1811_mic_id_cb id_cb, void *id_cb_data);
int wm8994_vmid_mode(struct snd_soc_component *component, enum wm8994_vmid_mode mode);
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index d303ef7571e9..197ae7d84a49 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -2106,7 +2106,7 @@ static int wm8996_set_fll(struct snd_soc_component *component, int fll_id, int s
timeout *= 10;
else
/* ensure timeout of atleast 1 jiffies */
- timeout = timeout/2 ? : 1;
+ timeout = (timeout/2) ? : 1;
for (retry = 0; retry < 10; retry++) {
time_left = wait_for_completion_timeout(&wm8996->fll_lock,
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index 99c3ebae6ba6..38ef631d1a1f 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -1096,6 +1096,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm8997 = {
.remove = wm8997_component_remove,
.set_sysclk = arizona_set_sysclk,
.set_pll = wm8997_set_fll,
+ .set_jack = arizona_jack_set_jack,
.controls = wm8997_snd_controls,
.num_controls = ARRAY_SIZE(wm8997_snd_controls),
.dapm_widgets = wm8997_dapm_widgets,
@@ -1132,6 +1133,11 @@ static int wm8997_probe(struct platform_device *pdev)
arizona_init_dvfs(&wm8997->core);
+ /* This may return -EPROBE_DEFER, so do this early on */
+ ret = arizona_jack_codec_dev_probe(&wm8997->core, &pdev->dev);
+ if (ret)
+ return ret;
+
for (i = 0; i < ARRAY_SIZE(wm8997->fll); i++)
wm8997->fll[i].vco_mult = 1;
@@ -1163,10 +1169,10 @@ static int wm8997_probe(struct platform_device *pdev)
ret = arizona_init_vol_limit(arizona);
if (ret < 0)
- return ret;
+ goto err_jack_codec_dev;
ret = arizona_init_spk_irqs(arizona);
if (ret < 0)
- return ret;
+ goto err_jack_codec_dev;
ret = devm_snd_soc_register_component(&pdev->dev,
&soc_component_dev_wm8997,
@@ -1181,6 +1187,8 @@ static int wm8997_probe(struct platform_device *pdev)
err_spk_irqs:
arizona_free_spk_irqs(arizona);
+err_jack_codec_dev:
+ arizona_jack_codec_dev_remove(&wm8997->core);
return ret;
}
@@ -1194,6 +1202,8 @@ static int wm8997_remove(struct platform_device *pdev)
arizona_free_spk_irqs(arizona);
+ arizona_jack_codec_dev_remove(&wm8997->core);
+
return 0;
}
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c
index b6f717aa5478..00b59fc9b1fe 100644
--- a/sound/soc/codecs/wm8998.c
+++ b/sound/soc/codecs/wm8998.c
@@ -1316,6 +1316,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm8998 = {
.remove = wm8998_component_remove,
.set_sysclk = arizona_set_sysclk,
.set_pll = wm8998_set_fll,
+ .set_jack = arizona_jack_set_jack,
.controls = wm8998_snd_controls,
.num_controls = ARRAY_SIZE(wm8998_snd_controls),
.dapm_widgets = wm8998_dapm_widgets,
@@ -1350,6 +1351,11 @@ static int wm8998_probe(struct platform_device *pdev)
wm8998->core.arizona = arizona;
wm8998->core.num_inputs = 3; /* IN1L, IN1R, IN2 */
+ /* This may return -EPROBE_DEFER, so do this early on */
+ ret = arizona_jack_codec_dev_probe(&wm8998->core, &pdev->dev);
+ if (ret)
+ return ret;
+
for (i = 0; i < ARRAY_SIZE(wm8998->fll); i++)
wm8998->fll[i].vco_mult = 1;
@@ -1392,6 +1398,7 @@ err_spk_irqs:
arizona_free_spk_irqs(arizona);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
+ arizona_jack_codec_dev_remove(&wm8998->core);
return ret;
}
@@ -1405,6 +1412,8 @@ static int wm8998_remove(struct platform_device *pdev)
arizona_free_spk_irqs(arizona);
+ arizona_jack_codec_dev_remove(&wm8998->core);
+
return 0;
}
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 070ca7d8c661..3dc119daf2f6 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -2079,7 +2079,7 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
snd_ctl_notify(dsp->component->card->snd_card,
SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h
index 988b29e63060..a4ed9bd31426 100644
--- a/sound/soc/codecs/wm_hubs.h
+++ b/sound/soc/codecs/wm_hubs.h
@@ -56,7 +56,7 @@ extern int wm_hubs_handle_analogue_pdata(struct snd_soc_component *,
int lineout1_diff, int lineout2_diff,
int lineout1fb, int lineout2fb,
int jd_scthr, int jd_thr,
- int micbias1_dly, int micbias2_dly,
+ int micbias1_delay, int micbias2_delay,
int micbias1_lvl, int micbias2_lvl);
extern irqreturn_t wm_hubs_dcs_done(int irq, void *data);
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index db87e07b11c9..2da4a5fa7a18 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -1014,7 +1014,7 @@ static int wsa881x_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
-static struct snd_soc_dai_ops wsa881x_dai_ops = {
+static const struct snd_soc_dai_ops wsa881x_dai_ops = {
.hw_params = wsa881x_hw_params,
.hw_free = wsa881x_hw_free,
.mute_stream = wsa881x_digital_mute,