summaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/Kconfig67
-rw-r--r--sound/soc/codecs/Makefile16
-rw-r--r--sound/soc/codecs/ad193x-i2c.c2
-rw-r--r--sound/soc/codecs/adau1372-i2c.c2
-rw-r--r--sound/soc/codecs/adau1373.c2
-rw-r--r--sound/soc/codecs/adau1701.c2
-rw-r--r--sound/soc/codecs/adau1761-i2c.c2
-rw-r--r--sound/soc/codecs/adau1781-i2c.c2
-rw-r--r--sound/soc/codecs/adau17x1.c13
-rw-r--r--sound/soc/codecs/adau1977-i2c.c2
-rw-r--r--sound/soc/codecs/adau7118-i2c.c2
-rw-r--r--sound/soc/codecs/adav803.c2
-rw-r--r--sound/soc/codecs/ak4118.c13
-rw-r--r--sound/soc/codecs/ak4375.c2
-rw-r--r--sound/soc/codecs/ak4458.c2
-rw-r--r--sound/soc/codecs/ak4535.c2
-rw-r--r--sound/soc/codecs/ak4613.c2
-rw-r--r--sound/soc/codecs/ak4641.c2
-rw-r--r--sound/soc/codecs/ak4642.c2
-rw-r--r--sound/soc/codecs/ak4671.c2
-rw-r--r--sound/soc/codecs/ak5558.c2
-rw-r--r--sound/soc/codecs/alc5623.c2
-rw-r--r--sound/soc/codecs/alc5632.c2
-rw-r--r--sound/soc/codecs/aw88395/aw88395.c2
-rw-r--r--sound/soc/codecs/chv3-codec.c41
-rw-r--r--sound/soc/codecs/cs35l32.c4
-rw-r--r--sound/soc/codecs/cs35l33.c4
-rw-r--r--sound/soc/codecs/cs35l34.c4
-rw-r--r--sound/soc/codecs/cs35l35.c4
-rw-r--r--sound/soc/codecs/cs35l36.c2
-rw-r--r--sound/soc/codecs/cs35l41-i2c.c2
-rw-r--r--sound/soc/codecs/cs35l45-i2c.c6
-rw-r--r--sound/soc/codecs/cs35l45-spi.c4
-rw-r--r--sound/soc/codecs/cs35l45-tables.c2
-rw-r--r--sound/soc/codecs/cs35l45.c4
-rw-r--r--sound/soc/codecs/cs35l45.h2
-rw-r--r--sound/soc/codecs/cs35l56-i2c.c2
-rw-r--r--sound/soc/codecs/cs35l56.c65
-rw-r--r--sound/soc/codecs/cs4234.c4
-rw-r--r--sound/soc/codecs/cs4265.c2
-rw-r--r--sound/soc/codecs/cs4270.c2
-rw-r--r--sound/soc/codecs/cs4271-i2c.c2
-rw-r--r--sound/soc/codecs/cs42l42-i2c.c2
-rw-r--r--sound/soc/codecs/cs42l42.c9
-rw-r--r--sound/soc/codecs/cs42l51-i2c.c2
-rw-r--r--sound/soc/codecs/cs42l51.c9
-rw-r--r--sound/soc/codecs/cs42l52.c2
-rw-r--r--sound/soc/codecs/cs42l56.c2
-rw-r--r--sound/soc/codecs/cs42l73.c4
-rw-r--r--sound/soc/codecs/cs42l83-i2c.c4
-rw-r--r--sound/soc/codecs/cs42xx8-i2c.c2
-rw-r--r--sound/soc/codecs/cs43130.c4
-rw-r--r--sound/soc/codecs/cs4341.c2
-rw-r--r--sound/soc/codecs/cs4349.c2
-rw-r--r--sound/soc/codecs/cs53l30.c14
-rw-r--r--sound/soc/codecs/cx2072x.c2
-rw-r--r--sound/soc/codecs/da7210.c2
-rw-r--r--sound/soc/codecs/da7213.c2
-rw-r--r--sound/soc/codecs/da7218.c2
-rw-r--r--sound/soc/codecs/da7219-aad.c42
-rw-r--r--sound/soc/codecs/da7219.c2
-rw-r--r--sound/soc/codecs/da732x.c2
-rw-r--r--sound/soc/codecs/da9055.c2
-rw-r--r--sound/soc/codecs/es8316.c27
-rw-r--r--sound/soc/codecs/es8326.c2
-rw-r--r--sound/soc/codecs/es8328-i2c.c2
-rw-r--r--sound/soc/codecs/es8328.c2
-rw-r--r--sound/soc/codecs/isabelle.c2
-rw-r--r--sound/soc/codecs/lm4857.c2
-rw-r--r--sound/soc/codecs/lm49453.c2
-rw-r--r--sound/soc/codecs/max9768.c2
-rw-r--r--sound/soc/codecs/max98088.c24
-rw-r--r--sound/soc/codecs/max98090.c56
-rw-r--r--sound/soc/codecs/max98090.h3
-rw-r--r--sound/soc/codecs/max98095.c2
-rw-r--r--sound/soc/codecs/max98363.c6
-rw-r--r--sound/soc/codecs/max98371.c2
-rw-r--r--sound/soc/codecs/max98373-i2c.c4
-rw-r--r--sound/soc/codecs/max98388.c1013
-rw-r--r--sound/soc/codecs/max98388.h234
-rw-r--r--sound/soc/codecs/max98390.c2
-rw-r--r--sound/soc/codecs/max98396.c2
-rw-r--r--sound/soc/codecs/max9850.c2
-rw-r--r--sound/soc/codecs/max98504.c2
-rw-r--r--sound/soc/codecs/max98520.c2
-rw-r--r--sound/soc/codecs/max9860.c2
-rw-r--r--sound/soc/codecs/max9867.c2
-rw-r--r--sound/soc/codecs/max9877.c2
-rw-r--r--sound/soc/codecs/max98925.c2
-rw-r--r--sound/soc/codecs/max98926.c2
-rw-r--r--sound/soc/codecs/max98927.c2
-rw-r--r--sound/soc/codecs/ml26124.c2
-rw-r--r--sound/soc/codecs/mt6359.c152
-rw-r--r--sound/soc/codecs/mt6660.c2
-rw-r--r--sound/soc/codecs/nau8540.c2
-rw-r--r--sound/soc/codecs/nau8810.c2
-rw-r--r--sound/soc/codecs/nau8821.c2
-rw-r--r--sound/soc/codecs/nau8822.c2
-rw-r--r--sound/soc/codecs/nau8824.c2
-rw-r--r--sound/soc/codecs/nau8825.c150
-rw-r--r--sound/soc/codecs/nau8825.h11
-rw-r--r--sound/soc/codecs/pcm1681.c2
-rw-r--r--sound/soc/codecs/pcm1789-i2c.c2
-rw-r--r--sound/soc/codecs/pcm179x-i2c.c2
-rw-r--r--sound/soc/codecs/pcm186x-i2c.c2
-rw-r--r--sound/soc/codecs/pcm186x.c1
-rw-r--r--sound/soc/codecs/pcm3060-i2c.c2
-rw-r--r--sound/soc/codecs/pcm3168a-i2c.c2
-rw-r--r--sound/soc/codecs/pcm512x-i2c.c2
-rw-r--r--sound/soc/codecs/rk3328_codec.c1
-rw-r--r--sound/soc/codecs/rt1011.c4
-rw-r--r--sound/soc/codecs/rt1015.c2
-rw-r--r--sound/soc/codecs/rt1016.c2
-rw-r--r--sound/soc/codecs/rt1019.c4
-rw-r--r--sound/soc/codecs/rt1305.c4
-rw-r--r--sound/soc/codecs/rt1308-sdw.c7
-rw-r--r--sound/soc/codecs/rt1308-sdw.h1
-rw-r--r--sound/soc/codecs/rt1308.c4
-rw-r--r--sound/soc/codecs/rt1316-sdw.c7
-rw-r--r--sound/soc/codecs/rt1316-sdw.h1
-rw-r--r--sound/soc/codecs/rt1318-sdw.c7
-rw-r--r--sound/soc/codecs/rt1318-sdw.h1
-rw-r--r--sound/soc/codecs/rt274.c2
-rw-r--r--sound/soc/codecs/rt286.c2
-rw-r--r--sound/soc/codecs/rt298.c2
-rw-r--r--sound/soc/codecs/rt5514.c4
-rw-r--r--sound/soc/codecs/rt5616.c4
-rw-r--r--sound/soc/codecs/rt5631.c4
-rw-r--r--sound/soc/codecs/rt5640.c4
-rw-r--r--sound/soc/codecs/rt5645.c6
-rw-r--r--sound/soc/codecs/rt5651.c4
-rw-r--r--sound/soc/codecs/rt5659.c12
-rw-r--r--sound/soc/codecs/rt5660.c4
-rw-r--r--sound/soc/codecs/rt5663.c6
-rw-r--r--sound/soc/codecs/rt5665.c4
-rw-r--r--sound/soc/codecs/rt5668.c4
-rw-r--r--sound/soc/codecs/rt5670.c4
-rw-r--r--sound/soc/codecs/rt5677.c4
-rw-r--r--sound/soc/codecs/rt5682-i2c.c5
-rw-r--r--sound/soc/codecs/rt5682-sdw.c7
-rw-r--r--sound/soc/codecs/rt5682.h1
-rw-r--r--sound/soc/codecs/rt5682s.c16
-rw-r--r--sound/soc/codecs/rt700-sdw.c7
-rw-r--r--sound/soc/codecs/rt700.h1
-rw-r--r--sound/soc/codecs/rt711-sdca-sdw.c9
-rw-r--r--sound/soc/codecs/rt711-sdca.h1
-rw-r--r--sound/soc/codecs/rt711-sdw.c7
-rw-r--r--sound/soc/codecs/rt711.h1
-rw-r--r--sound/soc/codecs/rt712-sdca-dmic.c9
-rw-r--r--sound/soc/codecs/rt712-sdca-dmic.h1
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.c9
-rw-r--r--sound/soc/codecs/rt712-sdca.h1
-rw-r--r--sound/soc/codecs/rt715-sdca-sdw.c9
-rw-r--r--sound/soc/codecs/rt715-sdca.h1
-rw-r--r--sound/soc/codecs/rt715-sdw.c6
-rw-r--r--sound/soc/codecs/rt715.h1
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.c507
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.h124
-rw-r--r--sound/soc/codecs/rt722-sdca.c1555
-rw-r--r--sound/soc/codecs/rt722-sdca.h237
-rw-r--r--sound/soc/codecs/rt9120.c2
-rw-r--r--sound/soc/codecs/sgtl5000.c2
-rw-r--r--sound/soc/codecs/sma1303.c2
-rw-r--r--sound/soc/codecs/src4xxx-i2c.c2
-rw-r--r--sound/soc/codecs/ssm2518.c2
-rw-r--r--sound/soc/codecs/ssm2602-i2c.c2
-rw-r--r--sound/soc/codecs/ssm3515.c448
-rw-r--r--sound/soc/codecs/ssm4567.c2
-rw-r--r--sound/soc/codecs/sta32x.c2
-rw-r--r--sound/soc/codecs/sta350.c2
-rw-r--r--sound/soc/codecs/sta529.c2
-rw-r--r--sound/soc/codecs/tas2552.c2
-rw-r--r--sound/soc/codecs/tas2562.c3
-rw-r--r--sound/soc/codecs/tas2764.c2
-rw-r--r--sound/soc/codecs/tas2770.c2
-rw-r--r--sound/soc/codecs/tas2780.c2
-rw-r--r--sound/soc/codecs/tas2781-comlib.c534
-rw-r--r--sound/soc/codecs/tas2781-fmwlib.c2428
-rw-r--r--sound/soc/codecs/tas2781-i2c.c763
-rw-r--r--sound/soc/codecs/tas5086.c2
-rw-r--r--sound/soc/codecs/tas571x.c2
-rw-r--r--sound/soc/codecs/tas5720.c3
-rw-r--r--sound/soc/codecs/tas5805m.c2
-rw-r--r--sound/soc/codecs/tas6424.c3
-rw-r--r--sound/soc/codecs/tda7419.c2
-rw-r--r--sound/soc/codecs/tfa9879.c2
-rw-r--r--sound/soc/codecs/tfa989x.c2
-rw-r--r--sound/soc/codecs/tlv320adc3xxx.c2
-rw-r--r--sound/soc/codecs/tlv320adcx140.c2
-rw-r--r--sound/soc/codecs/tlv320aic23-i2c.c2
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c2
-rw-r--r--sound/soc/codecs/tlv320aic32x4-i2c.c2
-rw-r--r--sound/soc/codecs/tlv320aic3x-i2c.c2
-rw-r--r--sound/soc/codecs/tlv320dac33.c2
-rw-r--r--sound/soc/codecs/tpa6130a2.c2
-rw-r--r--sound/soc/codecs/ts3a227e.c2
-rw-r--r--sound/soc/codecs/tscs42xx.c2
-rw-r--r--sound/soc/codecs/tscs454.c2
-rw-r--r--sound/soc/codecs/uda1380.c2
-rw-r--r--sound/soc/codecs/wcd938x-sdw.c2
-rw-r--r--sound/soc/codecs/wm0010.c3
-rw-r--r--sound/soc/codecs/wm1250-ev1.c2
-rw-r--r--sound/soc/codecs/wm2000.c2
-rw-r--r--sound/soc/codecs/wm2200.c2
-rw-r--r--sound/soc/codecs/wm5100.c2
-rw-r--r--sound/soc/codecs/wm8510.c2
-rw-r--r--sound/soc/codecs/wm8523.c2
-rw-r--r--sound/soc/codecs/wm8580.c2
-rw-r--r--sound/soc/codecs/wm8711.c2
-rw-r--r--sound/soc/codecs/wm8728.c2
-rw-r--r--sound/soc/codecs/wm8731-i2c.c2
-rw-r--r--sound/soc/codecs/wm8737.c2
-rw-r--r--sound/soc/codecs/wm8741.c2
-rw-r--r--sound/soc/codecs/wm8750.c2
-rw-r--r--sound/soc/codecs/wm8753.c2
-rw-r--r--sound/soc/codecs/wm8776.c2
-rw-r--r--sound/soc/codecs/wm8804-i2c.c2
-rw-r--r--sound/soc/codecs/wm8900.c2
-rw-r--r--sound/soc/codecs/wm8903.c2
-rw-r--r--sound/soc/codecs/wm8904.c2
-rw-r--r--sound/soc/codecs/wm8940.c2
-rw-r--r--sound/soc/codecs/wm8955.c2
-rw-r--r--sound/soc/codecs/wm8960.c2
-rw-r--r--sound/soc/codecs/wm8961.c2
-rw-r--r--sound/soc/codecs/wm8962.c2
-rw-r--r--sound/soc/codecs/wm8971.c2
-rw-r--r--sound/soc/codecs/wm8974.c2
-rw-r--r--sound/soc/codecs/wm8978.c2
-rw-r--r--sound/soc/codecs/wm8983.c2
-rw-r--r--sound/soc/codecs/wm8985.c2
-rw-r--r--sound/soc/codecs/wm8988.c2
-rw-r--r--sound/soc/codecs/wm8990.c2
-rw-r--r--sound/soc/codecs/wm8991.c2
-rw-r--r--sound/soc/codecs/wm8993.c2
-rw-r--r--sound/soc/codecs/wm8995.c2
-rw-r--r--sound/soc/codecs/wm8996.c2
-rw-r--r--sound/soc/codecs/wm9081.c2
-rw-r--r--sound/soc/codecs/wm9090.c2
-rw-r--r--sound/soc/codecs/wm_adsp.c21
-rw-r--r--sound/soc/codecs/wsa883x.c3
-rw-r--r--sound/soc/codecs/wsa884x.c1936
241 files changed, 10605 insertions, 478 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 8020097d4e4c..0cd107fa112f 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -57,6 +57,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_AW88395
imply SND_SOC_BT_SCO
imply SND_SOC_BD28623
+ imply SND_SOC_CHV3_CODEC
imply SND_SOC_CQ0093VC
imply SND_SOC_CROS_EC_CODEC
imply SND_SOC_CS35L32
@@ -136,6 +137,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_MAX98363
imply SND_SOC_MAX98373_I2C
imply SND_SOC_MAX98373_SDW
+ imply SND_SOC_MAX98388
imply SND_SOC_MAX98390
imply SND_SOC_MAX98396
imply SND_SOC_MAX9850
@@ -207,6 +209,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RT712_SDCA_DMIC_SDW
imply SND_SOC_RT715_SDW
imply SND_SOC_RT715_SDCA_SDW
+ imply SND_SOC_RT722_SDCA_SDW
imply SND_SOC_RT1308_SDW
imply SND_SOC_RT1316_SDW
imply SND_SOC_RT1318_SDW
@@ -234,6 +237,9 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_TAS2764
imply SND_SOC_TAS2770
imply SND_SOC_TAS2780
+ imply SND_SOC_TAS2781_COMLIB
+ imply SND_SOC_TAS2781_FMWLIB
+ imply SND_SOC_TAS2781_I2C
imply SND_SOC_TAS5086
imply SND_SOC_TAS571X
imply SND_SOC_TAS5720
@@ -324,6 +330,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_WM9713
imply SND_SOC_WSA881X
imply SND_SOC_WSA883X
+ imply SND_SOC_WSA884X
imply SND_SOC_ZL38060
help
Normally ASoC codec drivers are only built if a machine driver which
@@ -643,6 +650,13 @@ config SND_SOC_BD28623
config SND_SOC_BT_SCO
tristate "Dummy BT SCO codec driver"
+config SND_SOC_CHV3_CODEC
+ tristate "Google Chameleon v3 codec driver"
+ help
+ Enable support for the Google Chameleon v3 audio codec.
+ This codec does not have a control interface, it always outputs
+ 8 channel S32_LE audio.
+
config SND_SOC_CPCAP
tristate "Motorola CPCAP codec"
depends on MFD_CPCAP || COMPILE_TEST
@@ -1166,6 +1180,15 @@ config SND_SOC_MAX98373_SDW
interface for control data. Select this if MAX98373 is
connected via soundwire.
+config SND_SOC_MAX98388
+ tristate "Analog Devices MAX98388 Speaker Amplifier"
+ depends on I2C
+ help
+ Enable support for Analog Devices MAX98388 audio
+ amplifier. The device provides a PCM interface for
+ audio data and a standard I2C interface for control
+ data communication.
+
config SND_SOC_MAX98390
tristate "Maxim Integrated MAX98390 Speaker Amplifier"
depends on I2C
@@ -1539,6 +1562,12 @@ config SND_SOC_RT712_SDCA_DMIC_SDW
select REGMAP_SOUNDWIRE
select REGMAP_SOUNDWIRE_MBQ
+config SND_SOC_RT722_SDCA_SDW
+ tristate "Realtek RT722 SDCA Codec - SDW"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ select REGMAP_SOUNDWIRE_MBQ
+
config SND_SOC_RT715
tristate
@@ -1652,6 +1681,12 @@ config SND_SOC_SSM2602_I2C
select SND_SOC_SSM2602
select REGMAP_I2C
+config SND_SOC_SSM3515
+ tristate "Analog Devices SSM3515 amplifier driver"
+ select REGMAP_I2C
+ depends on I2C
+ depends on OF
+
config SND_SOC_SSM4567
tristate "Analog Devices ssm4567 amplifier driver support"
depends on I2C
@@ -1699,6 +1734,29 @@ config SND_SOC_TAS2780
Enable support for Texas Instruments TAS2780 high-efficiency
digital input mono Class-D audio power amplifiers.
+config SND_SOC_TAS2781_COMLIB
+ depends on I2C
+ select CRC8
+ select REGMAP_I2C
+ tristate
+
+config SND_SOC_TAS2781_FMWLIB
+ depends on SND_SOC_TAS2781_COMLIB
+ tristate
+ default n
+
+config SND_SOC_TAS2781_I2C
+ tristate "Texas Instruments TAS2781 speaker amplifier based on I2C"
+ depends on I2C
+ select SND_SOC_TAS2781_COMLIB
+ select SND_SOC_TAS2781_FMWLIB
+ help
+ Enable support for Texas Instruments TAS2781 Smart Amplifier
+ Digital input mono Class-D and DSP-inside audio power amplifiers.
+ Note the TAS2781 driver implements a flexible and configurable
+ algo coefficient setting, for one, two or even multiple TAS2781
+ chips.
+
config SND_SOC_TAS5086
tristate "Texas Instruments TAS5086 speaker amplifier"
depends on I2C
@@ -2162,6 +2220,15 @@ config SND_SOC_WSA883X
This enables support for Qualcomm WSA8830/WSA8835 Class-D
Smart Speaker Amplifier.
+config SND_SOC_WSA884X
+ tristate "WSA884X Codec"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ tristate
+ help
+ This enables support for Qualcomm WSA8840/WSA8845/WSA8845H Class-D
+ Smart Speaker Amplifier.
+
config SND_SOC_ZL38060
tristate "Microsemi ZL38060 Connected Home Audio Processor"
depends on SPI_MASTER
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 5cdbae88e6e3..b48a9a323b84 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -51,6 +51,7 @@ snd-soc-aw88395-objs := aw88395/aw88395.o \
aw88395/aw88395_device.o
snd-soc-bd28623-objs := bd28623.o
snd-soc-bt-sco-objs := bt-sco.o
+snd-soc-chv3-codec-objs := chv3-codec.o
snd-soc-cpcap-objs := cpcap.o
snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cros-ec-codec-objs := cros_ec_codec.o
@@ -152,6 +153,7 @@ snd-soc-max98363-objs := max98363.o
snd-soc-max98373-objs := max98373.o
snd-soc-max98373-i2c-objs := max98373-i2c.o
snd-soc-max98373-sdw-objs := max98373-sdw.o
+snd-soc-max98388-objs := max98388.o
snd-soc-max98390-objs := max98390.o
snd-soc-max98396-objs := max98396.o
snd-soc-max9850-objs := max9850.o
@@ -237,6 +239,7 @@ snd-soc-rt712-sdca-objs := rt712-sdca.o rt712-sdca-sdw.o
snd-soc-rt712-sdca-dmic-objs := rt712-sdca-dmic.o
snd-soc-rt715-objs := rt715.o rt715-sdw.o
snd-soc-rt715-sdca-objs := rt715-sdca.o rt715-sdca-sdw.o
+snd-soc-rt722-sdca-objs := rt722-sdca.o rt722-sdca-sdw.o
snd-soc-rt9120-objs := rt9120.o
snd-soc-sdw-mockup-objs := sdw-mockup.o
snd-soc-sgtl5000-objs := sgtl5000.o
@@ -256,6 +259,7 @@ snd-soc-ssm2518-objs := ssm2518.o
snd-soc-ssm2602-objs := ssm2602.o
snd-soc-ssm2602-spi-objs := ssm2602-spi.o
snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o
+snd-soc-ssm3515-objs := ssm3515.o
snd-soc-ssm4567-objs := ssm4567.o
snd-soc-sta32x-objs := sta32x.o
snd-soc-sta350-objs := sta350.o
@@ -269,6 +273,9 @@ snd-soc-tas5805m-objs := tas5805m.o
snd-soc-tas6424-objs := tas6424.o
snd-soc-tda7419-objs := tda7419.o
snd-soc-tas2770-objs := tas2770.o
+snd-soc-tas2781-comlib-objs := tas2781-comlib.o
+snd-soc-tas2781-fmwlib-objs := tas2781-fmwlib.o
+snd-soc-tas2781-i2c-objs := tas2781-i2c.o
snd-soc-tfa9879-objs := tfa9879.o
snd-soc-tfa989x-objs := tfa989x.o
snd-soc-tlv320adc3xxx-objs := tlv320adc3xxx.o
@@ -359,6 +366,7 @@ snd-soc-wm9713-objs := wm9713.o
snd-soc-wm-hubs-objs := wm_hubs.o
snd-soc-wsa881x-objs := wsa881x.o
snd-soc-wsa883x-objs := wsa883x.o
+snd-soc-wsa884x-objs := wsa884x.o
snd-soc-zl38060-objs := zl38060.o
# Amp
snd-soc-max9877-objs := max9877.o
@@ -425,6 +433,7 @@ obj-$(CONFIG_SND_SOC_AW88395_LIB) += snd-soc-aw88395-lib.o
obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o
obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
+obj-$(CONFIG_SND_SOC_CHV3_CODEC) += snd-soc-chv3-codec.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CPCAP) += snd-soc-cpcap.o
obj-$(CONFIG_SND_SOC_CROS_EC_CODEC) += snd-soc-cros-ec-codec.o
@@ -521,6 +530,7 @@ obj-$(CONFIG_SND_SOC_MAX98363) += snd-soc-max98363.o
obj-$(CONFIG_SND_SOC_MAX98373) += snd-soc-max98373.o
obj-$(CONFIG_SND_SOC_MAX98373_I2C) += snd-soc-max98373-i2c.o
obj-$(CONFIG_SND_SOC_MAX98373_SDW) += snd-soc-max98373-sdw.o
+obj-$(CONFIG_SND_SOC_MAX98388) += snd-soc-max98388.o
obj-$(CONFIG_SND_SOC_MAX98390) += snd-soc-max98390.o
obj-$(CONFIG_SND_SOC_MAX98396) += snd-soc-max98396.o
obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
@@ -607,6 +617,7 @@ obj-$(CONFIG_SND_SOC_RT712_SDCA_SDW) += snd-soc-rt712-sdca.o
obj-$(CONFIG_SND_SOC_RT712_SDCA_DMIC_SDW) += snd-soc-rt712-sdca-dmic.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_RT722_SDCA_SDW) += snd-soc-rt722-sdca.o
obj-$(CONFIG_SND_SOC_RT9120) += snd-soc-rt9120.o
obj-$(CONFIG_SND_SOC_SDW_MOCKUP) += snd-soc-sdw-mockup.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
@@ -623,6 +634,7 @@ obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o
obj-$(CONFIG_SND_SOC_SSM2602_I2C) += snd-soc-ssm2602-i2c.o
+obj-$(CONFIG_SND_SOC_SSM3515) += snd-soc-ssm3515.o
obj-$(CONFIG_SND_SOC_SSM4567) += snd-soc-ssm4567.o
obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o
obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o
@@ -633,6 +645,9 @@ obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
obj-$(CONFIG_SND_SOC_TAS2562) += snd-soc-tas2562.o
obj-$(CONFIG_SND_SOC_TAS2764) += snd-soc-tas2764.o
obj-$(CONFIG_SND_SOC_TAS2780) += snd-soc-tas2780.o
+obj-$(CONFIG_SND_SOC_TAS2781_COMLIB) += snd-soc-tas2781-comlib.o
+obj-$(CONFIG_SND_SOC_TAS2781_FMWLIB) += snd-soc-tas2781-fmwlib.o
+obj-$(CONFIG_SND_SOC_TAS2781_I2C) += snd-soc-tas2781-i2c.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o
@@ -733,6 +748,7 @@ obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o
obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o
obj-$(CONFIG_SND_SOC_WSA883X) += snd-soc-wsa883x.o
+obj-$(CONFIG_SND_SOC_WSA884X) += snd-soc-wsa884x.o
obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o
# Amp
diff --git a/sound/soc/codecs/ad193x-i2c.c b/sound/soc/codecs/ad193x-i2c.c
index 4cb8d87f9011..15d74bb31c4c 100644
--- a/sound/soc/codecs/ad193x-i2c.c
+++ b/sound/soc/codecs/ad193x-i2c.c
@@ -38,7 +38,7 @@ static struct i2c_driver ad193x_i2c_driver = {
.driver = {
.name = "ad193x",
},
- .probe_new = ad193x_i2c_probe,
+ .probe = ad193x_i2c_probe,
.id_table = ad193x_id,
};
module_i2c_driver(ad193x_i2c_driver);
diff --git a/sound/soc/codecs/adau1372-i2c.c b/sound/soc/codecs/adau1372-i2c.c
index 8ed0ffdedbc9..132b9e2cca59 100644
--- a/sound/soc/codecs/adau1372-i2c.c
+++ b/sound/soc/codecs/adau1372-i2c.c
@@ -30,7 +30,7 @@ static struct i2c_driver adau1372_i2c_driver = {
.driver = {
.name = "adau1372",
},
- .probe_new = adau1372_i2c_probe,
+ .probe = adau1372_i2c_probe,
.id_table = adau1372_i2c_ids,
};
module_i2c_driver(adau1372_i2c_driver);
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 37e178e8a1d0..c5b087b8fffc 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -1505,7 +1505,7 @@ static struct i2c_driver adau1373_i2c_driver = {
.driver = {
.name = "adau1373",
},
- .probe_new = adau1373_i2c_probe,
+ .probe = adau1373_i2c_probe,
.id_table = adau1373_i2c_id,
};
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 135a7db7fcf9..8c8de3b3c901 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -876,7 +876,7 @@ static struct i2c_driver adau1701_i2c_driver = {
.name = "adau1701",
.of_match_table = of_match_ptr(adau1701_dt_ids),
},
- .probe_new = adau1701_i2c_probe,
+ .probe = adau1701_i2c_probe,
.id_table = adau1701_i2c_id,
};
diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c
index 0cefff49569c..a554255186ae 100644
--- a/sound/soc/codecs/adau1761-i2c.c
+++ b/sound/soc/codecs/adau1761-i2c.c
@@ -60,7 +60,7 @@ static struct i2c_driver adau1761_i2c_driver = {
.name = "adau1761",
.of_match_table = of_match_ptr(adau1761_i2c_dt_ids),
},
- .probe_new = adau1761_i2c_probe,
+ .probe = adau1761_i2c_probe,
.remove = adau1761_i2c_remove,
.id_table = adau1761_i2c_ids,
};
diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c
index 39021b8cfb62..3a170fd78ff3 100644
--- a/sound/soc/codecs/adau1781-i2c.c
+++ b/sound/soc/codecs/adau1781-i2c.c
@@ -56,7 +56,7 @@ static struct i2c_driver adau1781_i2c_driver = {
.name = "adau1781",
.of_match_table = of_match_ptr(adau1781_i2c_dt_ids),
},
- .probe_new = adau1781_i2c_probe,
+ .probe = adau1781_i2c_probe,
.remove = adau1781_i2c_remove,
.id_table = adau1781_i2c_ids,
};
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index 634d4dbca5ec..f2932713b4de 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -1059,13 +1059,12 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
if (!adau)
return -ENOMEM;
- adau->mclk = devm_clk_get(dev, "mclk");
- if (IS_ERR(adau->mclk)) {
- if (PTR_ERR(adau->mclk) != -ENOENT)
- return PTR_ERR(adau->mclk);
- /* Clock is optional (for the driver) */
- adau->mclk = NULL;
- } else if (adau->mclk) {
+ /* Clock is optional (for the driver) */
+ adau->mclk = devm_clk_get_optional(dev, "mclk");
+ if (IS_ERR(adau->mclk))
+ return PTR_ERR(adau->mclk);
+
+ if (adau->mclk) {
adau->clk_src = ADAU17X1_CLK_SRC_PLL_AUTO;
/*
diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c
index 9f137a0634d5..24c7b9c84c19 100644
--- a/sound/soc/codecs/adau1977-i2c.c
+++ b/sound/soc/codecs/adau1977-i2c.c
@@ -42,7 +42,7 @@ static struct i2c_driver adau1977_i2c_driver = {
.driver = {
.name = "adau1977",
},
- .probe_new = adau1977_i2c_probe,
+ .probe = adau1977_i2c_probe,
.id_table = adau1977_i2c_ids,
};
module_i2c_driver(adau1977_i2c_driver);
diff --git a/sound/soc/codecs/adau7118-i2c.c b/sound/soc/codecs/adau7118-i2c.c
index afed48401b25..73f181f7757e 100644
--- a/sound/soc/codecs/adau7118-i2c.c
+++ b/sound/soc/codecs/adau7118-i2c.c
@@ -78,7 +78,7 @@ static struct i2c_driver adau7118_driver = {
.name = "adau7118",
.of_match_table = adau7118_of_match,
},
- .probe_new = adau7118_probe_i2c,
+ .probe = adau7118_probe_i2c,
.id_table = adau7118_id,
};
module_i2c_driver(adau7118_driver);
diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c
index bf181bbaabed..78a317947df9 100644
--- a/sound/soc/codecs/adav803.c
+++ b/sound/soc/codecs/adav803.c
@@ -29,7 +29,7 @@ static struct i2c_driver adav803_driver = {
.driver = {
.name = "adav803",
},
- .probe_new = adav803_probe,
+ .probe = adav803_probe,
.id_table = adav803_id,
};
module_i2c_driver(adav803_driver);
diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c
index b6d9a10bdccd..e34e5533765c 100644
--- a/sound/soc/codecs/ak4118.c
+++ b/sound/soc/codecs/ak4118.c
@@ -264,8 +264,6 @@ static irqreturn_t ak4118_irq_handler(int irq, void *data)
struct ak4118_priv *ak4118 = data;
struct snd_soc_component *component = ak4118->component;
struct snd_kcontrol_new *kctl_new;
- struct snd_kcontrol *kctl;
- struct snd_ctl_elem_id *id;
unsigned int i;
if (!component)
@@ -273,13 +271,8 @@ static irqreturn_t ak4118_irq_handler(int irq, void *data)
for (i = 0; i < ARRAY_SIZE(ak4118_iec958_controls); i++) {
kctl_new = &ak4118_iec958_controls[i];
- kctl = snd_soc_card_get_kcontrol(component->card,
- kctl_new->name);
- if (!kctl)
- continue;
- id = &kctl->id;
- snd_ctl_notify(component->card->snd_card,
- SNDRV_CTL_EVENT_MASK_VALUE, id);
+
+ snd_soc_component_notify_control(component, kctl_new->name);
}
return IRQ_HANDLED;
@@ -414,7 +407,7 @@ static struct i2c_driver ak4118_i2c_driver = {
.of_match_table = of_match_ptr(ak4118_of_match),
},
.id_table = ak4118_id_table,
- .probe_new = ak4118_i2c_probe,
+ .probe = ak4118_i2c_probe,
};
module_i2c_driver(ak4118_i2c_driver);
diff --git a/sound/soc/codecs/ak4375.c b/sound/soc/codecs/ak4375.c
index 573389e402f8..f287acb98646 100644
--- a/sound/soc/codecs/ak4375.c
+++ b/sound/soc/codecs/ak4375.c
@@ -597,7 +597,7 @@ static struct i2c_driver ak4375_i2c_driver = {
.pm = &ak4375_pm,
.of_match_table = ak4375_of_match,
},
- .probe_new = ak4375_i2c_probe,
+ .probe = ak4375_i2c_probe,
.remove = ak4375_i2c_remove,
};
module_i2c_driver(ak4375_i2c_driver);
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index 8c69c8cf9b67..77678f85ad94 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -818,7 +818,7 @@ static struct i2c_driver ak4458_i2c_driver = {
.pm = &ak4458_pm,
.of_match_table = ak4458_of_match,
},
- .probe_new = ak4458_i2c_probe,
+ .probe = ak4458_i2c_probe,
.remove = ak4458_i2c_remove,
};
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 8c8c93eea704..904bf91090aa 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -439,7 +439,7 @@ static struct i2c_driver ak4535_i2c_driver = {
.driver = {
.name = "ak4535",
},
- .probe_new = ak4535_i2c_probe,
+ .probe = ak4535_i2c_probe,
.id_table = ak4535_i2c_id,
};
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index f75c19ef3551..ad56caec9dac 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -925,7 +925,7 @@ static struct i2c_driver ak4613_i2c_driver = {
.name = "ak4613-codec",
.of_match_table = ak4613_of_match,
},
- .probe_new = ak4613_i2c_probe,
+ .probe = ak4613_i2c_probe,
.id_table = ak4613_i2c_id,
};
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index 0d3ee195b3cc..5b7df2f0dd6a 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -628,7 +628,7 @@ static struct i2c_driver ak4641_i2c_driver = {
.driver = {
.name = "ak4641",
},
- .probe_new = ak4641_i2c_probe,
+ .probe = ak4641_i2c_probe,
.remove = ak4641_i2c_remove,
.id_table = ak4641_i2c_id,
};
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 914d5b1969f8..2a8984c1fa9c 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -698,7 +698,7 @@ static struct i2c_driver ak4642_i2c_driver = {
.name = "ak4642-codec",
.of_match_table = ak4642_of_match,
},
- .probe_new = ak4642_i2c_probe,
+ .probe = ak4642_i2c_probe,
.id_table = ak4642_i2c_id,
};
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index cd76765f8cc0..5b849b390c2a 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -655,7 +655,7 @@ static struct i2c_driver ak4671_i2c_driver = {
.driver = {
.name = "ak4671-codec",
},
- .probe_new = ak4671_i2c_probe,
+ .probe = ak4671_i2c_probe,
.id_table = ak4671_i2c_id,
};
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c
index 60abcffe6a0c..442e2cb42df4 100644
--- a/sound/soc/codecs/ak5558.c
+++ b/sound/soc/codecs/ak5558.c
@@ -497,7 +497,7 @@ static struct i2c_driver ak5558_i2c_driver = {
.of_match_table = of_match_ptr(ak5558_i2c_dt_ids),
.pm = &ak5558_pm,
},
- .probe_new = ak5558_i2c_probe,
+ .probe = ak5558_i2c_probe,
.remove = ak5558_i2c_remove,
};
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index 9ef01b1dd294..b24c32206884 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -1083,7 +1083,7 @@ static struct i2c_driver alc5623_i2c_driver = {
.name = "alc562x-codec",
.of_match_table = of_match_ptr(alc5623_of_match),
},
- .probe_new = alc5623_i2c_probe,
+ .probe = alc5623_i2c_probe,
.id_table = alc5623_i2c_table,
};
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index a770704a4e17..d5021f266930 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -1182,7 +1182,7 @@ static struct i2c_driver alc5632_i2c_driver = {
.name = "alc5632",
.of_match_table = of_match_ptr(alc5632_of_match),
},
- .probe_new = alc5632_i2c_probe,
+ .probe = alc5632_i2c_probe,
.id_table = alc5632_i2c_table,
};
diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c
index afdce6b7fa26..9dcd75dd799a 100644
--- a/sound/soc/codecs/aw88395/aw88395.c
+++ b/sound/soc/codecs/aw88395/aw88395.c
@@ -570,7 +570,7 @@ static struct i2c_driver aw88395_i2c_driver = {
.driver = {
.name = AW88395_I2C_NAME,
},
- .probe_new = aw88395_i2c_probe,
+ .probe = aw88395_i2c_probe,
.id_table = aw88395_i2c_id,
};
module_i2c_driver(aw88395_i2c_driver);
diff --git a/sound/soc/codecs/chv3-codec.c b/sound/soc/codecs/chv3-codec.c
new file mode 100644
index 000000000000..ab99effa6874
--- /dev/null
+++ b/sound/soc/codecs/chv3-codec.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/module.h>
+#include <sound/soc.h>
+
+static struct snd_soc_dai_driver chv3_codec_dai = {
+ .name = "chv3-codec-hifi",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 8,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ },
+};
+
+static const struct snd_soc_component_driver soc_component_dev_chv3_codec = {
+};
+
+static int chv3_codec_probe(struct platform_device *pdev)
+{
+ return devm_snd_soc_register_component(&pdev->dev,
+ &soc_component_dev_chv3_codec, &chv3_codec_dai, 1);
+}
+
+static const struct of_device_id chv3_codec_of_match[] = {
+ { .compatible = "google,chv3-codec", },
+ { }
+};
+
+static struct platform_driver chv3_codec_platform_driver = {
+ .driver = {
+ .name = "chv3-codec",
+ .of_match_table = chv3_codec_of_match,
+ },
+ .probe = chv3_codec_probe,
+};
+module_platform_driver(chv3_codec_platform_driver);
+
+MODULE_DESCRIPTION("ASoC Chameleon v3 codec driver");
+MODULE_AUTHOR("Pawel Anikiel <pan@semihalf.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index dc7a58d68076..6e658bb16fb0 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -260,7 +260,7 @@ static const struct regmap_config cs35l32_regmap = {
.volatile_reg = cs35l32_volatile_register,
.readable_reg = cs35l32_readable_register,
.precious_reg = cs35l32_precious_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
@@ -572,7 +572,7 @@ static struct i2c_driver cs35l32_i2c_driver = {
.of_match_table = cs35l32_of_match,
},
.id_table = cs35l32_id,
- .probe_new = cs35l32_i2c_probe,
+ .probe = cs35l32_i2c_probe,
.remove = cs35l32_i2c_remove,
};
diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c
index 15e79168d256..9968c2e189e6 100644
--- a/sound/soc/codecs/cs35l33.c
+++ b/sound/soc/codecs/cs35l33.c
@@ -852,7 +852,7 @@ static const struct regmap_config cs35l33_regmap = {
.volatile_reg = cs35l33_volatile_register,
.readable_reg = cs35l33_readable_register,
.writeable_reg = cs35l33_writeable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -1282,7 +1282,7 @@ static struct i2c_driver cs35l33_i2c_driver = {
},
.id_table = cs35l33_id,
- .probe_new = cs35l33_i2c_probe,
+ .probe = cs35l33_i2c_probe,
.remove = cs35l33_i2c_remove,
};
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
index b3f98023e6a7..6974dd461410 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -799,7 +799,7 @@ static struct regmap_config cs35l34_regmap = {
.volatile_reg = cs35l34_volatile_register,
.readable_reg = cs35l34_readable_register,
.precious_reg = cs35l34_precious_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
@@ -1213,7 +1213,7 @@ static struct i2c_driver cs35l34_i2c_driver = {
},
.id_table = cs35l34_id,
- .probe_new = cs35l34_i2c_probe,
+ .probe = cs35l34_i2c_probe,
.remove = cs35l34_i2c_remove,
};
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
index 947a440a3a47..0a4b5aa78185 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -1099,7 +1099,7 @@ static struct regmap_config cs35l35_regmap = {
.volatile_reg = cs35l35_volatile_register,
.readable_reg = cs35l35_readable_register,
.precious_reg = cs35l35_precious_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -1654,7 +1654,7 @@ static struct i2c_driver cs35l35_i2c_driver = {
.of_match_table = cs35l35_of_match,
},
.id_table = cs35l35_id,
- .probe_new = cs35l35_i2c_probe,
+ .probe = cs35l35_i2c_probe,
.remove = cs35l35_i2c_remove,
};
diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c
index a078dd422ea1..04ba7f25012e 100644
--- a/sound/soc/codecs/cs35l36.c
+++ b/sound/soc/codecs/cs35l36.c
@@ -1944,7 +1944,7 @@ static struct i2c_driver cs35l36_i2c_driver = {
.of_match_table = cs35l36_of_match,
},
.id_table = cs35l36_id,
- .probe_new = cs35l36_i2c_probe,
+ .probe = cs35l36_i2c_probe,
.remove = cs35l36_i2c_remove,
};
module_i2c_driver(cs35l36_i2c_driver);
diff --git a/sound/soc/codecs/cs35l41-i2c.c b/sound/soc/codecs/cs35l41-i2c.c
index 3676b596f60b..7ea890d7d387 100644
--- a/sound/soc/codecs/cs35l41-i2c.c
+++ b/sound/soc/codecs/cs35l41-i2c.c
@@ -88,7 +88,7 @@ static struct i2c_driver cs35l41_i2c_driver = {
.acpi_match_table = ACPI_PTR(cs35l41_acpi_match),
},
.id_table = cs35l41_id_i2c,
- .probe_new = cs35l41_i2c_probe,
+ .probe = cs35l41_i2c_probe,
.remove = cs35l41_i2c_remove,
};
diff --git a/sound/soc/codecs/cs35l45-i2c.c b/sound/soc/codecs/cs35l45-i2c.c
index 562f73df7afa..77e0f8750f37 100644
--- a/sound/soc/codecs/cs35l45-i2c.c
+++ b/sound/soc/codecs/cs35l45-i2c.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+// SPDX-License-Identifier: GPL-2.0
//
// cs35l45-i2c.c -- CS35L45 I2C driver
//
@@ -65,12 +65,12 @@ static struct i2c_driver cs35l45_i2c_driver = {
.pm = &cs35l45_pm_ops,
},
.id_table = cs35l45_id_i2c,
- .probe_new = cs35l45_i2c_probe,
+ .probe = cs35l45_i2c_probe,
.remove = cs35l45_i2c_remove,
};
module_i2c_driver(cs35l45_i2c_driver);
MODULE_DESCRIPTION("I2C CS35L45 driver");
MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(SND_SOC_CS35L45);
diff --git a/sound/soc/codecs/cs35l45-spi.c b/sound/soc/codecs/cs35l45-spi.c
index a00b23b4180c..5efb77530cc3 100644
--- a/sound/soc/codecs/cs35l45-spi.c
+++ b/sound/soc/codecs/cs35l45-spi.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+// SPDX-License-Identifier: GPL-2.0
//
// cs35l45-spi.c -- CS35L45 SPI driver
//
@@ -74,5 +74,5 @@ module_spi_driver(cs35l45_spi_driver);
MODULE_DESCRIPTION("SPI CS35L45 driver");
MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(SND_SOC_CS35L45);
diff --git a/sound/soc/codecs/cs35l45-tables.c b/sound/soc/codecs/cs35l45-tables.c
index 46610e64e818..066f83c0c7ac 100644
--- a/sound/soc/codecs/cs35l45-tables.c
+++ b/sound/soc/codecs/cs35l45-tables.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+// SPDX-License-Identifier: GPL-2.0
//
// cs35l45-tables.c -- CS35L45 ALSA SoC audio driver
//
diff --git a/sound/soc/codecs/cs35l45.c b/sound/soc/codecs/cs35l45.c
index c31597f6bfae..d1edb9876c10 100644
--- a/sound/soc/codecs/cs35l45.c
+++ b/sound/soc/codecs/cs35l45.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+// SPDX-License-Identifier: GPL-2.0
//
// cs35l45.c - CS35L45 ALSA SoC audio driver
//
@@ -1296,4 +1296,4 @@ EXPORT_SYMBOL_NS_GPL(cs35l45_pm_ops, SND_SOC_CS35L45);
MODULE_DESCRIPTION("ASoC CS35L45 driver");
MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l45.h b/sound/soc/codecs/cs35l45.h
index 0da28439f628..61135a316df3 100644
--- a/sound/soc/codecs/cs35l45.h
+++ b/sound/soc/codecs/cs35l45.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* cs35l45.h - CS35L45 ALSA SoC audio driver
*
diff --git a/sound/soc/codecs/cs35l56-i2c.c b/sound/soc/codecs/cs35l56-i2c.c
index 295caad26224..ed2a41943d97 100644
--- a/sound/soc/codecs/cs35l56-i2c.c
+++ b/sound/soc/codecs/cs35l56-i2c.c
@@ -68,7 +68,7 @@ static struct i2c_driver cs35l56_i2c_driver = {
.pm = &cs35l56_pm_ops_i2c_spi,
},
.id_table = cs35l56_id_i2c,
- .probe_new = cs35l56_i2c_probe,
+ .probe = cs35l56_i2c_probe,
.remove = cs35l56_i2c_remove,
};
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index e0d2b9bb2326..c03f9d3c9a13 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -822,25 +822,23 @@ static void cs35l56_system_reset(struct cs35l56_private *cs35l56)
regcache_cache_only(cs35l56->regmap, false);
}
-static void cs35l56_dsp_work(struct work_struct *work)
+static void cs35l56_secure_patch(struct cs35l56_private *cs35l56)
{
- struct cs35l56_private *cs35l56 = container_of(work,
- struct cs35l56_private,
- dsp_work);
- unsigned int reg;
- unsigned int val;
- int ret = 0;
-
- if (!cs35l56->init_done)
- return;
-
- cs35l56->dsp.part = devm_kasprintf(cs35l56->dev, GFP_KERNEL, "cs35l56%s-%02x",
- cs35l56->secured ? "s" : "", cs35l56->rev);
+ int ret;
- if (!cs35l56->dsp.part)
- return;
+ /* Use wm_adsp to load and apply the firmware patch and coefficient files */
+ ret = wm_adsp_power_up(&cs35l56->dsp);
+ if (ret)
+ dev_dbg(cs35l56->dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
+ else
+ cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_AUDIO_REINIT);
+}
- pm_runtime_get_sync(cs35l56->dev);
+static void cs35l56_patch(struct cs35l56_private *cs35l56)
+{
+ unsigned int reg;
+ unsigned int val;
+ int ret;
/*
* Disable SoundWire interrupts to prevent race with IRQ work.
@@ -907,9 +905,6 @@ static void cs35l56_dsp_work(struct work_struct *work)
err_unlock:
mutex_unlock(&cs35l56->irq_lock);
err:
- pm_runtime_mark_last_busy(cs35l56->dev);
- pm_runtime_put_autosuspend(cs35l56->dev);
-
/* Re-enable SoundWire interrupts */
if (cs35l56->sdw_peripheral) {
cs35l56->sdw_irq_no_unmask = false;
@@ -918,6 +913,32 @@ err:
}
}
+static void cs35l56_dsp_work(struct work_struct *work)
+{
+ struct cs35l56_private *cs35l56 = container_of(work,
+ struct cs35l56_private,
+ dsp_work);
+
+ if (!cs35l56->init_done)
+ return;
+
+ pm_runtime_get_sync(cs35l56->dev);
+
+ /*
+ * When the device is running in secure mode the firmware files can
+ * only contain insecure tunings and therefore we do not need to
+ * shutdown the firmware to apply them and can use the lower cost
+ * reinit sequence instead.
+ */
+ if (cs35l56->secured)
+ cs35l56_secure_patch(cs35l56);
+ else
+ cs35l56_patch(cs35l56);
+
+ pm_runtime_mark_last_busy(cs35l56->dev);
+ pm_runtime_put_autosuspend(cs35l56->dev);
+}
+
static int cs35l56_component_probe(struct snd_soc_component *component)
{
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
@@ -1505,6 +1526,12 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
dev_info(cs35l56->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n",
cs35l56->secured ? "s" : "", cs35l56->rev, otpid);
+ /* Populate the DSP information with the revision and security state */
+ cs35l56->dsp.part = devm_kasprintf(cs35l56->dev, GFP_KERNEL, "cs35l56%s-%02x",
+ cs35l56->secured ? "s" : "", cs35l56->rev);
+ if (!cs35l56->dsp.part)
+ return -ENOMEM;
+
/* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */
regmap_write(cs35l56->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
regmap_update_bits(cs35l56->regmap, CS35L56_IRQ1_MASK_1,
diff --git a/sound/soc/codecs/cs4234.c b/sound/soc/codecs/cs4234.c
index dee1a6662c2e..69287ba7e955 100644
--- a/sound/soc/codecs/cs4234.c
+++ b/sound/soc/codecs/cs4234.c
@@ -675,7 +675,7 @@ static const struct regmap_config cs4234_regmap = {
.writeable_reg = cs4234_writeable_register,
.reg_defaults = cs4234_default_reg,
.num_reg_defaults = ARRAY_SIZE(cs4234_default_reg),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -906,7 +906,7 @@ static struct i2c_driver cs4234_i2c_driver = {
.pm = &cs4234_pm,
.of_match_table = cs4234_of_match,
},
- .probe_new = cs4234_i2c_probe,
+ .probe = cs4234_i2c_probe,
.remove = cs4234_i2c_remove,
};
module_i2c_driver(cs4234_i2c_driver);
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
index 3573363b7e31..0cfc5ab36a13 100644
--- a/sound/soc/codecs/cs4265.c
+++ b/sound/soc/codecs/cs4265.c
@@ -649,7 +649,7 @@ static struct i2c_driver cs4265_i2c_driver = {
.of_match_table = cs4265_of_match,
},
.id_table = cs4265_id,
- .probe_new = cs4265_i2c_probe,
+ .probe = cs4265_i2c_probe,
.remove = cs4265_i2c_remove,
};
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 1b640d8232ba..ab32f15e3b44 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -751,7 +751,7 @@ static struct i2c_driver cs4270_i2c_driver = {
.of_match_table = cs4270_of_match,
},
.id_table = cs4270_id,
- .probe_new = cs4270_i2c_probe,
+ .probe = cs4270_i2c_probe,
.remove = cs4270_i2c_remove,
};
diff --git a/sound/soc/codecs/cs4271-i2c.c b/sound/soc/codecs/cs4271-i2c.c
index 4033be1c3bc1..89fe7d1665df 100644
--- a/sound/soc/codecs/cs4271-i2c.c
+++ b/sound/soc/codecs/cs4271-i2c.c
@@ -33,7 +33,7 @@ static struct i2c_driver cs4271_i2c_driver = {
.name = "cs4271",
.of_match_table = of_match_ptr(cs4271_dt_ids),
},
- .probe_new = cs4271_i2c_probe,
+ .probe = cs4271_i2c_probe,
.id_table = cs4271_i2c_id,
};
module_i2c_driver(cs4271_i2c_driver);
diff --git a/sound/soc/codecs/cs42l42-i2c.c b/sound/soc/codecs/cs42l42-i2c.c
index 67b253287daf..2552a1e6b82f 100644
--- a/sound/soc/codecs/cs42l42-i2c.c
+++ b/sound/soc/codecs/cs42l42-i2c.c
@@ -92,7 +92,7 @@ static struct i2c_driver cs42l42_i2c_driver = {
.acpi_match_table = ACPI_PTR(cs42l42_acpi_match),
},
.id_table = cs42l42_id,
- .probe_new = cs42l42_i2c_probe,
+ .probe = cs42l42_i2c_probe,
.remove = cs42l42_i2c_remove,
};
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index e3edaa1a2761..a0de0329406a 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -393,7 +393,7 @@ const struct regmap_config cs42l42_regmap = {
.max_register = CS42L42_MAX_REGISTER,
.reg_defaults = cs42l42_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(cs42l42_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
@@ -646,12 +646,19 @@ static const struct cs42l42_pll_params pll_ratio_table[] = {
{ 3072000, 1, 0x00, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125, 1},
{ 4000000, 1, 0x00, 0x30, 0x800000, 0x03, 0x10, 12000000, 96, 1},
{ 4096000, 1, 0x00, 0x2E, 0xE00000, 0x03, 0x10, 12000000, 94, 1},
+ { 4800000, 1, 0x01, 0x50, 0x000000, 0x03, 0x10, 12000000, 80, 2},
+ { 4800000, 1, 0x01, 0x50, 0x000000, 0x01, 0x10, 12288000, 82, 2},
{ 5644800, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 11289600, 128, 1},
{ 6000000, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12000000, 128, 1},
{ 6144000, 1, 0x01, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125, 1},
+ { 6144000, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12288000, 128, 1},
+ { 9600000, 1, 0x02, 0x50, 0x000000, 0x03, 0x10, 12000000, 80, 2},
+ { 9600000, 1, 0x02, 0x50, 0x000000, 0x01, 0x10, 12288000, 82, 2},
{ 11289600, 0, 0, 0, 0, 0, 0, 11289600, 0, 1},
{ 12000000, 0, 0, 0, 0, 0, 0, 12000000, 0, 1},
{ 12288000, 0, 0, 0, 0, 0, 0, 12288000, 0, 1},
+ { 19200000, 1, 0x03, 0x50, 0x000000, 0x03, 0x10, 12000000, 80, 2},
+ { 19200000, 1, 0x03, 0x50, 0x000000, 0x01, 0x10, 12288000, 82, 2},
{ 22579200, 1, 0x03, 0x40, 0x000000, 0x03, 0x10, 11289600, 128, 1},
{ 24000000, 1, 0x03, 0x40, 0x000000, 0x03, 0x10, 12000000, 128, 1},
{ 24576000, 1, 0x03, 0x40, 0x000000, 0x03, 0x10, 12288000, 128, 1}
diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c
index 85238339fbca..b2106ff6a7cb 100644
--- a/sound/soc/codecs/cs42l51-i2c.c
+++ b/sound/soc/codecs/cs42l51-i2c.c
@@ -43,7 +43,7 @@ static struct i2c_driver cs42l51_i2c_driver = {
.of_match_table = cs42l51_of_match,
.pm = &cs42l51_pm_ops,
},
- .probe_new = cs42l51_i2c_probe,
+ .probe = cs42l51_i2c_probe,
.remove = cs42l51_i2c_remove,
.id_table = cs42l51_i2c_id,
};
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index e88d9ff95cdf..a67cd3ee84e0 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -724,12 +724,9 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
dev_set_drvdata(dev, cs42l51);
cs42l51->regmap = regmap;
- cs42l51->mclk_handle = devm_clk_get(dev, "MCLK");
- if (IS_ERR(cs42l51->mclk_handle)) {
- if (PTR_ERR(cs42l51->mclk_handle) != -ENOENT)
- return PTR_ERR(cs42l51->mclk_handle);
- cs42l51->mclk_handle = NULL;
- }
+ cs42l51->mclk_handle = devm_clk_get_optional(dev, "MCLK");
+ if (IS_ERR(cs42l51->mclk_handle))
+ return PTR_ERR(cs42l51->mclk_handle);
for (i = 0; i < ARRAY_SIZE(cs42l51->supplies); i++)
cs42l51->supplies[i].supply = cs42l51_supply_names[i];
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 90bf535fc5a5..1f1ded0ff0ac 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -1226,7 +1226,7 @@ static struct i2c_driver cs42l52_i2c_driver = {
.of_match_table = cs42l52_of_match,
},
.id_table = cs42l52_id,
- .probe_new = cs42l52_i2c_probe,
+ .probe = cs42l52_i2c_probe,
};
module_i2c_driver(cs42l52_i2c_driver);
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index 3b0e715549c9..4c646e8d72aa 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -1341,7 +1341,7 @@ static struct i2c_driver cs42l56_i2c_driver = {
.of_match_table = cs42l56_of_match,
},
.id_table = cs42l56_id,
- .probe_new = cs42l56_i2c_probe,
+ .probe = cs42l56_i2c_probe,
.remove = cs42l56_i2c_remove,
};
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 0a146319755a..6ab67d196d10 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -1267,7 +1267,7 @@ static const struct regmap_config cs42l73_regmap = {
.num_reg_defaults = ARRAY_SIZE(cs42l73_reg_defaults),
.volatile_reg = cs42l73_volatile_register,
.readable_reg = cs42l73_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
@@ -1384,7 +1384,7 @@ static struct i2c_driver cs42l73_i2c_driver = {
.of_match_table = cs42l73_of_match,
},
.id_table = cs42l73_id,
- .probe_new = cs42l73_i2c_probe,
+ .probe = cs42l73_i2c_probe,
};
diff --git a/sound/soc/codecs/cs42l83-i2c.c b/sound/soc/codecs/cs42l83-i2c.c
index 37629ebd90e0..f482b6a4f5c3 100644
--- a/sound/soc/codecs/cs42l83-i2c.c
+++ b/sound/soc/codecs/cs42l83-i2c.c
@@ -158,7 +158,7 @@ static const struct regmap_config cs42l83_regmap = {
.max_register = CS42L42_MAX_REGISTER,
.reg_defaults = cs42l83_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(cs42l83_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
@@ -228,7 +228,7 @@ static struct i2c_driver cs42l83_i2c_driver = {
.pm = &cs42l83_i2c_pm_ops,
.of_match_table = of_match_ptr(cs42l83_of_match),
},
- .probe_new = cs42l83_i2c_probe,
+ .probe = cs42l83_i2c_probe,
.remove = cs42l83_i2c_remove,
};
diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c
index 052ffb7dcfc6..a422472820fb 100644
--- a/sound/soc/codecs/cs42xx8-i2c.c
+++ b/sound/soc/codecs/cs42xx8-i2c.c
@@ -70,7 +70,7 @@ static struct i2c_driver cs42xx8_i2c_driver = {
.pm = &cs42xx8_pm,
.of_match_table = cs42xx8_of_match,
},
- .probe_new = cs42xx8_i2c_probe,
+ .probe = cs42xx8_i2c_probe,
.remove = cs42xx8_i2c_remove,
.id_table = cs42xx8_i2c_id,
};
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c
index db39abb2a31b..3292405024bc 100644
--- a/sound/soc/codecs/cs43130.c
+++ b/sound/soc/codecs/cs43130.c
@@ -2357,7 +2357,7 @@ static const struct regmap_config cs43130_regmap = {
.readable_reg = cs43130_readable_register,
.precious_reg = cs43130_precious_register,
.volatile_reg = cs43130_volatile_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
/* needed for regcache_sync */
.use_single_read = true,
.use_single_write = true,
@@ -2697,7 +2697,7 @@ static struct i2c_driver cs43130_i2c_driver = {
.pm = &cs43130_runtime_pm,
},
.id_table = cs43130_i2c_id,
- .probe_new = cs43130_i2c_probe,
+ .probe = cs43130_i2c_probe,
.remove = cs43130_i2c_remove,
};
diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c
index ac1696034846..2ceca5d0e5bf 100644
--- a/sound/soc/codecs/cs4341.c
+++ b/sound/soc/codecs/cs4341.c
@@ -258,7 +258,7 @@ static struct i2c_driver cs4341_i2c_driver = {
.name = "cs4341-i2c",
.of_match_table = of_match_ptr(cs4341_dt_ids),
},
- .probe_new = cs4341_i2c_probe,
+ .probe = cs4341_i2c_probe,
.id_table = cs4341_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
index ba94ffd0a7e4..8365dd0ebe2a 100644
--- a/sound/soc/codecs/cs4349.c
+++ b/sound/soc/codecs/cs4349.c
@@ -375,7 +375,7 @@ static struct i2c_driver cs4349_i2c_driver = {
.pm = &cs4349_runtime_pm,
},
.id_table = cs4349_i2c_id,
- .probe_new = cs4349_i2c_probe,
+ .probe = cs4349_i2c_probe,
.remove = cs4349_i2c_remove,
};
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index 69db0013d243..f4065555c36e 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -911,7 +911,7 @@ static struct regmap_config cs53l30_regmap = {
.volatile_reg = cs53l30_volatile_register,
.writeable_reg = cs53l30_writeable_register,
.readable_reg = cs53l30_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
@@ -990,14 +990,10 @@ static int cs53l30_i2c_probe(struct i2c_client *client)
}
/* Check if MCLK provided */
- cs53l30->mclk = devm_clk_get(dev, "mclk");
+ cs53l30->mclk = devm_clk_get_optional(dev, "mclk");
if (IS_ERR(cs53l30->mclk)) {
- if (PTR_ERR(cs53l30->mclk) != -ENOENT) {
- ret = PTR_ERR(cs53l30->mclk);
- goto error;
- }
- /* Otherwise mark the mclk pointer to NULL */
- cs53l30->mclk = NULL;
+ ret = PTR_ERR(cs53l30->mclk);
+ goto error;
}
/* Fetch the MUTE control */
@@ -1121,7 +1117,7 @@ static struct i2c_driver cs53l30_i2c_driver = {
.pm = &cs53l30_runtime_pm,
},
.id_table = cs53l30_id,
- .probe_new = cs53l30_i2c_probe,
+ .probe = cs53l30_i2c_probe,
.remove = cs53l30_i2c_remove,
};
diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c
index 5deceaa89282..082231088a26 100644
--- a/sound/soc/codecs/cx2072x.c
+++ b/sound/soc/codecs/cx2072x.c
@@ -1706,7 +1706,7 @@ static struct i2c_driver cx2072x_i2c_driver = {
.acpi_match_table = ACPI_PTR(cx2072x_acpi_match),
.pm = &cx2072x_runtime_pm,
},
- .probe_new = cx2072x_i2c_probe,
+ .probe = cx2072x_i2c_probe,
.remove = cx2072x_i2c_remove,
.id_table = cx2072x_i2c_id,
};
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index f838466bfebf..1e232d01809c 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -1248,7 +1248,7 @@ static struct i2c_driver da7210_i2c_driver = {
.driver = {
.name = "da7210",
},
- .probe_new = da7210_i2c_probe,
+ .probe = da7210_i2c_probe,
.id_table = da7210_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 1c1f211a8e2e..3a6449c44b23 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -2069,7 +2069,7 @@ static struct i2c_driver da7213_i2c_driver = {
.acpi_match_table = ACPI_PTR(da7213_acpi_match),
.pm = &da7213_pm,
},
- .probe_new = da7213_i2c_probe,
+ .probe = da7213_i2c_probe,
.remove = da7213_i2c_remove,
.id_table = da7213_i2c_id,
};
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index d9c28e701613..3f456b08b809 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -3317,7 +3317,7 @@ static struct i2c_driver da7218_i2c_driver = {
.name = "da7218",
.of_match_table = da7218_of_match,
},
- .probe_new = da7218_i2c_probe,
+ .probe = da7218_i2c_probe,
.id_table = da7218_i2c_id,
};
diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c
index 993a0d00bc48..c65256bd526d 100644
--- a/sound/soc/codecs/da7219-aad.c
+++ b/sound/soc/codecs/da7219-aad.c
@@ -571,16 +571,29 @@ static enum da7219_aad_jack_ins_deb
}
}
+static enum da7219_aad_jack_ins_det_pty
+ da7219_aad_fw_jack_ins_det_pty(struct device *dev, const char *str)
+{
+ if (!strcmp(str, "low")) {
+ return DA7219_AAD_JACK_INS_DET_PTY_LOW;
+ } else if (!strcmp(str, "high")) {
+ return DA7219_AAD_JACK_INS_DET_PTY_HIGH;
+ } else {
+ dev_warn(dev, "Invalid jack insertion detection polarity");
+ return DA7219_AAD_JACK_INS_DET_PTY_LOW;
+ }
+}
+
static enum da7219_aad_jack_det_rate
da7219_aad_fw_jack_det_rate(struct device *dev, const char *str)
{
- if (!strcmp(str, "32ms_64ms")) {
+ if (!strcmp(str, "32_64")) {
return DA7219_AAD_JACK_DET_RATE_32_64MS;
- } else if (!strcmp(str, "64ms_128ms")) {
+ } else if (!strcmp(str, "64_128")) {
return DA7219_AAD_JACK_DET_RATE_64_128MS;
- } else if (!strcmp(str, "128ms_256ms")) {
+ } else if (!strcmp(str, "128_256")) {
return DA7219_AAD_JACK_DET_RATE_128_256MS;
- } else if (!strcmp(str, "256ms_512ms")) {
+ } else if (!strcmp(str, "256_512")) {
return DA7219_AAD_JACK_DET_RATE_256_512MS;
} else {
dev_warn(dev, "Invalid jack detect rate");
@@ -688,6 +701,12 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev)
else
aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS;
+ if (!fwnode_property_read_string(aad_np, "dlg,jack-ins-det-pty", &fw_str))
+ aad_pdata->jack_ins_det_pty =
+ da7219_aad_fw_jack_ins_det_pty(dev, fw_str);
+ else
+ aad_pdata->jack_ins_det_pty = DA7219_AAD_JACK_INS_DET_PTY_LOW;
+
if (!fwnode_property_read_string(aad_np, "dlg,jack-det-rate", &fw_str))
aad_pdata->jack_det_rate =
da7219_aad_fw_jack_det_rate(dev, fw_str);
@@ -849,6 +868,21 @@ static void da7219_aad_handle_pdata(struct snd_soc_component *component)
mask |= DA7219_ADC_1_BIT_REPEAT_MASK;
}
snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_7, mask, cfg);
+
+ switch (aad_pdata->jack_ins_det_pty) {
+ case DA7219_AAD_JACK_INS_DET_PTY_LOW:
+ snd_soc_component_write(component, 0xF0, 0x8B);
+ snd_soc_component_write(component, 0x75, 0x80);
+ snd_soc_component_write(component, 0xF0, 0x00);
+ break;
+ case DA7219_AAD_JACK_INS_DET_PTY_HIGH:
+ snd_soc_component_write(component, 0xF0, 0x8B);
+ snd_soc_component_write(component, 0x75, 0x00);
+ snd_soc_component_write(component, 0xF0, 0x00);
+ break;
+ default:
+ break;
+ }
}
}
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 7468ee4af2ea..600c2db58756 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -2714,7 +2714,7 @@ static struct i2c_driver da7219_i2c_driver = {
.of_match_table = of_match_ptr(da7219_of_match),
.acpi_match_table = ACPI_PTR(da7219_acpi_match),
},
- .probe_new = da7219_i2c_probe,
+ .probe = da7219_i2c_probe,
.id_table = da7219_i2c_id,
};
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index 2c5b0b74201c..f8ca1afa8af5 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -1555,7 +1555,7 @@ static struct i2c_driver da732x_i2c_driver = {
.driver = {
.name = "da7320",
},
- .probe_new = da732x_i2c_probe,
+ .probe = da732x_i2c_probe,
.id_table = da732x_i2c_id,
};
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index 28043b4530df..ae20086777b5 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -1531,7 +1531,7 @@ static struct i2c_driver da9055_i2c_driver = {
.name = "da9055-codec",
.of_match_table = of_match_ptr(da9055_of_match),
},
- .probe_new = da9055_i2c_probe,
+ .probe = da9055_i2c_probe,
.id_table = da9055_i2c_id,
};
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index a27d80956459..34cf60769b62 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -52,7 +52,12 @@ static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9600, 50, 1);
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9600, 50, 1);
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_max_gain_tlv, -650, 150, 0);
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_min_gain_tlv, -1200, 150, 0);
-static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_target_tlv, -1650, 150, 0);
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(alc_target_tlv,
+ 0, 10, TLV_DB_SCALE_ITEM(-1650, 150, 0),
+ 11, 11, TLV_DB_SCALE_ITEM(-150, 0, 0),
+);
+
static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(hpmixer_gain_tlv,
0, 4, TLV_DB_SCALE_ITEM(-1200, 150, 0),
8, 11, TLV_DB_SCALE_ITEM(-450, 150, 0),
@@ -115,7 +120,7 @@ static const struct snd_kcontrol_new es8316_snd_controls[] = {
alc_max_gain_tlv),
SOC_SINGLE_TLV("ALC Capture Min Volume", ES8316_ADC_ALC2, 0, 28, 0,
alc_min_gain_tlv),
- SOC_SINGLE_TLV("ALC Capture Target Volume", ES8316_ADC_ALC3, 4, 10, 0,
+ SOC_SINGLE_TLV("ALC Capture Target Volume", ES8316_ADC_ALC3, 4, 11, 0,
alc_target_tlv),
SOC_SINGLE("ALC Capture Hold Time", ES8316_ADC_ALC3, 0, 10, 0),
SOC_SINGLE("ALC Capture Decay Time", ES8316_ADC_ALC4, 4, 10, 0),
@@ -364,13 +369,11 @@ static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int count = 0;
es8316->sysclk = freq;
+ es8316->sysclk_constraints.list = NULL;
+ es8316->sysclk_constraints.count = 0;
- if (freq == 0) {
- es8316->sysclk_constraints.list = NULL;
- es8316->sysclk_constraints.count = 0;
-
+ if (freq == 0)
return 0;
- }
ret = clk_set_rate(es8316->mclk, freq);
if (ret)
@@ -386,8 +389,10 @@ static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai,
es8316->allowed_rates[count++] = freq / ratio;
}
- es8316->sysclk_constraints.list = es8316->allowed_rates;
- es8316->sysclk_constraints.count = count;
+ if (count) {
+ es8316->sysclk_constraints.list = es8316->allowed_rates;
+ es8316->sysclk_constraints.count = count;
+ }
return 0;
}
@@ -820,7 +825,7 @@ static const struct regmap_config es8316_regmap = {
.use_single_write = true,
.max_register = 0x53,
.volatile_reg = es8316_volatile_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int es8316_i2c_probe(struct i2c_client *i2c_client)
@@ -887,7 +892,7 @@ static struct i2c_driver es8316_i2c_driver = {
.acpi_match_table = ACPI_PTR(es8316_acpi_match),
.of_match_table = of_match_ptr(es8316_of_match),
},
- .probe_new = es8316_i2c_probe,
+ .probe = es8316_i2c_probe,
.id_table = es8316_i2c_id,
};
module_i2c_driver(es8316_i2c_driver);
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
index 28a0565c2a95..7cb5b57ae655 100644
--- a/sound/soc/codecs/es8326.c
+++ b/sound/soc/codecs/es8326.c
@@ -896,7 +896,7 @@ static struct i2c_driver es8326_i2c_driver = {
.acpi_match_table = ACPI_PTR(es8326_acpi_match),
.of_match_table = of_match_ptr(es8326_of_match),
},
- .probe_new = es8326_i2c_probe,
+ .probe = es8326_i2c_probe,
.id_table = es8326_i2c_id,
};
module_i2c_driver(es8326_i2c_driver);
diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c
index 68072e99fcc7..3c4aaa0032a0 100644
--- a/sound/soc/codecs/es8328-i2c.c
+++ b/sound/soc/codecs/es8328-i2c.c
@@ -40,7 +40,7 @@ static struct i2c_driver es8328_i2c_driver = {
.name = "es8328",
.of_match_table = es8328_of_match,
},
- .probe_new = es8328_i2c_probe,
+ .probe = es8328_i2c_probe,
.id_table = es8328_id,
};
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index 160adc706cc6..0bd9ba5a11b4 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -822,7 +822,7 @@ const struct regmap_config es8328_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = ES8328_REG_MAX,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
index 50105d72b2b7..f9456133a89a 100644
--- a/sound/soc/codecs/isabelle.c
+++ b/sound/soc/codecs/isabelle.c
@@ -1142,7 +1142,7 @@ static struct i2c_driver isabelle_i2c_driver = {
.driver = {
.name = "isabelle",
},
- .probe_new = isabelle_i2c_probe,
+ .probe = isabelle_i2c_probe,
.id_table = isabelle_i2c_id,
};
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c
index dba161305de8..e7542f71323d 100644
--- a/sound/soc/codecs/lm4857.c
+++ b/sound/soc/codecs/lm4857.c
@@ -137,7 +137,7 @@ static struct i2c_driver lm4857_i2c_driver = {
.driver = {
.name = "lm4857",
},
- .probe_new = lm4857_i2c_probe,
+ .probe = lm4857_i2c_probe,
.id_table = lm4857_i2c_id,
};
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index a2e782cc4276..a4094689b3dd 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -1451,7 +1451,7 @@ static struct i2c_driver lm49453_i2c_driver = {
.driver = {
.name = "lm49453",
},
- .probe_new = lm49453_i2c_probe,
+ .probe = lm49453_i2c_probe,
.id_table = lm49453_i2c_id,
};
diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c
index d711eb1da0a8..d22b4ba51ed8 100644
--- a/sound/soc/codecs/max9768.c
+++ b/sound/soc/codecs/max9768.c
@@ -214,7 +214,7 @@ static struct i2c_driver max9768_i2c_driver = {
.driver = {
.name = "max9768",
},
- .probe_new = max9768_i2c_probe,
+ .probe = max9768_i2c_probe,
.id_table = max9768_i2c_id,
};
module_i2c_driver(max9768_i2c_driver);
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 405ec16be2b6..8b56ee550c09 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -310,24 +310,24 @@ static const struct regmap_config max98088_regmap = {
static void m98088_eq_band(struct snd_soc_component *component, unsigned int dai,
unsigned int band, u16 *coefs)
{
- unsigned int eq_reg;
- unsigned int i;
+ unsigned int eq_reg;
+ unsigned int i;
if (WARN_ON(band > 4) ||
WARN_ON(dai > 1))
return;
- /* Load the base register address */
- eq_reg = dai ? M98088_REG_84_DAI2_EQ_BASE : M98088_REG_52_DAI1_EQ_BASE;
+ /* Load the base register address */
+ eq_reg = dai ? M98088_REG_84_DAI2_EQ_BASE : M98088_REG_52_DAI1_EQ_BASE;
- /* Add the band address offset, note adjustment for word address */
- eq_reg += band * (M98088_COEFS_PER_BAND << 1);
+ /* Add the band address offset, note adjustment for word address */
+ eq_reg += band * (M98088_COEFS_PER_BAND << 1);
- /* Step through the registers and coefs */
- for (i = 0; i < M98088_COEFS_PER_BAND; i++) {
- snd_soc_component_write(component, eq_reg++, M98088_BYTE1(coefs[i]));
- snd_soc_component_write(component, eq_reg++, M98088_BYTE0(coefs[i]));
- }
+ /* Step through the registers and coefs */
+ for (i = 0; i < M98088_COEFS_PER_BAND; i++) {
+ snd_soc_component_write(component, eq_reg++, M98088_BYTE1(coefs[i]));
+ snd_soc_component_write(component, eq_reg++, M98088_BYTE0(coefs[i]));
+ }
}
/*
@@ -1789,7 +1789,7 @@ static struct i2c_driver max98088_i2c_driver = {
.name = "max98088",
.of_match_table = of_match_ptr(max98088_of_match),
},
- .probe_new = max98088_i2c_probe,
+ .probe = max98088_i2c_probe,
.id_table = max98088_i2c_id,
};
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index b419c49e1e08..2adf744c6526 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pm.h>
-#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/acpi.h>
@@ -1582,7 +1581,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
struct snd_soc_component *component = codec_dai->component;
struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
struct max98090_cdata *cdata;
- u8 regval;
+ u8 regval, tdm_regval;
max98090->dai_fmt = fmt;
cdata = &max98090->dai[0];
@@ -1591,6 +1590,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
cdata->fmt = fmt;
regval = 0;
+ tdm_regval = 0;
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBC_CFC:
/* Set to consumer mode PLL - MAS mode off */
@@ -1636,7 +1636,8 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
regval |= M98090_RJ_MASK;
break;
case SND_SOC_DAIFMT_DSP_A:
- /* Not supported mode */
+ tdm_regval |= M98090_TDM_MASK;
+ break;
default:
dev_err(component->dev, "DAI format unsupported");
return -EINVAL;
@@ -1665,11 +1666,20 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
* seen for the case of TDM mode. The remaining cases have
* normal logic.
*/
- if (max98090->tdm_slots > 1)
+ if (tdm_regval)
regval ^= M98090_BCI_MASK;
snd_soc_component_write(component,
M98090_REG_INTERFACE_FORMAT, regval);
+
+ regval = 0;
+ if (tdm_regval)
+ regval = max98090->tdm_lslot << M98090_TDM_SLOTL_SHIFT |
+ max98090->tdm_rslot << M98090_TDM_SLOTR_SHIFT |
+ 0 << M98090_TDM_SLOTDLY_SHIFT;
+
+ snd_soc_component_write(component, M98090_REG_TDM_FORMAT, regval);
+ snd_soc_component_write(component, M98090_REG_TDM_CONTROL, tdm_regval);
}
return 0;
@@ -1680,33 +1690,22 @@ static int max98090_set_tdm_slot(struct snd_soc_dai *codec_dai,
{
struct snd_soc_component *component = codec_dai->component;
struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
- struct max98090_cdata *cdata;
- cdata = &max98090->dai[0];
if (slots < 0 || slots > 4)
return -EINVAL;
- max98090->tdm_slots = slots;
- max98090->tdm_width = slot_width;
-
- if (max98090->tdm_slots > 1) {
- /* SLOTL SLOTR SLOTDLY */
- snd_soc_component_write(component, M98090_REG_TDM_FORMAT,
- 0 << M98090_TDM_SLOTL_SHIFT |
- 1 << M98090_TDM_SLOTR_SHIFT |
- 0 << M98090_TDM_SLOTDLY_SHIFT);
-
- /* FSW TDM */
- snd_soc_component_update_bits(component, M98090_REG_TDM_CONTROL,
- M98090_TDM_MASK,
- M98090_TDM_MASK);
- }
+ if (slot_width != 16)
+ return -EINVAL;
- /*
- * Normally advisable to set TDM first, but this permits either order
- */
- cdata->fmt = 0;
- max98090_dai_set_fmt(codec_dai, max98090->dai_fmt);
+ if (rx_mask != tx_mask)
+ return -EINVAL;
+
+ if (!rx_mask)
+ return -EINVAL;
+
+ max98090->tdm_slots = slots;
+ max98090->tdm_lslot = ffs(rx_mask) - 1;
+ max98090->tdm_rslot = fls(rx_mask) - 1;
return 0;
}
@@ -2409,6 +2408,9 @@ static int max98090_probe(struct snd_soc_component *component)
max98090->pa1en = 0;
max98090->pa2en = 0;
+ max98090->tdm_lslot = 0;
+ max98090->tdm_rslot = 1;
+
ret = snd_soc_component_read(component, M98090_REG_REVISION_ID);
if (ret < 0) {
dev_err(component->dev, "Failed to read device revision: %d\n",
@@ -2691,7 +2693,7 @@ static struct i2c_driver max98090_i2c_driver = {
.of_match_table = of_match_ptr(max98090_of_match),
.acpi_match_table = ACPI_PTR(max98090_acpi_match),
},
- .probe_new = max98090_i2c_probe,
+ .probe = max98090_i2c_probe,
.shutdown = max98090_i2c_shutdown,
.remove = max98090_i2c_remove,
.id_table = max98090_i2c_id,
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h
index a197114b0dad..6ce8dd176e48 100644
--- a/sound/soc/codecs/max98090.h
+++ b/sound/soc/codecs/max98090.h
@@ -1533,7 +1533,8 @@ struct max98090_priv {
struct snd_soc_jack *jack;
unsigned int dai_fmt;
int tdm_slots;
- int tdm_width;
+ int tdm_lslot;
+ int tdm_rslot;
u8 lin_state;
unsigned int pa1en;
unsigned int pa2en;
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 44aa58fcc23f..7e525d49328d 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -2155,7 +2155,7 @@ static struct i2c_driver max98095_i2c_driver = {
.name = "max98095",
.of_match_table = of_match_ptr(max98095_of_match),
},
- .probe_new = max98095_i2c_probe,
+ .probe = max98095_i2c_probe,
.id_table = max98095_i2c_id,
};
diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c
index e6b84e222b50..b5c69bba0e48 100644
--- a/sound/soc/codecs/max98363.c
+++ b/sound/soc/codecs/max98363.c
@@ -15,11 +15,6 @@
#include "max98363.h"
static struct reg_default max98363_reg[] = {
- {MAX98363_R2001_INTR_RAW, 0x0},
- {MAX98363_R2003_INTR_STATE, 0x0},
- {MAX98363_R2005_INTR_FALG, 0x0},
- {MAX98363_R2007_INTR_EN, 0x0},
- {MAX98363_R2009_INTR_CLR, 0x0},
{MAX98363_R2021_ERR_MON_CTRL, 0x0},
{MAX98363_R2022_SPK_MON_THRESH, 0x0},
{MAX98363_R2023_SPK_MON_DURATION, 0x0},
@@ -28,7 +23,6 @@ static struct reg_default max98363_reg[] = {
{MAX98363_R2040_AMP_VOL, 0x0},
{MAX98363_R2041_AMP_GAIN, 0x5},
{MAX98363_R2042_DSP_CFG, 0x0},
- {MAX98363_R21FF_REV_ID, 0x0},
};
static bool max98363_readable_register(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c
index bac9d1bcf60a..f0e49179c38f 100644
--- a/sound/soc/codecs/max98371.c
+++ b/sound/soc/codecs/max98371.c
@@ -419,7 +419,7 @@ static struct i2c_driver max98371_i2c_driver = {
.name = "max98371",
.of_match_table = of_match_ptr(max98371_of_match),
},
- .probe_new = max98371_i2c_probe,
+ .probe = max98371_i2c_probe,
.id_table = max98371_i2c_id,
};
diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c
index ec0905df65d1..0fa5ceca62a2 100644
--- a/sound/soc/codecs/max98373-i2c.c
+++ b/sound/soc/codecs/max98373-i2c.c
@@ -9,7 +9,7 @@
#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
-#include <linux/pm_runtime.h>
+#include <linux/pm.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/cdev.h>
@@ -624,7 +624,7 @@ static struct i2c_driver max98373_i2c_driver = {
.acpi_match_table = ACPI_PTR(max98373_acpi_match),
.pm = &max98373_pm,
},
- .probe_new = max98373_i2c_probe,
+ .probe = max98373_i2c_probe,
.id_table = max98373_i2c_id,
};
diff --git a/sound/soc/codecs/max98388.c b/sound/soc/codecs/max98388.c
new file mode 100644
index 000000000000..cde5e85946cb
--- /dev/null
+++ b/sound/soc/codecs/max98388.c
@@ -0,0 +1,1013 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2022, Analog Devices Inc.
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "max98388.h"
+
+static struct reg_default max98388_reg[] = {
+ {MAX98388_R2000_SW_RESET, 0x00},
+ {MAX98388_R2001_INT_RAW1, 0x00},
+ {MAX98388_R2002_INT_RAW2, 0x00},
+ {MAX98388_R2004_INT_STATE1, 0x00},
+ {MAX98388_R2005_INT_STATE2, 0x00},
+ {MAX98388_R2020_THERM_WARN_THRESH, 0x0A},
+ {MAX98388_R2031_SPK_MON_THRESH, 0x58},
+ {MAX98388_R2032_SPK_MON_LD_SEL, 0x08},
+ {MAX98388_R2033_SPK_MON_DURATION, 0x02},
+ {MAX98388_R2037_ERR_MON_CTRL, 0x01},
+ {MAX98388_R2040_PCM_MODE_CFG, 0xC0},
+ {MAX98388_R2041_PCM_CLK_SETUP, 0x04},
+ {MAX98388_R2042_PCM_SR_SETUP, 0x88},
+ {MAX98388_R2044_PCM_TX_CTRL1, 0x00},
+ {MAX98388_R2045_PCM_TX_CTRL2, 0x00},
+ {MAX98388_R2050_PCM_TX_HIZ_CTRL1, 0xFF},
+ {MAX98388_R2051_PCM_TX_HIZ_CTRL2, 0xFF},
+ {MAX98388_R2052_PCM_TX_HIZ_CTRL3, 0xFF},
+ {MAX98388_R2053_PCM_TX_HIZ_CTRL4, 0xFF},
+ {MAX98388_R2054_PCM_TX_HIZ_CTRL5, 0xFF},
+ {MAX98388_R2055_PCM_TX_HIZ_CTRL6, 0xFF},
+ {MAX98388_R2056_PCM_TX_HIZ_CTRL7, 0xFF},
+ {MAX98388_R2057_PCM_TX_HIZ_CTRL8, 0xFF},
+ {MAX98388_R2058_PCM_RX_SRC1, 0x00},
+ {MAX98388_R2059_PCM_RX_SRC2, 0x01},
+ {MAX98388_R205C_PCM_TX_DRIVE_STRENGTH, 0x00},
+ {MAX98388_R205D_PCM_TX_SRC_EN, 0x00},
+ {MAX98388_R205E_PCM_RX_EN, 0x00},
+ {MAX98388_R205F_PCM_TX_EN, 0x00},
+ {MAX98388_R2090_SPK_CH_VOL_CTRL, 0x00},
+ {MAX98388_R2091_SPK_CH_CFG, 0x02},
+ {MAX98388_R2092_SPK_AMP_OUT_CFG, 0x03},
+ {MAX98388_R2093_SPK_AMP_SSM_CFG, 0x01},
+ {MAX98388_R2094_SPK_AMP_ER_CTRL, 0x00},
+ {MAX98388_R209E_SPK_CH_PINK_NOISE_EN, 0x00},
+ {MAX98388_R209F_SPK_CH_AMP_EN, 0x00},
+ {MAX98388_R20A0_IV_DATA_DSP_CTRL, 0x10},
+ {MAX98388_R20A7_IV_DATA_EN, 0x00},
+ {MAX98388_R20E0_BP_ALC_THRESH, 0x04},
+ {MAX98388_R20E1_BP_ALC_RATES, 0x20},
+ {MAX98388_R20E2_BP_ALC_ATTEN, 0x06},
+ {MAX98388_R20E3_BP_ALC_REL, 0x02},
+ {MAX98388_R20E4_BP_ALC_MUTE, 0x33},
+ {MAX98388_R20EE_BP_INF_HOLD_REL, 0x00},
+ {MAX98388_R20EF_BP_ALC_EN, 0x00},
+ {MAX98388_R210E_AUTO_RESTART, 0x00},
+ {MAX98388_R210F_GLOBAL_EN, 0x00},
+ {MAX98388_R22FF_REV_ID, 0x00},
+};
+
+static int max98388_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(max98388->regmap,
+ MAX98388_R210F_GLOBAL_EN, 1);
+ usleep_range(30000, 31000);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(max98388->regmap,
+ MAX98388_R210F_GLOBAL_EN, 0);
+ usleep_range(30000, 31000);
+ max98388->tdm_mode = false;
+ break;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+static const char * const max98388_monomix_switch_text[] = {
+ "Left", "Right", "LeftRight"};
+
+static const struct soc_enum dai_sel_enum =
+ SOC_ENUM_SINGLE(MAX98388_R2058_PCM_RX_SRC1,
+ MAX98388_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
+ 3, max98388_monomix_switch_text);
+
+static const struct snd_kcontrol_new max98388_dai_controls =
+ SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
+
+static const struct snd_kcontrol_new max98388_vi_control =
+ SOC_DAPM_SINGLE("Switch", MAX98388_R205F_PCM_TX_EN, 0, 1, 0);
+
+static const struct snd_soc_dapm_widget max98388_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback",
+ MAX98388_R205E_PCM_RX_EN, 0, 0, max98388_dac_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
+ &max98388_dai_controls),
+ SND_SOC_DAPM_OUTPUT("BE_OUT"),
+ SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0,
+ MAX98388_R20A7_IV_DATA_EN, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0,
+ MAX98388_R20A7_IV_DATA_EN, 1, 0),
+ SND_SOC_DAPM_ADC("ADC Voltage", NULL,
+ MAX98388_R205D_PCM_TX_SRC_EN, 0, 0),
+ SND_SOC_DAPM_ADC("ADC Current", NULL,
+ MAX98388_R205D_PCM_TX_SRC_EN, 1, 0),
+ SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0,
+ &max98388_vi_control),
+ SND_SOC_DAPM_SIGGEN("VMON"),
+ SND_SOC_DAPM_SIGGEN("IMON"),
+};
+
+static DECLARE_TLV_DB_SCALE(max98388_digital_tlv, -6350, 50, 1);
+static DECLARE_TLV_DB_SCALE(max98388_amp_gain_tlv, -300, 300, 0);
+
+static const char * const max98388_alc_max_atten_text[] = {
+ "0dBFS", "-1dBFS", "-2dBFS", "-3dBFS", "-4dBFS", "-5dBFS",
+ "-6dBFS", "-7dBFS", "-8dBFS", "-9dBFS", "-10dBFS", "-11dBFS",
+ "-12dBFS", "-13dBFS", "-14dBFS", "-15dBFS"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98388_alc_max_atten_enum,
+ MAX98388_R20E2_BP_ALC_ATTEN,
+ MAX98388_ALC_MAX_ATTEN_SHIFT,
+ max98388_alc_max_atten_text);
+
+static const char * const max98388_thermal_warn_text[] = {
+ "95C", "105C", "115C", "125C"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98388_thermal_warning_thresh_enum,
+ MAX98388_R2020_THERM_WARN_THRESH,
+ MAX98388_THERM_WARN_THRESH_SHIFT,
+ max98388_thermal_warn_text);
+
+static const char * const max98388_thermal_shutdown_text[] = {
+ "135C", "145C", "155C", "165C"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98388_thermal_shutdown_thresh_enum,
+ MAX98388_R2020_THERM_WARN_THRESH,
+ MAX98388_THERM_SHDN_THRESH_SHIFT,
+ max98388_thermal_shutdown_text);
+
+static const char * const max98388_alc_thresh_single_text[] = {
+ "3.625V", "3.550V", "3.475V", "3.400V", "3.325V", "3.250V",
+ "3.175V", "3.100V", "3.025V", "2.950V", "2.875V", "2.800V",
+ "2.725V", "2.650V", "2.575V", "2.500V"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98388_alc_thresh_single_enum,
+ MAX98388_R20E0_BP_ALC_THRESH,
+ MAX98388_ALC_THRESH_SHIFT,
+ max98388_alc_thresh_single_text);
+
+static const char * const max98388_alc_attack_rate_text[] = {
+ "0", "10us", "20us", "40us", "80us", "160us",
+ "320us", "640us", "1.28ms", "2.56ms", "5.12ms", "10.24ms",
+ "20.48ms", "40.96ms", "81.92ms", "163.84ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98388_alc_attack_rate_enum,
+ MAX98388_R20E1_BP_ALC_RATES,
+ MAX98388_ALC_ATTACK_RATE_SHIFT,
+ max98388_alc_attack_rate_text);
+
+static const char * const max98388_alc_release_rate_text[] = {
+ "20us", "40us", "80us", "160us", "320us", "640us",
+ "1.28ms", "2.56ms", "5.12ms", "10.24ms", "20.48ms", "40.96ms",
+ "81.92ms", "163.84ms", "327.68ms", "655.36ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98388_alc_release_rate_enum,
+ MAX98388_R20E1_BP_ALC_RATES,
+ MAX98388_ALC_RELEASE_RATE_SHIFT,
+ max98388_alc_release_rate_text);
+
+static const char * const max98388_alc_debounce_text[] = {
+ "0.01ms", "0.1ms", "1ms", "10ms", "100ms", "250ms", "500ms", "hold"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98388_alc_debouce_enum,
+ MAX98388_R20E3_BP_ALC_REL,
+ MAX98388_ALC_DEBOUNCE_TIME_SHIFT,
+ max98388_alc_debounce_text);
+
+static const char * const max98388_alc_mute_delay_text[] = {
+ "0.01ms", "0.05ms", "0.1ms", "0.5ms", "1ms", "5ms", "25ms", "250ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98388_alc_mute_delay_enum,
+ MAX98388_R20E4_BP_ALC_MUTE,
+ MAX98388_ALC_MUTE_DELAY_SHIFT,
+ max98388_alc_mute_delay_text);
+
+static const char * const max98388_spkmon_duration_text[] = {
+ "10ms", "25ms", "50ms", "75ms", "100ms", "200ms", "300ms", "400ms",
+ "500ms", "600ms", "700ms", "800ms", "900ms", "1000ms", "1100ms", "1200ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98388_spkmon_duration_enum,
+ MAX98388_R2033_SPK_MON_DURATION,
+ MAX98388_SPKMON_DURATION_SHIFT,
+ max98388_spkmon_duration_text);
+
+static const char * const max98388_spkmon_thresh_text[] = {
+ "0.03V", "0.06V", "0.09V", "0.12V", "0.15V", "0.18V", "0.20V", "0.23V",
+ "0.26V", "0.29V", "0.32V", "0.35V", "0.38V", "0.41V", "0.44V", "0.47V",
+ "0.50V", "0.53V", "0.56V", "0.58V", "0.61V", "0.64V", "0.67V", "0.70V",
+ "0.73V", "0.76V", "0.79V", "0.82V", "0.85V", "0.88V", "0.91V", "0.94V",
+ "0.96V", "0.99V", "1.02V", "1.05V", "1.08V", "1.11V", "1.14V", "1.17V",
+ "1.20V", "1.23V", "1.26V", "1.29V", "1.32V", "1.35V", "1.37V", "1.40V",
+ "1.43V", "1.46V", "1.49V", "1.52V", "1.55V", "1.58V", "1.61V", "1.64V",
+ "1.67V", "1.70V", "1.73V", "1.75V", "1.78V", "1.81V", "1.84V", "1.87V",
+ "1.90V", "1.93V", "1.96V", "1.99V", "2.02V", "2.05V", "2.08V", "2.11V",
+ "2.13V", "2.16V", "2.19V", "2.22V", "2.25V", "2.28V", "2.31V", "2.34V",
+ "2.37V", "2.40V", "2.43V", "2.46V", "2.49V", "2.51V", "2.54V", "2.57V",
+ "2.60V", "2.63V", "2.66V", "2.69V", "2.72V", "2.75V", "2.78V", "2.81V",
+ "2.84V", "2.87V", "2.89V", "2.92V", "2.95V", "2.98V", "3.01V", "3.04V",
+ "3.07V", "3.10V", "3.13V", "3.16V", "3.19V", "3.22V", "3.25V", "3.27V",
+ "3.30V", "3.33V", "3.36V", "3.39V", "3.42V", "3.45V", "3.48V", "3.51V",
+ "3.54V", "3.57V", "3.60V", "3.63V", "3.66V", "3.68V", "3.71V", "3.74V"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98388_spkmon_thresh_enum,
+ MAX98388_R2031_SPK_MON_THRESH,
+ MAX98388_SPKMON_THRESH_SHIFT,
+ max98388_spkmon_thresh_text);
+
+static const char * const max98388_spkmon_load_text[] = {
+ "2.00ohm", "2.25ohm", "2.50ohm", "2.75ohm", "3.00ohm", "3.25ohm",
+ "3.50ohm", "3.75ohm", "4.00ohm", "4.25ohm", "4.50ohm", "4.75ohm",
+ "5.00ohm", "5.25ohm", "5.50ohm", "5.75ohm", "6.00ohm", "6.25ohm",
+ "6.50ohm", "6.75ohm", "7.00ohm", "7.25ohm", "7.50ohm", "7.75ohm",
+ "8.00ohm", "8.25ohm", "8.50ohm", "8.75ohm", "9.00ohm", "9.25ohm",
+ "9.50ohm", "9.75ohm", "10.00ohm", "10.25ohm", "10.50ohm", "10.75ohm",
+ "11.00ohm", "11.25ohm", "11.50ohm", "11.75ohm", "12.00ohm", "12.25ohm",
+ "12.50ohm", "12.75ohm", "13.00ohm", "13.25ohm", "13.50ohm", "13.75ohm",
+ "14.00ohm", "14.25ohm", "14.50ohm", "14.75ohm", "15.00ohm", "15.25ohm",
+ "15.50ohm", "15.75ohm", "16.00ohm", "16.25ohm", "16.50ohm", "16.75ohm",
+ "17.00ohm", "17.25ohm", "17.50ohm", "17.75ohm", "18.00ohm", "18.25ohm",
+ "18.50ohm", "18.75ohm", "19.00ohm", "19.25ohm", "19.50ohm", "19.75ohm",
+ "20.00ohm", "20.25ohm", "20.50ohm", "20.75ohm", "21.00ohm", "21.25ohm",
+ "21.50ohm", "21.75ohm", "22.00ohm", "22.25ohm", "22.50ohm", "22.75ohm",
+ "23.00ohm", "23.25ohm", "23.50ohm", "23.75ohm", "24.00ohm", "24.25ohm",
+ "24.50ohm", "24.75ohm", "25.00ohm", "25.25ohm", "25.50ohm", "25.75ohm",
+ "26.00ohm", "26.25ohm", "26.50ohm", "26.75ohm", "27.00ohm", "27.25ohm",
+ "27.50ohm", "27.75ohm", "28.00ohm", "28.25ohm", "28.50ohm", "28.75ohm",
+ "29.00ohm", "29.25ohm", "29.50ohm", "29.75ohm", "30.00ohm", "30.25ohm",
+ "30.50ohm", "30.75ohm", "31.00ohm", "31.25ohm", "31.50ohm", "31.75ohm",
+ "32.00ohm", "32.25ohm", "32.50ohm", "32.75ohm", "33.00ohm", "33.25ohm",
+ "33.50ohm", "33.75ohm"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98388_spkmon_load_enum,
+ MAX98388_R2032_SPK_MON_LD_SEL,
+ MAX98388_SPKMON_LOAD_SHIFT,
+ max98388_spkmon_load_text);
+
+static const char * const max98388_edge_rate_text[] = {
+ "Normal", "Reduced", "Maximum", "Increased",
+};
+
+static SOC_ENUM_SINGLE_DECL(max98388_edge_rate_falling_enum,
+ MAX98388_R2094_SPK_AMP_ER_CTRL,
+ MAX98388_EDGE_RATE_FALL_SHIFT,
+ max98388_edge_rate_text);
+
+static SOC_ENUM_SINGLE_DECL(max98388_edge_rate_rising_enum,
+ MAX98388_R2094_SPK_AMP_ER_CTRL,
+ MAX98388_EDGE_RATE_RISE_SHIFT,
+ max98388_edge_rate_text);
+
+static const char * const max98388_ssm_mod_text[] = {
+ "1.5%", "3.0%", "4.5%", "6.0%",
+};
+
+static SOC_ENUM_SINGLE_DECL(max98388_ssm_mod_enum,
+ MAX98388_R2093_SPK_AMP_SSM_CFG,
+ MAX98388_SPK_AMP_SSM_MOD_SHIFT,
+ max98388_ssm_mod_text);
+
+static const struct snd_kcontrol_new max98388_snd_controls[] = {
+ SOC_SINGLE("Ramp Up Switch", MAX98388_R2091_SPK_CH_CFG,
+ MAX98388_SPK_CFG_VOL_RMPUP_SHIFT, 1, 0),
+ SOC_SINGLE("Ramp Down Switch", MAX98388_R2091_SPK_CH_CFG,
+ MAX98388_SPK_CFG_VOL_RMPDN_SHIFT, 1, 0),
+ /* Two Cell Mode Enable */
+ SOC_SINGLE("OP Mode Switch", MAX98388_R2092_SPK_AMP_OUT_CFG,
+ MAX98388_SPK_AMP_OUT_MODE_SHIFT, 1, 0),
+ /* Speaker Amplifier Overcurrent Automatic Restart Enable */
+ SOC_SINGLE("OVC Autorestart Switch", MAX98388_R210E_AUTO_RESTART,
+ MAX98388_OVC_AUTORESTART_SHIFT, 1, 0),
+ /* Thermal Shutdown Automatic Restart Enable */
+ SOC_SINGLE("THERM Autorestart Switch", MAX98388_R210E_AUTO_RESTART,
+ MAX98388_THERM_AUTORESTART_SHIFT, 1, 0),
+ /* PVDD UVLO Auto Restart */
+ SOC_SINGLE("UVLO Autorestart Switch", MAX98388_R210E_AUTO_RESTART,
+ MAX98388_PVDD_UVLO_AUTORESTART_SHIFT, 1, 0),
+ /* Clock Monitor Automatic Restart Enable */
+ SOC_SINGLE("CMON Autorestart Switch", MAX98388_R210E_AUTO_RESTART,
+ MAX98388_CMON_AUTORESTART_SHIFT, 1, 0),
+ SOC_SINGLE("CLK Monitor Switch", MAX98388_R2037_ERR_MON_CTRL,
+ MAX98388_CLOCK_MON_SHIFT, 1, 0),
+ /* Pinknoise Generator Enable */
+ SOC_SINGLE("Pinknoise Gen Switch", MAX98388_R209E_SPK_CH_PINK_NOISE_EN,
+ MAX98388_PINK_NOISE_GEN_SHIFT, 1, 0),
+ /* Dither Enable */
+ SOC_SINGLE("Dither Switch", MAX98388_R2091_SPK_CH_CFG,
+ MAX98388_SPK_CFG_DITH_EN_SHIFT, 1, 0),
+ SOC_SINGLE("VI Dither Switch", MAX98388_R20A0_IV_DATA_DSP_CTRL,
+ MAX98388_AMP_DSP_CTRL_DITH_SHIFT, 1, 0),
+ /* DC Blocker Enable */
+ SOC_SINGLE("DC Blocker Switch", MAX98388_R2091_SPK_CH_CFG,
+ MAX98388_SPK_CFG_DCBLK_SHIFT, 1, 0),
+ SOC_SINGLE("Voltage DC Blocker Switch", MAX98388_R20A0_IV_DATA_DSP_CTRL,
+ MAX98388_AMP_DSP_CTRL_VOL_DCBLK_SHIFT, 1, 0),
+ SOC_SINGLE("Current DC Blocker Switch", MAX98388_R20A0_IV_DATA_DSP_CTRL,
+ MAX98388_AMP_DSP_CTRL_CUR_DCBLK_SHIFT, 1, 0),
+ /* Digital Volume */
+ SOC_SINGLE_TLV("Digital Volume", MAX98388_R2090_SPK_CH_VOL_CTRL,
+ 0, 0x7F, 1, max98388_digital_tlv),
+ /* Speaker Volume */
+ SOC_SINGLE_TLV("Speaker Volume", MAX98388_R2092_SPK_AMP_OUT_CFG,
+ 0, 5, 0, max98388_amp_gain_tlv),
+ SOC_ENUM("Thermal Warn Thresh", max98388_thermal_warning_thresh_enum),
+ SOC_ENUM("Thermal SHDN Thresh", max98388_thermal_shutdown_thresh_enum),
+ /* Brownout Protection Automatic Level Control */
+ SOC_SINGLE("ALC Switch", MAX98388_R20EF_BP_ALC_EN, 0, 1, 0),
+ SOC_ENUM("ALC Thresh", max98388_alc_thresh_single_enum),
+ SOC_ENUM("ALC Attack Rate", max98388_alc_attack_rate_enum),
+ SOC_ENUM("ALC Release Rate", max98388_alc_release_rate_enum),
+ SOC_ENUM("ALC Max Atten", max98388_alc_max_atten_enum),
+ SOC_ENUM("ALC Debounce Time", max98388_alc_debouce_enum),
+ SOC_SINGLE("ALC Unmute Ramp Switch", MAX98388_R20E4_BP_ALC_MUTE,
+ MAX98388_ALC_UNMUTE_RAMP_EN_SHIFT, 1, 0),
+ SOC_SINGLE("ALC Mute Ramp Switch", MAX98388_R20E4_BP_ALC_MUTE,
+ MAX98388_ALC_MUTE_RAMP_EN_SHIFT, 1, 0),
+ SOC_SINGLE("ALC Mute Switch", MAX98388_R20E4_BP_ALC_MUTE,
+ MAX98388_ALC_MUTE_EN_SHIFT, 1, 0),
+ SOC_ENUM("ALC Mute Delay", max98388_alc_mute_delay_enum),
+ /* Speaker Monitor */
+ SOC_SINGLE("SPKMON Switch", MAX98388_R2037_ERR_MON_CTRL,
+ MAX98388_SPK_MON_SHIFT, 1, 0),
+ SOC_ENUM("SPKMON Thresh", max98388_spkmon_thresh_enum),
+ SOC_ENUM("SPKMON Load", max98388_spkmon_load_enum),
+ SOC_ENUM("SPKMON Duration", max98388_spkmon_duration_enum),
+ /* General Parameters */
+ SOC_ENUM("Fall Slew Rate", max98388_edge_rate_falling_enum),
+ SOC_ENUM("Rise Slew Rate", max98388_edge_rate_rising_enum),
+ SOC_SINGLE("AMP SSM Switch", MAX98388_R2093_SPK_AMP_SSM_CFG,
+ MAX98388_SPK_AMP_SSM_EN_SHIFT, 1, 0),
+ SOC_ENUM("AMP SSM Mod", max98388_ssm_mod_enum),
+};
+
+static const struct snd_soc_dapm_route max98388_audio_map[] = {
+ /* Plabyack */
+ {"DAI Sel Mux", "Left", "Amp Enable"},
+ {"DAI Sel Mux", "Right", "Amp Enable"},
+ {"DAI Sel Mux", "LeftRight", "Amp Enable"},
+ {"BE_OUT", NULL, "DAI Sel Mux"},
+ /* Capture */
+ { "ADC Voltage", NULL, "VMON"},
+ { "ADC Current", NULL, "IMON"},
+ { "VI Sense", "Switch", "ADC Voltage"},
+ { "VI Sense", "Switch", "ADC Current"},
+ { "Voltage Sense", NULL, "VI Sense"},
+ { "Current Sense", NULL, "VI Sense"},
+};
+
+static void max98388_reset(struct max98388_priv *max98388, struct device *dev)
+{
+ int ret, reg, count;
+
+ /* Software Reset */
+ ret = regmap_update_bits(max98388->regmap,
+ MAX98388_R2000_SW_RESET,
+ MAX98388_SOFT_RESET,
+ MAX98388_SOFT_RESET);
+ if (ret)
+ dev_err(dev, "Reset command failed. (ret:%d)\n", ret);
+
+ count = 0;
+ while (count < 3) {
+ usleep_range(10000, 11000);
+ /* Software Reset Verification */
+ ret = regmap_read(max98388->regmap,
+ MAX98388_R22FF_REV_ID, &reg);
+ if (!ret) {
+ dev_info(dev, "Reset completed (retry:%d)\n", count);
+ return;
+ }
+ count++;
+ }
+ dev_err(dev, "Reset failed. (ret:%d)\n", ret);
+}
+
+static int max98388_probe(struct snd_soc_component *component)
+{
+ struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component);
+
+ /* Software Reset */
+ max98388_reset(max98388, component->dev);
+
+ /* General channel source configuration */
+ regmap_write(max98388->regmap,
+ MAX98388_R2059_PCM_RX_SRC2,
+ 0x10);
+
+ /* Enable DC blocker */
+ regmap_write(max98388->regmap,
+ MAX98388_R2091_SPK_CH_CFG,
+ 0x1);
+ /* Enable IMON VMON DC blocker */
+ regmap_write(max98388->regmap,
+ MAX98388_R20A0_IV_DATA_DSP_CTRL,
+ 0x3);
+ /* TX slot configuration */
+ regmap_write(max98388->regmap,
+ MAX98388_R2044_PCM_TX_CTRL1,
+ max98388->v_slot);
+
+ regmap_write(max98388->regmap,
+ MAX98388_R2045_PCM_TX_CTRL2,
+ max98388->i_slot);
+ /* Enable Auto-restart behavior by default */
+ regmap_write(max98388->regmap,
+ MAX98388_R210E_AUTO_RESTART, 0xF);
+ /* Set interleave mode */
+ if (max98388->interleave_mode)
+ regmap_update_bits(max98388->regmap,
+ MAX98388_R2040_PCM_MODE_CFG,
+ MAX98388_PCM_TX_CH_INTERLEAVE_MASK,
+ MAX98388_PCM_TX_CH_INTERLEAVE_MASK);
+
+ /* Speaker Amplifier Channel Enable */
+ regmap_update_bits(max98388->regmap,
+ MAX98388_R209F_SPK_CH_AMP_EN,
+ MAX98388_SPK_EN_MASK, 1);
+
+ return 0;
+}
+
+static int max98388_dai_set_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component);
+ unsigned int format = 0;
+ unsigned int invert = 0;
+
+ dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ invert = MAX98388_PCM_MODE_CFG_PCM_BCLKEDGE;
+ break;
+ default:
+ dev_err(component->dev, "DAI invert mode unsupported\n");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98388->regmap,
+ MAX98388_R2041_PCM_CLK_SETUP,
+ MAX98388_PCM_MODE_CFG_PCM_BCLKEDGE,
+ invert);
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ format = MAX98388_PCM_FORMAT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ format = MAX98388_PCM_FORMAT_LJ;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ format = MAX98388_PCM_FORMAT_TDM_MODE1;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ format = MAX98388_PCM_FORMAT_TDM_MODE0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98388->regmap,
+ MAX98388_R2040_PCM_MODE_CFG,
+ MAX98388_PCM_MODE_CFG_FORMAT_MASK,
+ format << MAX98388_PCM_MODE_CFG_FORMAT_SHIFT);
+
+ return 0;
+}
+
+/* BCLKs per LRCLK */
+static const int bclk_sel_table[] = {
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 320,
+};
+
+static int max98388_get_bclk_sel(int bclk)
+{
+ int i;
+ /* match BCLKs per LRCLK */
+ for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) {
+ if (bclk_sel_table[i] == bclk)
+ return i + 2;
+ }
+ return 0;
+}
+
+static int max98388_set_clock(struct snd_soc_component *component,
+ struct snd_pcm_hw_params *params)
+{
+ struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component);
+ /* BCLK/LRCLK ratio calculation */
+ int blr_clk_ratio = params_channels(params) * max98388->ch_size;
+ int value;
+
+ if (!max98388->tdm_mode) {
+ /* BCLK configuration */
+ value = max98388_get_bclk_sel(blr_clk_ratio);
+ if (!value) {
+ dev_err(component->dev, "format unsupported %d\n",
+ params_format(params));
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98388->regmap,
+ MAX98388_R2041_PCM_CLK_SETUP,
+ MAX98388_PCM_CLK_SETUP_BSEL_MASK,
+ value);
+ }
+ return 0;
+}
+
+static int max98388_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component);
+ unsigned int sampling_rate = 0;
+ unsigned int chan_sz = 0;
+ int ret, reg;
+ int status = 0;
+
+ /* pcm mode configuration */
+ switch (snd_pcm_format_width(params_format(params))) {
+ case 16:
+ chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_16;
+ break;
+ case 24:
+ chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_24;
+ break;
+ case 32:
+ chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_32;
+ break;
+ default:
+ dev_err(component->dev, "format unsupported %d\n",
+ params_format(params));
+ goto err;
+ }
+
+ max98388->ch_size = snd_pcm_format_width(params_format(params));
+
+ ret = regmap_read(max98388->regmap,
+ MAX98388_R2040_PCM_MODE_CFG, &reg);
+ if (ret < 0)
+ goto err;
+
+ /* GLOBAL_EN OFF prior to the channel size re-configure */
+ if (chan_sz != (reg & MAX98388_PCM_MODE_CFG_CHANSZ_MASK)) {
+ ret = regmap_read(max98388->regmap,
+ MAX98388_R210F_GLOBAL_EN, &status);
+ if (ret < 0)
+ goto err;
+
+ if (status) {
+ regmap_write(max98388->regmap,
+ MAX98388_R210F_GLOBAL_EN, 0);
+ usleep_range(30000, 31000);
+ }
+ regmap_update_bits(max98388->regmap,
+ MAX98388_R2040_PCM_MODE_CFG,
+ MAX98388_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+ }
+ dev_dbg(component->dev, "format supported %d",
+ params_format(params));
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 8000:
+ sampling_rate = MAX98388_PCM_SR_8000;
+ break;
+ case 11025:
+ sampling_rate = MAX98388_PCM_SR_11025;
+ break;
+ case 12000:
+ sampling_rate = MAX98388_PCM_SR_12000;
+ break;
+ case 16000:
+ sampling_rate = MAX98388_PCM_SR_16000;
+ break;
+ case 22050:
+ sampling_rate = MAX98388_PCM_SR_22050;
+ break;
+ case 24000:
+ sampling_rate = MAX98388_PCM_SR_24000;
+ break;
+ case 32000:
+ sampling_rate = MAX98388_PCM_SR_32000;
+ break;
+ case 44100:
+ sampling_rate = MAX98388_PCM_SR_44100;
+ break;
+ case 48000:
+ sampling_rate = MAX98388_PCM_SR_48000;
+ break;
+ case 88200:
+ sampling_rate = MAX98388_PCM_SR_88200;
+ break;
+ case 96000:
+ sampling_rate = MAX98388_PCM_SR_96000;
+ break;
+ default:
+ dev_err(component->dev, "rate %d not supported\n",
+ params_rate(params));
+ goto err;
+ }
+
+ /* set DAI_SR to correct LRCLK frequency */
+ regmap_update_bits(max98388->regmap,
+ MAX98388_R2042_PCM_SR_SETUP,
+ MAX98388_PCM_SR_MASK,
+ sampling_rate);
+
+ /* set sampling rate of IV */
+ if (max98388->interleave_mode &&
+ sampling_rate > MAX98388_PCM_SR_16000)
+ regmap_update_bits(max98388->regmap,
+ MAX98388_R2042_PCM_SR_SETUP,
+ MAX98388_PCM_SR_IV_MASK,
+ (sampling_rate - 3) << MAX98388_PCM_SR_IV_SHIFT);
+ else
+ regmap_update_bits(max98388->regmap,
+ MAX98388_R2042_PCM_SR_SETUP,
+ MAX98388_PCM_SR_IV_MASK,
+ sampling_rate << MAX98388_PCM_SR_IV_SHIFT);
+
+ ret = max98388_set_clock(component, params);
+
+ if (status) {
+ regmap_write(max98388->regmap,
+ MAX98388_R210F_GLOBAL_EN, 1);
+ usleep_range(30000, 31000);
+ }
+
+ return ret;
+
+err:
+ return -EINVAL;
+}
+
+#define MAX_NUM_SLOTS 16
+#define MAX_NUM_CH 2
+
+static int max98388_dai_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ struct snd_soc_component *component = dai->component;
+ struct max98388_priv *max98388 = snd_soc_component_get_drvdata(component);
+ int bsel = 0;
+ unsigned int chan_sz = 0;
+ unsigned int mask;
+ int cnt, slot_found;
+ int addr, bits;
+
+ if (!tx_mask && !rx_mask && !slots && !slot_width)
+ max98388->tdm_mode = false;
+ else
+ max98388->tdm_mode = true;
+
+ /* BCLK configuration */
+ bsel = max98388_get_bclk_sel(slots * slot_width);
+ if (bsel == 0) {
+ dev_err(component->dev, "BCLK %d not supported\n",
+ slots * slot_width);
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98388->regmap,
+ MAX98388_R2041_PCM_CLK_SETUP,
+ MAX98388_PCM_CLK_SETUP_BSEL_MASK,
+ bsel);
+
+ /* Channel size configuration */
+ switch (slot_width) {
+ case 16:
+ chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_16;
+ break;
+ case 24:
+ chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_24;
+ break;
+ case 32:
+ chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_32;
+ break;
+ default:
+ dev_err(component->dev, "format unsupported %d\n",
+ slot_width);
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98388->regmap,
+ MAX98388_R2040_PCM_MODE_CFG,
+ MAX98388_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+
+ /* Rx slot configuration */
+ slot_found = 0;
+ mask = rx_mask;
+ for (cnt = 0 ; cnt < MAX_NUM_SLOTS ; cnt++, mask >>= 1) {
+ if (mask & 0x1) {
+ if (slot_found == 0)
+ regmap_update_bits(max98388->regmap,
+ MAX98388_R2059_PCM_RX_SRC2,
+ MAX98388_RX_SRC_CH0_SHIFT,
+ cnt);
+ else
+ regmap_update_bits(max98388->regmap,
+ MAX98388_R2059_PCM_RX_SRC2,
+ MAX98388_RX_SRC_CH1_SHIFT,
+ cnt);
+ slot_found++;
+ if (slot_found >= MAX_NUM_CH)
+ break;
+ }
+ }
+
+ /* speaker feedback slot configuration */
+ slot_found = 0;
+ mask = tx_mask;
+ for (cnt = 0 ; cnt < MAX_NUM_SLOTS ; cnt++, mask >>= 1) {
+ if (mask & 0x1) {
+ addr = MAX98388_R2044_PCM_TX_CTRL1 + (cnt / 8);
+ bits = cnt % 8;
+ regmap_update_bits(max98388->regmap, addr, bits, bits);
+ if (slot_found >= MAX_NUM_CH)
+ break;
+ }
+ }
+
+ return 0;
+}
+
+#define MAX98388_RATES SNDRV_PCM_RATE_8000_96000
+
+#define MAX98388_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops max98388_dai_ops = {
+ .set_fmt = max98388_dai_set_fmt,
+ .hw_params = max98388_dai_hw_params,
+ .set_tdm_slot = max98388_dai_tdm_slot,
+};
+
+static bool max98388_readable_register(struct device *dev,
+ unsigned int reg)
+{
+ switch (reg) {
+ case MAX98388_R2001_INT_RAW1 ... MAX98388_R2002_INT_RAW2:
+ case MAX98388_R2004_INT_STATE1... MAX98388_R2005_INT_STATE2:
+ case MAX98388_R2020_THERM_WARN_THRESH:
+ case MAX98388_R2031_SPK_MON_THRESH
+ ... MAX98388_R2033_SPK_MON_DURATION:
+ case MAX98388_R2037_ERR_MON_CTRL:
+ case MAX98388_R2040_PCM_MODE_CFG
+ ... MAX98388_R2042_PCM_SR_SETUP:
+ case MAX98388_R2044_PCM_TX_CTRL1
+ ... MAX98388_R2045_PCM_TX_CTRL2:
+ case MAX98388_R2050_PCM_TX_HIZ_CTRL1
+ ... MAX98388_R2059_PCM_RX_SRC2:
+ case MAX98388_R205C_PCM_TX_DRIVE_STRENGTH
+ ... MAX98388_R205F_PCM_TX_EN:
+ case MAX98388_R2090_SPK_CH_VOL_CTRL
+ ... MAX98388_R2094_SPK_AMP_ER_CTRL:
+ case MAX98388_R209E_SPK_CH_PINK_NOISE_EN
+ ... MAX98388_R209F_SPK_CH_AMP_EN:
+ case MAX98388_R20A0_IV_DATA_DSP_CTRL:
+ case MAX98388_R20A7_IV_DATA_EN:
+ case MAX98388_R20E0_BP_ALC_THRESH ... MAX98388_R20E4_BP_ALC_MUTE:
+ case MAX98388_R20EE_BP_INF_HOLD_REL ... MAX98388_R20EF_BP_ALC_EN:
+ case MAX98388_R210E_AUTO_RESTART:
+ case MAX98388_R210F_GLOBAL_EN:
+ case MAX98388_R22FF_REV_ID:
+ return true;
+ default:
+ return false;
+ }
+};
+
+static bool max98388_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX98388_R2001_INT_RAW1 ... MAX98388_R2005_INT_STATE2:
+ case MAX98388_R210F_GLOBAL_EN:
+ case MAX98388_R22FF_REV_ID:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static struct snd_soc_dai_driver max98388_dai[] = {
+ {
+ .name = "max98388-aif1",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98388_RATES,
+ .formats = MAX98388_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98388_RATES,
+ .formats = MAX98388_FORMATS,
+ },
+ .ops = &max98388_dai_ops,
+ }
+};
+
+static int max98388_suspend(struct device *dev)
+{
+ struct max98388_priv *max98388 = dev_get_drvdata(dev);
+
+ regcache_cache_only(max98388->regmap, true);
+ regcache_mark_dirty(max98388->regmap);
+
+ return 0;
+}
+
+static int max98388_resume(struct device *dev)
+{
+ struct max98388_priv *max98388 = dev_get_drvdata(dev);
+
+ regcache_cache_only(max98388->regmap, false);
+ max98388_reset(max98388, dev);
+ regcache_sync(max98388->regmap);
+
+ return 0;
+}
+
+static const struct dev_pm_ops max98388_pm = {
+ SYSTEM_SLEEP_PM_OPS(max98388_suspend, max98388_resume)
+};
+
+static const struct regmap_config max98388_regmap = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = MAX98388_R22FF_REV_ID,
+ .reg_defaults = max98388_reg,
+ .num_reg_defaults = ARRAY_SIZE(max98388_reg),
+ .readable_reg = max98388_readable_register,
+ .volatile_reg = max98388_volatile_reg,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static const struct snd_soc_component_driver soc_codec_dev_max98388 = {
+ .probe = max98388_probe,
+ .controls = max98388_snd_controls,
+ .num_controls = ARRAY_SIZE(max98388_snd_controls),
+ .dapm_widgets = max98388_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(max98388_dapm_widgets),
+ .dapm_routes = max98388_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(max98388_audio_map),
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static void max98388_read_deveice_property(struct device *dev,
+ struct max98388_priv *max98388)
+{
+ int value;
+
+ if (!device_property_read_u32(dev, "adi,vmon-slot-no", &value))
+ max98388->v_slot = value & 0xF;
+ else
+ max98388->v_slot = 0;
+
+ if (!device_property_read_u32(dev, "adi,imon-slot-no", &value))
+ max98388->i_slot = value & 0xF;
+ else
+ max98388->i_slot = 1;
+
+ if (device_property_read_bool(dev, "adi,interleave-mode"))
+ max98388->interleave_mode = true;
+ else
+ max98388->interleave_mode = false;
+}
+
+static int max98388_i2c_probe(struct i2c_client *i2c)
+{
+ int ret = 0;
+ int reg = 0;
+
+ struct max98388_priv *max98388 = NULL;
+
+ max98388 = devm_kzalloc(&i2c->dev, sizeof(*max98388), GFP_KERNEL);
+ if (!max98388)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, max98388);
+
+ /* regmap initialization */
+ max98388->regmap = devm_regmap_init_i2c(i2c, &max98388_regmap);
+ if (IS_ERR(max98388->regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(max98388->regmap),
+ "Failed to allocate register map.\n");
+
+ /* voltage/current slot & gpio configuration */
+ max98388_read_deveice_property(&i2c->dev, max98388);
+
+ /* Device Reset */
+ max98388->reset_gpio = devm_gpiod_get_optional(&i2c->dev,
+ "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(max98388->reset_gpio))
+ return dev_err_probe(&i2c->dev, PTR_ERR(max98388->reset_gpio),
+ "Unable to request GPIO\n");
+
+ if (max98388->reset_gpio) {
+ usleep_range(5000, 6000);
+ gpiod_set_value_cansleep(max98388->reset_gpio, 0);
+ /* Wait for the hw reset done */
+ usleep_range(5000, 6000);
+ }
+
+ /* Read Revision ID */
+ ret = regmap_read(max98388->regmap,
+ MAX98388_R22FF_REV_ID, &reg);
+ if (ret < 0)
+ return dev_err_probe(&i2c->dev, ret,
+ "Failed to read the revision ID\n");
+
+ dev_info(&i2c->dev, "MAX98388 revisionID: 0x%02X\n", reg);
+
+ /* codec registration */
+ ret = devm_snd_soc_register_component(&i2c->dev,
+ &soc_codec_dev_max98388,
+ max98388_dai,
+ ARRAY_SIZE(max98388_dai));
+ if (ret < 0)
+ dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+
+ return ret;
+}
+
+static const struct i2c_device_id max98388_i2c_id[] = {
+ { "max98388", 0},
+ { },
+};
+
+MODULE_DEVICE_TABLE(i2c, max98388_i2c_id);
+
+static const struct of_device_id max98388_of_match[] = {
+ { .compatible = "adi,max98388", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max98388_of_match);
+
+static const struct acpi_device_id max98388_acpi_match[] = {
+ { "ADS8388", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, max98388_acpi_match);
+
+static struct i2c_driver max98388_i2c_driver = {
+ .driver = {
+ .name = "max98388",
+ .of_match_table = max98388_of_match,
+ .acpi_match_table = max98388_acpi_match,
+ .pm = pm_sleep_ptr(&max98388_pm),
+ },
+ .probe = max98388_i2c_probe,
+ .id_table = max98388_i2c_id,
+};
+
+module_i2c_driver(max98388_i2c_driver)
+
+MODULE_DESCRIPTION("ALSA SoC MAX98388 driver");
+MODULE_AUTHOR("Ryan Lee <ryans.lee@analog.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98388.h b/sound/soc/codecs/max98388.h
new file mode 100644
index 000000000000..77833d181913
--- /dev/null
+++ b/sound/soc/codecs/max98388.h
@@ -0,0 +1,234 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * max98388.h -- MAX98388 ALSA SoC audio driver header
+ *
+ * Copyright(c) 2022, Analog Devices Inc.
+ */
+
+#ifndef _MAX98388_H
+#define _MAX98388_H
+
+/* Device Status Registers */
+#define MAX98388_R2000_SW_RESET 0x2000
+#define MAX98388_R2001_INT_RAW1 0x2001
+#define MAX98388_R2002_INT_RAW2 0x2002
+#define MAX98388_R2004_INT_STATE1 0x2004
+#define MAX98388_R2005_INT_STATE2 0x2005
+/* Thermal Protection Registers */
+#define MAX98388_R2020_THERM_WARN_THRESH 0x2020
+/* Error Monitor */
+#define MAX98388_R2031_SPK_MON_THRESH 0x2031
+#define MAX98388_R2032_SPK_MON_LD_SEL 0x2032
+#define MAX98388_R2033_SPK_MON_DURATION 0x2033
+#define MAX98388_R2037_ERR_MON_CTRL 0x2037
+/* PCM Registers */
+#define MAX98388_R2040_PCM_MODE_CFG 0x2040
+#define MAX98388_R2041_PCM_CLK_SETUP 0x2041
+#define MAX98388_R2042_PCM_SR_SETUP 0x2042
+#define MAX98388_R2044_PCM_TX_CTRL1 0x2044
+#define MAX98388_R2045_PCM_TX_CTRL2 0x2045
+#define MAX98388_R2050_PCM_TX_HIZ_CTRL1 0x2050
+#define MAX98388_R2051_PCM_TX_HIZ_CTRL2 0x2051
+#define MAX98388_R2052_PCM_TX_HIZ_CTRL3 0x2052
+#define MAX98388_R2053_PCM_TX_HIZ_CTRL4 0x2053
+#define MAX98388_R2054_PCM_TX_HIZ_CTRL5 0x2054
+#define MAX98388_R2055_PCM_TX_HIZ_CTRL6 0x2055
+#define MAX98388_R2056_PCM_TX_HIZ_CTRL7 0x2056
+#define MAX98388_R2057_PCM_TX_HIZ_CTRL8 0x2057
+#define MAX98388_R2058_PCM_RX_SRC1 0x2058
+#define MAX98388_R2059_PCM_RX_SRC2 0x2059
+#define MAX98388_R205C_PCM_TX_DRIVE_STRENGTH 0x205C
+#define MAX98388_R205D_PCM_TX_SRC_EN 0x205D
+#define MAX98388_R205E_PCM_RX_EN 0x205E
+#define MAX98388_R205F_PCM_TX_EN 0x205F
+/* Speaker Channel Control */
+#define MAX98388_R2090_SPK_CH_VOL_CTRL 0x2090
+#define MAX98388_R2091_SPK_CH_CFG 0x2091
+#define MAX98388_R2092_SPK_AMP_OUT_CFG 0x2092
+#define MAX98388_R2093_SPK_AMP_SSM_CFG 0x2093
+#define MAX98388_R2094_SPK_AMP_ER_CTRL 0x2094
+#define MAX98388_R209E_SPK_CH_PINK_NOISE_EN 0x209E
+#define MAX98388_R209F_SPK_CH_AMP_EN 0x209F
+#define MAX98388_R20A0_IV_DATA_DSP_CTRL 0x20A0
+#define MAX98388_R20A7_IV_DATA_EN 0x20A7
+#define MAX98388_R20E0_BP_ALC_THRESH 0x20E0
+#define MAX98388_R20E1_BP_ALC_RATES 0x20E1
+#define MAX98388_R20E2_BP_ALC_ATTEN 0x20E2
+#define MAX98388_R20E3_BP_ALC_REL 0x20E3
+#define MAX98388_R20E4_BP_ALC_MUTE 0x20E4
+#define MAX98388_R20EE_BP_INF_HOLD_REL 0x20EE
+#define MAX98388_R20EF_BP_ALC_EN 0x20EF
+#define MAX98388_R210E_AUTO_RESTART 0x210E
+#define MAX98388_R210F_GLOBAL_EN 0x210F
+#define MAX98388_R22FF_REV_ID 0x22FF
+
+/* MAX98388_R2000_SW_RESET */
+#define MAX98388_SOFT_RESET (0x1 << 0)
+
+/* MAX98388_R2020_THERM_WARN_THRESH */
+#define MAX98388_THERM_SHDN_THRESH_SHIFT (0)
+#define MAX98388_THERM_WARN_THRESH_SHIFT (2)
+
+/* MAX98388_R2022_PCM_TX_SRC_1 */
+#define MAX98388_PCM_TX_CH_SRC_A_V_SHIFT (0)
+#define MAX98388_PCM_TX_CH_SRC_A_I_SHIFT (4)
+
+/* MAX98388_R2024_PCM_DATA_FMT_CFG */
+#define MAX98388_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3)
+#define MAX98388_PCM_MODE_CFG_FORMAT_SHIFT (3)
+#define MAX98388_PCM_TX_CH_INTERLEAVE_MASK (0x1 << 2)
+#define MAX98388_PCM_FORMAT_I2S (0x0 << 0)
+#define MAX98388_PCM_FORMAT_LJ (0x1 << 0)
+#define MAX98388_PCM_FORMAT_TDM_MODE0 (0x3 << 0)
+#define MAX98388_PCM_FORMAT_TDM_MODE1 (0x4 << 0)
+#define MAX98388_PCM_FORMAT_TDM_MODE2 (0x5 << 0)
+#define MAX98388_PCM_MODE_CFG_CHANSZ_MASK (0x3 << 6)
+#define MAX98388_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6)
+#define MAX98388_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6)
+#define MAX98388_PCM_MODE_CFG_CHANSZ_32 (0x3 << 6)
+
+/* MAX98388_R2031_SPK_MON_THRESH */
+#define MAX98388_SPKMON_THRESH_SHIFT (0)
+
+/* MAX98388_R2032_SPK_MON_LD_SEL */
+#define MAX98388_SPKMON_LOAD_SHIFT (0)
+
+/* MAX98388_R2033_SPK_MON_DURATION */
+#define MAX98388_SPKMON_DURATION_SHIFT (0)
+
+/* MAX98388_R2037_ERR_MON_CTRL */
+#define MAX98388_CLOCK_MON_SHIFT (0)
+#define MAX98388_SPK_MON_SHIFT (1)
+
+/* MAX98388_R203E_AMP_PATH_GAIN */
+#define MAX98388_SPK_DIGI_GAIN_MASK (0xF << 4)
+#define MAX98388_SPK_DIGI_GAIN_SHIFT (4)
+#define MAX98388_FS_GAIN_MAX_MASK (0xF << 0)
+#define MAX98388_FS_GAIN_MAX_SHIFT (0)
+
+/* MAX98388_R2041_PCM_CLK_SETUP */
+#define MAX98388_PCM_MODE_CFG_PCM_BCLKEDGE (0x1 << 4)
+#define MAX98388_PCM_CLK_SETUP_BSEL_MASK (0xF << 0)
+
+/* MAX98388_R2042_PCM_SR_SETUP */
+#define MAX98388_PCM_SR_MASK (0xF << 0)
+#define MAX98388_PCM_SR_IV_MASK (0xF << 4)
+#define MAX98388_PCM_SR_IV_SHIFT (4)
+#define MAX98388_PCM_SR_8000 (0x0 << 0)
+#define MAX98388_PCM_SR_11025 (0x1 << 0)
+#define MAX98388_PCM_SR_12000 (0x2 << 0)
+#define MAX98388_PCM_SR_16000 (0x3 << 0)
+#define MAX98388_PCM_SR_22050 (0x4 << 0)
+#define MAX98388_PCM_SR_24000 (0x5 << 0)
+#define MAX98388_PCM_SR_32000 (0x6 << 0)
+#define MAX98388_PCM_SR_44100 (0x7 << 0)
+#define MAX98388_PCM_SR_48000 (0x8 << 0)
+#define MAX98388_PCM_SR_88200 (0x9 << 0)
+#define MAX98388_PCM_SR_96000 (0xA << 0)
+
+/* MAX98388_R2043_AMP_EN */
+#define MAX98388_SPK_EN_MASK (0x1 << 0)
+#define MAX98388_SPKFB_EN_MASK (0x1 << 1)
+#define MAX98388_SPKFB_EN_SHIFT (1)
+
+/* MAX98388_R2052_MEAS_ADC_PVDD_FLT_CFG */
+#define MAX98388_FLT_EN_SHIFT (4)
+
+/* MAX98388_R2058_PCM_RX_SRC1 */
+#define MAX98388_PCM_TO_SPK_MONOMIX_CFG_SHIFT (0)
+
+/* MAX98388_R2059_PCM_RX_SRC2 */
+#define MAX98388_RX_SRC_CH0_SHIFT (0)
+#define MAX98388_RX_SRC_CH1_SHIFT (4)
+
+/* MAX98388_R2091_SPK_CH_CFG */
+#define MAX98388_SPK_CFG_DCBLK_SHIFT (0)
+#define MAX98388_SPK_CFG_DITH_EN_SHIFT (1)
+#define MAX98388_SPK_CFG_INV_SHIFT (2)
+#define MAX98388_SPK_CFG_VOL_RMPUP_SHIFT (3)
+#define MAX98388_SPK_CFG_VOL_RMPDN_SHIFT (4)
+
+/* MAX98388_R2092_SPK_AMP_OUT_CFG */
+#define MAX98388_SPK_AMP_OUT_GAIN_SHIFT (0)
+#define MAX98388_SPK_AMP_OUT_MODE_SHIFT (3)
+
+/* MAX98388_R2093_SPK_AMP_SSM_CFG */
+#define MAX98388_SPK_AMP_SSM_EN_SHIFT (0)
+#define MAX98388_SPK_AMP_SSM_MOD_SHIFT (1)
+
+/* MAX98388_R2094_SPK_AMP_ER_CTRL */
+#define MAX98388_EDGE_RATE_RISE_SHIFT (0)
+#define MAX98388_EDGE_RATE_FALL_SHIFT (2)
+
+/* MAX98388_R209E_SPK_CH_PINK_NOISE_EN */
+#define MAX98388_PINK_NOISE_GEN_SHIFT (0)
+
+/* MAX98388_R20A0_IV_DATA_DSP_CTRL */
+#define MAX98388_AMP_DSP_CTRL_VOL_DCBLK_SHIFT (0)
+#define MAX98388_AMP_DSP_CTRL_CUR_DCBLK_SHIFT (1)
+#define MAX98388_AMP_DSP_CTRL_VOL_INV_SHIFT (2)
+#define MAX98388_AMP_DSP_CTRL_CUR_INV_SHIFT (3)
+#define MAX98388_AMP_DSP_CTRL_DITH_SHIFT (4)
+
+/* MAX98388_R20B2_BDE_L4_CFG_2 */
+#define MAX98388_LVL4_HOLD_EN_SHIFT (6)
+#define MAX98388_LVL4_MUTE_EN_SHIFT (7)
+
+/* MAX98388_R20B5_BDE_EN */
+#define MAX98388_BDE_EN_SHIFT (0)
+
+/* MAX98388_R20D1_DHT_CFG */
+#define MAX98388_DHT_ROT_PNT_SHIFT (0)
+#define MAX98388_DHT_SPK_GAIN_MIN_SHIFT (4)
+
+/* MAX98388_R20D2_DHT_ATTACK_CFG */
+#define MAX98388_DHT_ATTACK_RATE_SHIFT (0)
+#define MAX98388_DHT_ATTACK_STEP_SHIFT (3)
+
+/* MAX98388_R20D3_DHT_RELEASE_CFG */
+#define MAX98388_DHT_RELEASE_RATE_SHIFT (0)
+#define MAX98388_DHT_RELEASE_STEP_SHIFT (3)
+
+/* MAX98388_R20D4_DHT_EN */
+#define MAX98388_DHT_EN_SHIFT (0)
+
+/* MAX98388_R20E0_BP_ALC_THRESH */
+#define MAX98388_ALC_THRESH_SHIFT (0)
+
+/* MAX98388_R20E1_BP_ALC_RATES */
+#define MAX98388_ALC_RELEASE_RATE_SHIFT (0)
+#define MAX98388_ALC_ATTACK_RATE_SHIFT (4)
+
+/* MAX98388_R20E2_BP_ALC_ATTEN */
+#define MAX98388_ALC_MAX_ATTEN_SHIFT (0)
+
+/* MAX98388_R20E3_BP_ALC_REL */
+#define MAX98388_ALC_DEBOUNCE_TIME_SHIFT (0)
+
+/* MAX98388_R20E4_BP_ALC_MUTE */
+#define MAX98388_ALC_MUTE_EN_SHIFT (0)
+#define MAX98388_ALC_MUTE_DELAY_SHIFT (1)
+#define MAX98388_ALC_MUTE_RAMP_EN_SHIFT (4)
+#define MAX98388_ALC_UNMUTE_RAMP_EN_SHIFT (5)
+
+/* MAX98388_R210E_AUTO_RESTART */
+#define MAX98388_PVDD_UVLO_AUTORESTART_SHIFT (0)
+#define MAX98388_THERM_AUTORESTART_SHIFT (1)
+#define MAX98388_OVC_AUTORESTART_SHIFT (2)
+#define MAX98388_CMON_AUTORESTART_SHIFT (3)
+
+/* MAX98388_R210F_GLOBAL_EN */
+#define MAX98388_GLOBAL_EN_MASK (0x1 << 0)
+
+struct max98388_priv {
+ struct regmap *regmap;
+ struct gpio_desc *reset_gpio;
+ unsigned int v_slot;
+ unsigned int i_slot;
+ unsigned int spkfb_slot;
+ bool interleave_mode;
+ unsigned int ch_size;
+ bool tdm_mode;
+};
+
+#endif
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
index 7a5260ff8d6b..5b8e78e51630 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -1133,7 +1133,7 @@ static struct i2c_driver max98390_i2c_driver = {
.acpi_match_table = ACPI_PTR(max98390_acpi_match),
.pm = &max98390_pm,
},
- .probe_new = max98390_i2c_probe,
+ .probe = max98390_i2c_probe,
.id_table = max98390_i2c_id,
};
diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c
index db3de41f10e0..3a1d8c211f3c 100644
--- a/sound/soc/codecs/max98396.c
+++ b/sound/soc/codecs/max98396.c
@@ -1907,7 +1907,7 @@ static struct i2c_driver max98396_i2c_driver = {
.acpi_match_table = ACPI_PTR(max98396_acpi_match),
.pm = &max98396_pm,
},
- .probe_new = max98396_i2c_probe,
+ .probe = max98396_i2c_probe,
.id_table = max98396_i2c_id,
};
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
index a6733396b0ca..8b012a85360a 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -329,7 +329,7 @@ static struct i2c_driver max9850_i2c_driver = {
.driver = {
.name = "max9850",
},
- .probe_new = max9850_i2c_probe,
+ .probe = max9850_i2c_probe,
.id_table = max9850_i2c_id,
};
diff --git a/sound/soc/codecs/max98504.c b/sound/soc/codecs/max98504.c
index 0daa2a3dd621..93412b966b33 100644
--- a/sound/soc/codecs/max98504.c
+++ b/sound/soc/codecs/max98504.c
@@ -371,7 +371,7 @@ static struct i2c_driver max98504_i2c_driver = {
.name = "max98504",
.of_match_table = of_match_ptr(max98504_of_match),
},
- .probe_new = max98504_i2c_probe,
+ .probe = max98504_i2c_probe,
.id_table = max98504_i2c_id,
};
module_i2c_driver(max98504_i2c_driver);
diff --git a/sound/soc/codecs/max98520.c b/sound/soc/codecs/max98520.c
index 5edd6f90f8a7..8637fff307ad 100644
--- a/sound/soc/codecs/max98520.c
+++ b/sound/soc/codecs/max98520.c
@@ -756,7 +756,7 @@ static struct i2c_driver max98520_i2c_driver = {
.of_match_table = of_match_ptr(max98520_of_match),
.pm = &max98520_pm,
},
- .probe_new = max98520_i2c_probe,
+ .probe = max98520_i2c_probe,
.id_table = max98520_i2c_id,
};
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c
index 9611ab1e79e5..4015ed2c47ec 100644
--- a/sound/soc/codecs/max9860.c
+++ b/sound/soc/codecs/max9860.c
@@ -723,7 +723,7 @@ static const struct of_device_id max9860_of_match[] = {
MODULE_DEVICE_TABLE(of, max9860_of_match);
static struct i2c_driver max9860_i2c_driver = {
- .probe_new = max9860_probe,
+ .probe = max9860_probe,
.remove = max9860_remove,
.id_table = max9860_i2c_id,
.driver = {
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
index ae552d72beec..b616ad39858c 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -702,7 +702,7 @@ static struct i2c_driver max9867_i2c_driver = {
.name = "max9867",
.of_match_table = of_match_ptr(max9867_of_match),
},
- .probe_new = max9867_i2c_probe,
+ .probe = max9867_i2c_probe,
.id_table = max9867_i2c_id,
};
diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c
index 3bf86328d5cd..2ae64fcf29c7 100644
--- a/sound/soc/codecs/max9877.c
+++ b/sound/soc/codecs/max9877.c
@@ -160,7 +160,7 @@ static struct i2c_driver max9877_i2c_driver = {
.driver = {
.name = "max9877",
},
- .probe_new = max9877_i2c_probe,
+ .probe = max9877_i2c_probe,
.id_table = max9877_i2c_id,
};
diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c
index c24d9f2c8874..a9c1d85cd0d5 100644
--- a/sound/soc/codecs/max98925.c
+++ b/sound/soc/codecs/max98925.c
@@ -635,7 +635,7 @@ static struct i2c_driver max98925_i2c_driver = {
.name = "max98925",
.of_match_table = of_match_ptr(max98925_of_match),
},
- .probe_new = max98925_i2c_probe,
+ .probe = max98925_i2c_probe,
.id_table = max98925_i2c_id,
};
diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c
index bffd56e240e9..bdc508e23e59 100644
--- a/sound/soc/codecs/max98926.c
+++ b/sound/soc/codecs/max98926.c
@@ -582,7 +582,7 @@ static struct i2c_driver max98926_i2c_driver = {
.name = "max98926",
.of_match_table = of_match_ptr(max98926_of_match),
},
- .probe_new = max98926_i2c_probe,
+ .probe = max98926_i2c_probe,
.id_table = max98926_i2c_id,
};
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index 331d3e1d735c..0aaf2e6ae78d 100644
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -973,7 +973,7 @@ static struct i2c_driver max98927_i2c_driver = {
.acpi_match_table = ACPI_PTR(max98927_acpi_match),
.pm = &max98927_pm,
},
- .probe_new = max98927_i2c_probe,
+ .probe = max98927_i2c_probe,
.remove = max98927_i2c_remove,
.id_table = max98927_i2c_id,
};
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index 3c6ac77379cb..a45ef9d65703 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -581,7 +581,7 @@ static struct i2c_driver ml26124_i2c_driver = {
.driver = {
.name = "ml26124",
},
- .probe_new = ml26124_i2c_probe,
+ .probe = ml26124_i2c_probe,
.id_table = ml26124_i2c_id,
};
diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c
index cb487e63615c..30690479ec17 100644
--- a/sound/soc/codecs/mt6359.c
+++ b/sound/soc/codecs/mt6359.c
@@ -18,6 +18,20 @@
#include "mt6359.h"
+static void mt6359_set_gpio_smt(struct mt6359_priv *priv)
+{
+ /* set gpio SMT mode */
+ regmap_update_bits(priv->regmap, MT6359_SMT_CON1, 0x3ff0, 0x3ff0);
+}
+
+static void mt6359_set_gpio_driving(struct mt6359_priv *priv)
+{
+ /* 8:4mA(default), a:8mA, c:12mA, e:16mA */
+ regmap_update_bits(priv->regmap, MT6359_DRV_CON2, 0xffff, 0x8888);
+ regmap_update_bits(priv->regmap, MT6359_DRV_CON3, 0xffff, 0x8888);
+ regmap_update_bits(priv->regmap, MT6359_DRV_CON4, 0x00ff, 0x88);
+}
+
static void mt6359_set_playback_gpio(struct mt6359_priv *priv)
{
/* set gpio mosi mode, clk / data mosi */
@@ -360,8 +374,34 @@ static int mt6359_put_volsw(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = 0;
int index = ucontrol->value.integer.value[0];
+ int orig_gain[2], new_gain[2];
int ret;
+ switch (mc->reg) {
+ case MT6359_ZCD_CON2:
+ orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL];
+ orig_gain[1] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR];
+ break;
+ case MT6359_ZCD_CON1:
+ orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL];
+ orig_gain[1] = priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR];
+ break;
+ case MT6359_ZCD_CON3:
+ orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL];
+ break;
+ case MT6359_AUDENC_ANA_CON0:
+ orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1];
+ break;
+ case MT6359_AUDENC_ANA_CON1:
+ orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2];
+ break;
+ case MT6359_AUDENC_ANA_CON2:
+ orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP3];
+ break;
+ default:
+ return -EINVAL;
+ }
+
ret = snd_soc_put_volsw(kcontrol, ucontrol);
if (ret < 0)
return ret;
@@ -373,6 +413,8 @@ static int mt6359_put_volsw(struct snd_kcontrol *kcontrol,
(reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK;
priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] =
(reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK;
+ new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL];
+ new_gain[1] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR];
break;
case MT6359_ZCD_CON1:
regmap_read(priv->regmap, MT6359_ZCD_CON1, &reg);
@@ -380,35 +422,82 @@ static int mt6359_put_volsw(struct snd_kcontrol *kcontrol,
(reg >> RG_AUDLOLGAIN_SFT) & RG_AUDLOLGAIN_MASK;
priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR] =
(reg >> RG_AUDLORGAIN_SFT) & RG_AUDLORGAIN_MASK;
+ new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL];
+ new_gain[1] = priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR];
break;
case MT6359_ZCD_CON3:
regmap_read(priv->regmap, MT6359_ZCD_CON3, &reg);
priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL] =
(reg >> RG_AUDHSGAIN_SFT) & RG_AUDHSGAIN_MASK;
+ new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL];
break;
case MT6359_AUDENC_ANA_CON0:
regmap_read(priv->regmap, MT6359_AUDENC_ANA_CON0, &reg);
priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1] =
(reg >> RG_AUDPREAMPLGAIN_SFT) & RG_AUDPREAMPLGAIN_MASK;
+ new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1];
break;
case MT6359_AUDENC_ANA_CON1:
regmap_read(priv->regmap, MT6359_AUDENC_ANA_CON1, &reg);
priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2] =
(reg >> RG_AUDPREAMPRGAIN_SFT) & RG_AUDPREAMPRGAIN_MASK;
+ new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2];
break;
case MT6359_AUDENC_ANA_CON2:
regmap_read(priv->regmap, MT6359_AUDENC_ANA_CON2, &reg);
priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP3] =
(reg >> RG_AUDPREAMP3GAIN_SFT) & RG_AUDPREAMP3GAIN_MASK;
+ new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP3];
break;
}
+ ret = 0;
+ if (orig_gain[0] != new_gain[0]) {
+ ret = 1;
+ } else if (snd_soc_volsw_is_stereo(mc)) {
+ if (orig_gain[1] != new_gain[1])
+ ret = 1;
+ }
+
dev_dbg(priv->dev, "%s(), name %s, reg(0x%x) = 0x%x, set index = %x\n",
__func__, kcontrol->id.name, mc->reg, reg, index);
return ret;
}
+static int mt6359_get_playback_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct mt6359_priv *priv = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ switch (mc->reg) {
+ case MT6359_ZCD_CON2:
+ ucontrol->value.integer.value[0] =
+ priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL];
+ ucontrol->value.integer.value[1] =
+ priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR];
+ break;
+ case MT6359_ZCD_CON1:
+ ucontrol->value.integer.value[0] =
+ priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL];
+ ucontrol->value.integer.value[1] =
+ priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR];
+ break;
+ case MT6359_ZCD_CON3:
+ ucontrol->value.integer.value[0] =
+ priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/* MUX */
/* LOL MUX */
@@ -1070,9 +1159,10 @@ static int mt_lo_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+ unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
dev_dbg(priv->dev, "%s(), event 0x%x, mux %u\n",
- __func__, event, dapm_kcontrol_get_value(w->kcontrols[0]));
+ __func__, event, mux);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1110,14 +1200,29 @@ static int mt_lo_event(struct snd_soc_dapm_widget *w,
/* Enable AUD_CLK */
mt6359_set_decoder_clk(priv, true);
- /* Enable Audio DAC (3rd DAC) */
- regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x3113);
- /* Enable low-noise mode of DAC */
- if (priv->dev_counter[DEVICE_HP] == 0)
- regmap_write(priv->regmap,
- MT6359_AUDDEC_ANA_CON9, 0x0001);
- /* Switch LOL MUX to audio 3rd DAC */
- regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x311b);
+ /* Switch LOL MUX to audio DAC */
+ if (mux == LO_MUX_L_DAC) {
+ if (priv->dev_counter[DEVICE_HP] > 0) {
+ dev_info(priv->dev, "%s(), can not enable DAC, hp count %d\n",
+ __func__, priv->dev_counter[DEVICE_HP]);
+ break;
+ }
+ /* Enable DACL and switch HP MUX to open*/
+ regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON0, 0x3009);
+ /* Disable low-noise mode of DAC */
+ regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON9, 0xf200);
+ usleep_range(100, 120);
+ /* Switch LOL MUX to DACL */
+ regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x0117);
+ } else if (mux == LO_MUX_3RD_DAC) {
+ /* Enable Audio DAC (3rd DAC) */
+ regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x3113);
+ /* Enable low-noise mode of DAC */
+ if (priv->dev_counter[DEVICE_HP] == 0)
+ regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON9, 0x0001);
+ /* Switch LOL MUX to audio 3rd DAC */
+ regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x311b);
+ }
break;
case SND_SOC_DAPM_PRE_PMD:
/* Switch LOL MUX to open */
@@ -1129,6 +1234,15 @@ static int mt_lo_event(struct snd_soc_dapm_widget *w,
regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0,
0x000f, 0x0000);
+ if (mux == LO_MUX_L_DAC) {
+ /* Disable HP driver core circuits */
+ regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0,
+ 0x3 << 4, 0x0);
+ /* Disable HP driver bias circuits */
+ regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0,
+ 0x3 << 6, 0x0);
+ }
+
/* Disable AUD_CLK */
mt6359_set_decoder_clk(priv, false);
@@ -2358,6 +2472,10 @@ static const struct snd_soc_dapm_route mt6359_dapm_routes[] = {
{"MISO2_MUX", "UL2_CH1", "UL2_SRC_MUX"},
{"MISO2_MUX", "UL2_CH2", "UL2_SRC_MUX"},
+ {"MISO0_MUX", NULL, "UL_SRC"},
+ {"MISO1_MUX", NULL, "UL_SRC"},
+ {"MISO2_MUX", NULL, "UL_SRC_34"},
+
{"UL_SRC_MUX", "AMIC", "ADC_L"},
{"UL_SRC_MUX", "AMIC", "ADC_R"},
{"UL_SRC_MUX", "DMIC", "DMIC0_MUX"},
@@ -2497,6 +2615,7 @@ static const struct snd_soc_dapm_route mt6359_dapm_routes[] = {
/* Lineout Path */
{"LOL Mux", "Playback", "DAC_3RD"},
+ {"LOL Mux", "Playback_L_DAC", "DACL"},
{"LINEOUT L", NULL, "LOL Mux"},
/* Headphone Path */
@@ -2666,6 +2785,8 @@ static int mt6359_codec_init_reg(struct snd_soc_component *cmpnt)
0x1 << RG_AUDLOLSCDISABLE_VAUDP32_SFT);
/* set gpio */
+ mt6359_set_gpio_smt(priv);
+ mt6359_set_gpio_driving(priv);
mt6359_reset_playback_gpio(priv);
mt6359_reset_capture_gpio(priv);
@@ -2697,22 +2818,23 @@ static void mt6359_codec_remove(struct snd_soc_component *cmpnt)
cmpnt->regmap = NULL;
}
-static const DECLARE_TLV_DB_SCALE(hp_playback_tlv, -2200, 100, 0);
static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0);
static const DECLARE_TLV_DB_SCALE(capture_tlv, 0, 600, 0);
static const struct snd_kcontrol_new mt6359_snd_controls[] = {
/* dl pga gain */
SOC_DOUBLE_EXT_TLV("Headset Volume",
- MT6359_ZCD_CON2, 0, 7, 0x1E, 0,
- snd_soc_get_volsw, mt6359_put_volsw,
- hp_playback_tlv),
+ MT6359_ZCD_CON2, 0, 7, 0x12, 0,
+ mt6359_get_playback_volsw, mt6359_put_volsw,
+ playback_tlv),
SOC_DOUBLE_EXT_TLV("Lineout Volume",
MT6359_ZCD_CON1, 0, 7, 0x12, 0,
- snd_soc_get_volsw, mt6359_put_volsw, playback_tlv),
+ mt6359_get_playback_volsw, mt6359_put_volsw,
+ playback_tlv),
SOC_SINGLE_EXT_TLV("Handset Volume",
MT6359_ZCD_CON3, 0, 0x12, 0,
- snd_soc_get_volsw, mt6359_put_volsw, playback_tlv),
+ mt6359_get_playback_volsw, mt6359_put_volsw,
+ playback_tlv),
/* ul pga gain */
SOC_SINGLE_EXT_TLV("PGA1 Volume",
diff --git a/sound/soc/codecs/mt6660.c b/sound/soc/codecs/mt6660.c
index cc2df5f7ea19..5c50c7de26cd 100644
--- a/sound/soc/codecs/mt6660.c
+++ b/sound/soc/codecs/mt6660.c
@@ -570,7 +570,7 @@ static struct i2c_driver mt6660_i2c_driver = {
.of_match_table = of_match_ptr(mt6660_of_id),
.pm = &mt6660_dev_pm_ops,
},
- .probe_new = mt6660_i2c_probe,
+ .probe = mt6660_i2c_probe,
.remove = mt6660_i2c_remove,
.id_table = mt6660_i2c_id,
};
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c
index 0626d5694c22..2174a89772fc 100644
--- a/sound/soc/codecs/nau8540.c
+++ b/sound/soc/codecs/nau8540.c
@@ -890,7 +890,7 @@ static struct i2c_driver nau8540_i2c_driver = {
.name = "nau8540",
.of_match_table = of_match_ptr(nau8540_of_ids),
},
- .probe_new = nau8540_i2c_probe,
+ .probe = nau8540_i2c_probe,
.id_table = nau8540_i2c_ids,
};
module_i2c_driver(nau8540_i2c_driver);
diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c
index ccb512c21d74..47f000cd4d99 100644
--- a/sound/soc/codecs/nau8810.c
+++ b/sound/soc/codecs/nau8810.c
@@ -914,7 +914,7 @@ static struct i2c_driver nau8810_i2c_driver = {
.name = "nau8810",
.of_match_table = of_match_ptr(nau8810_of_match),
},
- .probe_new = nau8810_i2c_probe,
+ .probe = nau8810_i2c_probe,
.id_table = nau8810_i2c_id,
};
diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c
index fee970427a24..96d75882b33a 100644
--- a/sound/soc/codecs/nau8821.c
+++ b/sound/soc/codecs/nau8821.c
@@ -1859,7 +1859,7 @@ static struct i2c_driver nau8821_driver = {
.of_match_table = of_match_ptr(nau8821_of_ids),
.acpi_match_table = ACPI_PTR(nau8821_acpi_match),
},
- .probe_new = nau8821_i2c_probe,
+ .probe = nau8821_i2c_probe,
.id_table = nau8821_i2c_ids,
};
module_i2c_driver(nau8821_driver);
diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c
index d5006d8de639..ff3024899f45 100644
--- a/sound/soc/codecs/nau8822.c
+++ b/sound/soc/codecs/nau8822.c
@@ -1166,7 +1166,7 @@ static struct i2c_driver nau8822_i2c_driver = {
.name = "nau8822",
.of_match_table = of_match_ptr(nau8822_of_match),
},
- .probe_new = nau8822_i2c_probe,
+ .probe = nau8822_i2c_probe,
.id_table = nau8822_i2c_id,
};
module_i2c_driver(nau8822_i2c_driver);
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
index 5a4db8944d06..704af1cf8cbf 100644
--- a/sound/soc/codecs/nau8824.c
+++ b/sound/soc/codecs/nau8824.c
@@ -2030,7 +2030,7 @@ static struct i2c_driver nau8824_i2c_driver = {
.of_match_table = of_match_ptr(nau8824_of_ids),
.acpi_match_table = ACPI_PTR(nau8824_acpi_match),
},
- .probe_new = nau8824_i2c_probe,
+ .probe = nau8824_i2c_probe,
.id_table = nau8824_i2c_ids,
};
module_i2c_driver(nau8824_i2c_driver);
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index f4eb999761a4..9e0e4ddf128e 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -53,6 +53,7 @@ struct nau8825_fll {
int mclk_src;
int ratio;
int fll_frac;
+ int fll_frac_num;
int fll_int;
int clk_ref_div;
};
@@ -178,6 +179,8 @@ static const struct reg_default nau8825_reg_defaults[] = {
{ NAU8825_REG_CLASSG_CTRL, 0x0 },
{ NAU8825_REG_OPT_EFUSE_CTRL, 0x0 },
{ NAU8825_REG_MISC_CTRL, 0x0 },
+ { NAU8825_REG_FLL2_LOWER, 0x0 },
+ { NAU8825_REG_FLL2_UPPER, 0x0 },
{ NAU8825_REG_BIAS_ADJ, 0x0 },
{ NAU8825_REG_TRIM_SETTINGS, 0x0 },
{ NAU8825_REG_ANALOG_CONTROL_1, 0x0 },
@@ -200,6 +203,23 @@ static struct reg_default nau8825_xtalk_baktab[] = {
{ NAU8825_REG_DACR_CTRL, 0x02cf },
};
+/* The regmap patch for Rev C */
+static const struct reg_sequence nau8825_regmap_patch[] = {
+ { NAU8825_REG_FLL2, 0x0000 },
+ { NAU8825_REG_FLL4, 0x8010 },
+ { NAU8825_REG_FLL_VCO_RSV, 0x0bc0 },
+ { NAU8825_REG_INTERRUPT_MASK, 0x0800 },
+ { NAU8825_REG_DACL_CTRL, 0x00cf },
+ { NAU8825_REG_DACR_CTRL, 0x02cf },
+ { NAU8825_REG_OPT_EFUSE_CTRL, 0x0400 },
+ { NAU8825_REG_FLL2_LOWER, 0x26e9 },
+ { NAU8825_REG_FLL2_UPPER, 0x0031 },
+ { NAU8825_REG_ANALOG_CONTROL_2, 0x0020 },
+ { NAU8825_REG_ANALOG_ADC_2, 0x0220 },
+ { NAU8825_REG_MIC_BIAS, 0x0046 },
+};
+
+
static const unsigned short logtable[256] = {
0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
@@ -608,8 +628,13 @@ static void nau8825_xtalk_prepare(struct nau8825 *nau8825)
regmap_update_bits(nau8825->regmap,
NAU8825_REG_INTERRUPT_MASK, NAU8825_IRQ_RMS_EN, 0);
/* Power up left and right DAC */
- regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
- NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, 0);
+ if (nau8825->sw_id == NAU8825_SOFTWARE_ID_NAU8825)
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+ NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, 0);
+ else
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+ NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
+ NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
}
static void nau8825_xtalk_clean_dac(struct nau8825 *nau8825)
@@ -622,9 +647,14 @@ static void nau8825_xtalk_clean_dac(struct nau8825 *nau8825)
NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L,
NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L);
/* Power down left and right DAC */
- regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
- NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
- NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
+ if (nau8825->sw_id == NAU8825_SOFTWARE_ID_NAU8825)
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+ NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
+ NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
+ else
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+ NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, 0);
+
/* Enable the TESTDAC and disable L/R HP impedance */
regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
NAU8825_BIAS_HPR_IMP | NAU8825_BIAS_HPL_IMP |
@@ -855,7 +885,7 @@ static bool nau8825_readable_reg(struct device *dev, unsigned int reg)
case NAU8825_REG_IMM_MODE_CTRL ... NAU8825_REG_IMM_RMS_R:
case NAU8825_REG_CLASSG_CTRL ... NAU8825_REG_OPT_EFUSE_CTRL:
case NAU8825_REG_MISC_CTRL:
- case NAU8825_REG_I2C_DEVICE_ID ... NAU8825_REG_SARDOUT_RAM_STATUS:
+ case NAU8825_REG_I2C_DEVICE_ID ... NAU8825_REG_FLL2_UPPER:
case NAU8825_REG_BIAS_ADJ:
case NAU8825_REG_TRIM_SETTINGS ... NAU8825_REG_ANALOG_CONTROL_2:
case NAU8825_REG_ANALOG_ADC_1 ... NAU8825_REG_MIC_BIAS:
@@ -881,6 +911,7 @@ static bool nau8825_writeable_reg(struct device *dev, unsigned int reg)
case NAU8825_REG_IMM_MODE_CTRL:
case NAU8825_REG_CLASSG_CTRL ... NAU8825_REG_OPT_EFUSE_CTRL:
case NAU8825_REG_MISC_CTRL:
+ case NAU8825_REG_FLL2_LOWER ... NAU8825_REG_FLL2_UPPER:
case NAU8825_REG_BIAS_ADJ:
case NAU8825_REG_TRIM_SETTINGS ... NAU8825_REG_ANALOG_CONTROL_2:
case NAU8825_REG_ANALOG_ADC_1 ... NAU8825_REG_MIC_BIAS:
@@ -911,6 +942,32 @@ static bool nau8825_volatile_reg(struct device *dev, unsigned int reg)
}
}
+static int nau8825_fepga_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 nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_FEPGA,
+ NAU8825_ACDC_CTRL_MASK,
+ NAU8825_ACDC_VREF_MICP | NAU8825_ACDC_VREF_MICN);
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_BOOST,
+ NAU8825_DISCHRG_EN, NAU8825_DISCHRG_EN);
+ msleep(40);
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_BOOST,
+ NAU8825_DISCHRG_EN, 0);
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_FEPGA,
+ NAU8825_ACDC_CTRL_MASK, 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int nau8825_adc_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -970,10 +1027,25 @@ static int nau8825_output_dac_event(struct snd_soc_dapm_widget *w,
/* Disables the TESTDAC to let DAC signal pass through. */
regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
NAU8825_BIAS_TESTDAC_EN, 0);
+ if (nau8825->sw_id == NAU8825_SOFTWARE_ID_NAU8825)
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+ NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, 0);
+ else
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+ NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
+ NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
break;
case SND_SOC_DAPM_POST_PMD:
regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
NAU8825_BIAS_TESTDAC_EN, NAU8825_BIAS_TESTDAC_EN);
+ if (nau8825->sw_id == NAU8825_SOFTWARE_ID_NAU8825)
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+ NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
+ NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
+ else
+ regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+ NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, 0);
+
break;
default:
return -EINVAL;
@@ -1127,8 +1199,8 @@ static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("MIC"),
SND_SOC_DAPM_MICBIAS("MICBIAS", NAU8825_REG_MIC_BIAS, 8, 0),
- SND_SOC_DAPM_PGA("Frontend PGA", NAU8825_REG_POWER_UP_CONTROL, 14, 0,
- NULL, 0),
+ SND_SOC_DAPM_PGA_E("Frontend PGA", NAU8825_REG_POWER_UP_CONTROL, 14, 0,
+ NULL, 0, nau8825_fepga_event, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_ADC_E("ADC", NULL, SND_SOC_NOPM, 0, 0,
nau8825_adc_event, SND_SOC_DAPM_POST_PMU |
@@ -1181,12 +1253,13 @@ static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = {
NAU8825_REG_POWER_UP_CONTROL, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("Output DACL", 7,
- NAU8825_REG_CHARGE_PUMP, 8, 1, nau8825_output_dac_event,
+ SND_SOC_NOPM, 0, 0, nau8825_output_dac_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_S("Output DACR", 7,
- NAU8825_REG_CHARGE_PUMP, 9, 1, nau8825_output_dac_event,
+ SND_SOC_NOPM, 0, 0, nau8825_output_dac_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
/* HPOL/R are ungrounded by disabling 16 Ohm pull-downs on playback */
SND_SOC_DAPM_PGA_S("HPOL Pulldown", 8,
NAU8825_REG_HSD_CTRL, 0, 1, NULL, 0),
@@ -1678,6 +1751,10 @@ static void nau8825_setup_auto_irq(struct nau8825 *nau8825)
{
struct regmap *regmap = nau8825->regmap;
+ /* Enable HSD function */
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+ NAU8825_HSD_AUTO_MODE, NAU8825_HSD_AUTO_MODE);
+
/* Enable headset jack type detection complete interruption and
* jack ejection interruption.
*/
@@ -1929,6 +2006,9 @@ static int nau8825_jack_insert(struct nau8825 *nau8825)
regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
NAU8825_CLK_MCLK_SRC_MASK, 0xf);
+ /* Disable HSD function */
+ regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, NAU8825_HSD_AUTO_MODE, 0);
+
/* Leaving HPOL/R grounded after jack insert by default. They will be
* ungrounded as part of the widget power up sequence at the beginning
* of playback to reduce pop.
@@ -2173,9 +2253,10 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1,
NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_64);
/* Disable DACR/L power */
- regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP,
- NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
- NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
+ if (nau8825->sw_id == NAU8825_SOFTWARE_ID_NAU8825)
+ regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP,
+ NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
+ NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
/* Enable TESTDAC. This sets the analog DAC inputs to a '0' input
* signal to avoid any glitches due to power up transients in both
* the analog and digital DAC circuit.
@@ -2307,9 +2388,12 @@ static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs,
/* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional
* input based on FDCO, FREF and FLL ratio.
*/
- fvco = div_u64(fvco_max << 16, fref * fll_param->ratio);
- fll_param->fll_int = (fvco >> 16) & 0x3FF;
- fll_param->fll_frac = fvco & 0xFFFF;
+ fvco = div_u64(fvco_max << fll_param->fll_frac_num, fref * fll_param->ratio);
+ fll_param->fll_int = (fvco >> fll_param->fll_frac_num) & 0x3FF;
+ if (fll_param->fll_frac_num == 16)
+ fll_param->fll_frac = fvco & 0xFFFF;
+ else
+ fll_param->fll_frac = fvco & 0xFFFFFF;
return 0;
}
@@ -2323,8 +2407,16 @@ static void nau8825_fll_apply(struct nau8825 *nau8825,
regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL1,
NAU8825_FLL_RATIO_MASK | NAU8825_ICTRL_LATCH_MASK,
fll_param->ratio | (0x6 << NAU8825_ICTRL_LATCH_SFT));
- /* FLL 16-bit fractional input */
- regmap_write(nau8825->regmap, NAU8825_REG_FLL2, fll_param->fll_frac);
+ /* FLL 16/24 bit fractional input */
+ if (fll_param->fll_frac_num == 16)
+ regmap_write(nau8825->regmap, NAU8825_REG_FLL2,
+ fll_param->fll_frac);
+ else {
+ regmap_write(nau8825->regmap, NAU8825_REG_FLL2_LOWER,
+ fll_param->fll_frac & 0xffff);
+ regmap_write(nau8825->regmap, NAU8825_REG_FLL2_UPPER,
+ (fll_param->fll_frac >> 16) & 0xff);
+ }
/* FLL 10-bit integer input */
regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL3,
NAU8825_FLL_INTEGER_MASK, fll_param->fll_int);
@@ -2366,6 +2458,11 @@ static int nau8825_set_pll(struct snd_soc_component *component, int pll_id, int
struct nau8825_fll fll_param;
int ret, fs;
+ if (nau8825->sw_id == NAU8825_SOFTWARE_ID_NAU8825)
+ fll_param.fll_frac_num = 16;
+ else
+ fll_param.fll_frac_num = 24;
+
fs = freq_out / 256;
ret = nau8825_calc_fll_param(freq_in, fs, &fll_param);
if (ret < 0) {
@@ -2897,8 +2994,19 @@ static int nau8825_i2c_probe(struct i2c_client *i2c)
ret);
return ret;
}
- if ((value & NAU8825_SOFTWARE_ID_MASK) !=
- NAU8825_SOFTWARE_ID_NAU8825) {
+ nau8825->sw_id = value & NAU8825_SOFTWARE_ID_MASK;
+ switch (nau8825->sw_id) {
+ case NAU8825_SOFTWARE_ID_NAU8825:
+ break;
+ case NAU8825_SOFTWARE_ID_NAU8825C:
+ ret = regmap_register_patch(nau8825->regmap, nau8825_regmap_patch,
+ ARRAY_SIZE(nau8825_regmap_patch));
+ if (ret) {
+ dev_err(dev, "Failed to register Rev C patch: %d\n", ret);
+ return ret;
+ }
+ break;
+ default:
dev_err(dev, "Not a NAU8825 chip\n");
return -ENODEV;
}
@@ -2944,7 +3052,7 @@ static struct i2c_driver nau8825_driver = {
.of_match_table = of_match_ptr(nau8825_of_ids),
.acpi_match_table = ACPI_PTR(nau8825_acpi_match),
},
- .probe_new = nau8825_i2c_probe,
+ .probe = nau8825_i2c_probe,
.remove = nau8825_i2c_remove,
.id_table = nau8825_i2c_ids,
};
diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h
index 44b62bc3880f..2abfbb5184da 100644
--- a/sound/soc/codecs/nau8825.h
+++ b/sound/soc/codecs/nau8825.h
@@ -75,6 +75,8 @@
#define NAU8825_REG_MISC_CTRL 0x55
#define NAU8825_REG_I2C_DEVICE_ID 0x58
#define NAU8825_REG_SARDOUT_RAM_STATUS 0x59
+#define NAU8825_REG_FLL2_LOWER 0x5a
+#define NAU8825_REG_FLL2_UPPER 0x5b
#define NAU8825_REG_BIAS_ADJ 0x66
#define NAU8825_REG_TRIM_SETTINGS 0x68
#define NAU8825_REG_ANALOG_CONTROL_1 0x69
@@ -386,6 +388,7 @@
#define NAU8825_GPIO2JD1 (1 << 7)
#define NAU8825_SOFTWARE_ID_MASK 0x3
#define NAU8825_SOFTWARE_ID_NAU8825 0x0
+#define NAU8825_SOFTWARE_ID_NAU8825C 0x1
/* BIAS_ADJ (0x66) */
#define NAU8825_BIAS_HPR_IMP (1 << 15)
@@ -442,10 +445,17 @@
/* BOOST (0x76) */
#define NAU8825_PRECHARGE_DIS (1 << 13)
#define NAU8825_GLOBAL_BIAS_EN (1 << 12)
+#define NAU8825_DISCHRG_EN (1 << 11)
#define NAU8825_HP_BOOST_DIS (1 << 9)
#define NAU8825_HP_BOOST_G_DIS (1 << 8)
#define NAU8825_SHORT_SHUTDOWN_EN (1 << 6)
+/* FEPGA (0x77) */
+#define NAU8825_ACDC_CTRL_SFT 14
+#define NAU8825_ACDC_CTRL_MASK (0x3 << NAU8825_ACDC_CTRL_SFT)
+#define NAU8825_ACDC_VREF_MICP (0x1 << NAU8825_ACDC_CTRL_SFT)
+#define NAU8825_ACDC_VREF_MICN (0x2 << NAU8825_ACDC_CTRL_SFT)
+
/* POWER_UP_CONTROL (0x7f) */
#define NAU8825_POWERUP_INTEGR_R (1 << 5)
#define NAU8825_POWERUP_INTEGR_L (1 << 4)
@@ -490,6 +500,7 @@ struct nau8825 {
struct clk *mclk;
struct work_struct xtalk_work;
struct semaphore xtalk_sem;
+ int sw_id;
int irq;
int mclk_freq; /* 0 - mclk is disabled */
int button_pressed;
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index 3591f6f53901..735e1942b530 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -327,7 +327,7 @@ static struct i2c_driver pcm1681_i2c_driver = {
.of_match_table = of_match_ptr(pcm1681_dt_ids),
},
.id_table = pcm1681_i2c_id,
- .probe_new = pcm1681_i2c_probe,
+ .probe = pcm1681_i2c_probe,
};
module_i2c_driver(pcm1681_i2c_driver);
diff --git a/sound/soc/codecs/pcm1789-i2c.c b/sound/soc/codecs/pcm1789-i2c.c
index fafe0dcbe4ea..f2d0b4d21e41 100644
--- a/sound/soc/codecs/pcm1789-i2c.c
+++ b/sound/soc/codecs/pcm1789-i2c.c
@@ -52,7 +52,7 @@ static struct i2c_driver pcm1789_i2c_driver = {
.of_match_table = of_match_ptr(pcm1789_of_match),
},
.id_table = pcm1789_i2c_ids,
- .probe_new = pcm1789_i2c_probe,
+ .probe = pcm1789_i2c_probe,
.remove = pcm1789_i2c_remove,
};
diff --git a/sound/soc/codecs/pcm179x-i2c.c b/sound/soc/codecs/pcm179x-i2c.c
index e20fe3a85af8..10579681f44b 100644
--- a/sound/soc/codecs/pcm179x-i2c.c
+++ b/sound/soc/codecs/pcm179x-i2c.c
@@ -49,7 +49,7 @@ static struct i2c_driver pcm179x_i2c_driver = {
.of_match_table = of_match_ptr(pcm179x_of_match),
},
.id_table = pcm179x_i2c_ids,
- .probe_new = pcm179x_i2c_probe,
+ .probe = pcm179x_i2c_probe,
};
module_i2c_driver(pcm179x_i2c_driver);
diff --git a/sound/soc/codecs/pcm186x-i2c.c b/sound/soc/codecs/pcm186x-i2c.c
index 932c8d41c3ea..a514ebd1b68a 100644
--- a/sound/soc/codecs/pcm186x-i2c.c
+++ b/sound/soc/codecs/pcm186x-i2c.c
@@ -46,7 +46,7 @@ static int pcm186x_i2c_probe(struct i2c_client *i2c)
}
static struct i2c_driver pcm186x_i2c_driver = {
- .probe_new = pcm186x_i2c_probe,
+ .probe = pcm186x_i2c_probe,
.id_table = pcm186x_i2c_id,
.driver = {
.name = "pcm186x",
diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c
index dd21803ba13c..451a8fd8fac5 100644
--- a/sound/soc/codecs/pcm186x.c
+++ b/sound/soc/codecs/pcm186x.c
@@ -12,7 +12,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <linux/slab.h>
diff --git a/sound/soc/codecs/pcm3060-i2c.c b/sound/soc/codecs/pcm3060-i2c.c
index 2388098eeca3..5330cf46b127 100644
--- a/sound/soc/codecs/pcm3060-i2c.c
+++ b/sound/soc/codecs/pcm3060-i2c.c
@@ -49,7 +49,7 @@ static struct i2c_driver pcm3060_i2c_driver = {
#endif /* CONFIG_OF */
},
.id_table = pcm3060_i2c_id,
- .probe_new = pcm3060_i2c_probe,
+ .probe = pcm3060_i2c_probe,
};
module_i2c_driver(pcm3060_i2c_driver);
diff --git a/sound/soc/codecs/pcm3168a-i2c.c b/sound/soc/codecs/pcm3168a-i2c.c
index a0eec82e9872..7052cc0c97d1 100644
--- a/sound/soc/codecs/pcm3168a-i2c.c
+++ b/sound/soc/codecs/pcm3168a-i2c.c
@@ -44,7 +44,7 @@ static const struct of_device_id pcm3168a_of_match[] = {
MODULE_DEVICE_TABLE(of, pcm3168a_of_match);
static struct i2c_driver pcm3168a_i2c_driver = {
- .probe_new = pcm3168a_i2c_probe,
+ .probe = pcm3168a_i2c_probe,
.remove = pcm3168a_i2c_remove,
.id_table = pcm3168a_i2c_id,
.driver = {
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c
index 9dfbbe8f4a0b..5cd2b64b9337 100644
--- a/sound/soc/codecs/pcm512x-i2c.c
+++ b/sound/soc/codecs/pcm512x-i2c.c
@@ -66,7 +66,7 @@ MODULE_DEVICE_TABLE(acpi, pcm512x_acpi_match);
#endif
static struct i2c_driver pcm512x_i2c_driver = {
- .probe_new = pcm512x_i2c_probe,
+ .probe = pcm512x_i2c_probe,
.remove = pcm512x_i2c_remove,
.id_table = pcm512x_i2c_id,
.driver = {
diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c
index 1d523bfd9d84..9697aefc6e03 100644
--- a/sound/soc/codecs/rk3328_codec.c
+++ b/sound/soc/codecs/rk3328_codec.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <sound/dmaengine_pcm.h>
diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c
index c1568216126e..42bac8150f62 100644
--- a/sound/soc/codecs/rt1011.c
+++ b/sound/soc/codecs/rt1011.c
@@ -2184,7 +2184,7 @@ static const struct regmap_config rt1011_regmap = {
.max_register = RT1011_MAX_REG + 1,
.volatile_reg = rt1011_volatile_register,
.readable_reg = rt1011_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt1011_reg,
.num_reg_defaults = ARRAY_SIZE(rt1011_reg),
.use_single_read = true,
@@ -2483,7 +2483,7 @@ static struct i2c_driver rt1011_i2c_driver = {
.of_match_table = of_match_ptr(rt1011_of_match),
.acpi_match_table = ACPI_PTR(rt1011_acpi_match)
},
- .probe_new = rt1011_i2c_probe,
+ .probe = rt1011_i2c_probe,
.shutdown = rt1011_i2c_shutdown,
.id_table = rt1011_i2c_id,
};
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c
index 57d0f1c69e46..38d9f69b08d6 100644
--- a/sound/soc/codecs/rt1015.c
+++ b/sound/soc/codecs/rt1015.c
@@ -1170,7 +1170,7 @@ static struct i2c_driver rt1015_i2c_driver = {
.of_match_table = of_match_ptr(rt1015_of_match),
.acpi_match_table = ACPI_PTR(rt1015_acpi_match),
},
- .probe_new = rt1015_i2c_probe,
+ .probe = rt1015_i2c_probe,
.shutdown = rt1015_i2c_shutdown,
.id_table = rt1015_i2c_id,
};
diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c
index 37eeec650f03..b1e69fa290b2 100644
--- a/sound/soc/codecs/rt1016.c
+++ b/sound/soc/codecs/rt1016.c
@@ -683,7 +683,7 @@ static struct i2c_driver rt1016_i2c_driver = {
.of_match_table = of_match_ptr(rt1016_of_match),
.acpi_match_table = ACPI_PTR(rt1016_acpi_match),
},
- .probe_new = rt1016_i2c_probe,
+ .probe = rt1016_i2c_probe,
.shutdown = rt1016_i2c_shutdown,
.id_table = rt1016_i2c_id,
};
diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c
index dff2596c81eb..fd55049920c1 100644
--- a/sound/soc/codecs/rt1019.c
+++ b/sound/soc/codecs/rt1019.c
@@ -535,7 +535,7 @@ static const struct regmap_config rt1019_regmap = {
.max_register = RT1019_BEEP_2,
.volatile_reg = rt1019_volatile_register,
.readable_reg = rt1019_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt1019_reg,
.num_reg_defaults = ARRAY_SIZE(rt1019_reg),
};
@@ -600,7 +600,7 @@ static struct i2c_driver rt1019_i2c_driver = {
.of_match_table = of_match_ptr(rt1019_of_match),
.acpi_match_table = ACPI_PTR(rt1019_acpi_match),
},
- .probe_new = rt1019_i2c_probe,
+ .probe = rt1019_i2c_probe,
.id_table = rt1019_i2c_id,
};
module_i2c_driver(rt1019_i2c_driver);
diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c
index 5b39a440b6dc..59895131e6e0 100644
--- a/sound/soc/codecs/rt1305.c
+++ b/sound/soc/codecs/rt1305.c
@@ -955,7 +955,7 @@ static const struct regmap_config rt1305_regmap = {
RT1305_PR_SPACING),
.volatile_reg = rt1305_volatile_register,
.readable_reg = rt1305_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt1305_reg,
.num_reg_defaults = ARRAY_SIZE(rt1305_reg),
.ranges = rt1305_ranges,
@@ -1170,7 +1170,7 @@ static struct i2c_driver rt1305_i2c_driver = {
.acpi_match_table = ACPI_PTR(rt1305_acpi_match)
#endif
},
- .probe_new = rt1305_i2c_probe,
+ .probe = rt1305_i2c_probe,
.shutdown = rt1305_i2c_shutdown,
.id_table = rt1305_i2c_id,
};
diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c
index 1797af824f60..f43520ca3187 100644
--- a/sound/soc/codecs/rt1308-sdw.c
+++ b/sound/soc/codecs/rt1308-sdw.c
@@ -68,7 +68,7 @@ static const struct regmap_config rt1308_sdw_regmap = {
.max_register = 0xcfff,
.reg_defaults = rt1308_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(rt1308_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -304,9 +304,6 @@ static int rt1308_update_status(struct sdw_slave *slave,
{
struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev);
- /* Update the status */
- rt1308->status = status;
-
if (status == SDW_SLAVE_UNATTACHED)
rt1308->hw_init = false;
@@ -314,7 +311,7 @@ static int rt1308_update_status(struct sdw_slave *slave,
* Perform initialization only if slave status is present and
* hw_init flag is false
*/
- if (rt1308->hw_init || rt1308->status != SDW_SLAVE_ATTACHED)
+ if (rt1308->hw_init || status != SDW_SLAVE_ATTACHED)
return 0;
/* perform I/O transfers required for Slave initialization */
diff --git a/sound/soc/codecs/rt1308-sdw.h b/sound/soc/codecs/rt1308-sdw.h
index 04ff18fa18e2..f816c73e247e 100644
--- a/sound/soc/codecs/rt1308-sdw.h
+++ b/sound/soc/codecs/rt1308-sdw.h
@@ -159,7 +159,6 @@ struct rt1308_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;
diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c
index d2a8e9fe3e23..9d07756cda40 100644
--- a/sound/soc/codecs/rt1308.c
+++ b/sound/soc/codecs/rt1308.c
@@ -773,7 +773,7 @@ static const struct regmap_config rt1308_regmap = {
.max_register = RT1308_MAX_REG,
.volatile_reg = rt1308_volatile_register,
.readable_reg = rt1308_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt1308_reg,
.num_reg_defaults = ARRAY_SIZE(rt1308_reg),
.use_single_read = true,
@@ -862,7 +862,7 @@ static struct i2c_driver rt1308_i2c_driver = {
.of_match_table = of_match_ptr(rt1308_of_match),
.acpi_match_table = ACPI_PTR(rt1308_acpi_match),
},
- .probe_new = rt1308_i2c_probe,
+ .probe = rt1308_i2c_probe,
.shutdown = rt1308_i2c_shutdown,
.id_table = rt1308_i2c_id,
};
diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
index 2ee5e763e345..721821d9e9af 100644
--- a/sound/soc/codecs/rt1316-sdw.c
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -188,7 +188,7 @@ static const struct regmap_config rt1316_sdw_regmap = {
.max_register = 0x4108ffff,
.reg_defaults = rt1316_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(rt1316_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -323,9 +323,6 @@ static int rt1316_update_status(struct sdw_slave *slave,
{
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;
@@ -333,7 +330,7 @@ static int rt1316_update_status(struct sdw_slave *slave,
* Perform initialization only if slave status is present and
* hw_init flag is false
*/
- if (rt1316->hw_init || rt1316->status != SDW_SLAVE_ATTACHED)
+ if (rt1316->hw_init || status != SDW_SLAVE_ATTACHED)
return 0;
/* perform I/O transfers required for Slave initialization */
diff --git a/sound/soc/codecs/rt1316-sdw.h b/sound/soc/codecs/rt1316-sdw.h
index e37121655bc1..dc1bfe40edd3 100644
--- a/sound/soc/codecs/rt1316-sdw.h
+++ b/sound/soc/codecs/rt1316-sdw.h
@@ -42,7 +42,6 @@ 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;
diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c
index 795accedc22c..16d750102c8c 100644
--- a/sound/soc/codecs/rt1318-sdw.c
+++ b/sound/soc/codecs/rt1318-sdw.c
@@ -337,7 +337,7 @@ static const struct regmap_config rt1318_sdw_regmap = {
.max_register = 0x41081488,
.reg_defaults = rt1318_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(rt1318_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -456,9 +456,6 @@ static int rt1318_update_status(struct sdw_slave *slave,
{
struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev);
- /* Update the status */
- rt1318->status = status;
-
if (status == SDW_SLAVE_UNATTACHED)
rt1318->hw_init = false;
@@ -466,7 +463,7 @@ static int rt1318_update_status(struct sdw_slave *slave,
* Perform initialization only if slave status is present and
* hw_init flag is false
*/
- if (rt1318->hw_init || rt1318->status != SDW_SLAVE_ATTACHED)
+ if (rt1318->hw_init || status != SDW_SLAVE_ATTACHED)
return 0;
/* perform I/O transfers required for Slave initialization */
diff --git a/sound/soc/codecs/rt1318-sdw.h b/sound/soc/codecs/rt1318-sdw.h
index 85918c184f16..86e83d63a017 100644
--- a/sound/soc/codecs/rt1318-sdw.h
+++ b/sound/soc/codecs/rt1318-sdw.h
@@ -88,7 +88,6 @@ struct rt1318_sdw_priv {
struct snd_soc_component *component;
struct regmap *regmap;
struct sdw_slave *sdw_slave;
- enum sdw_slave_status status;
struct sdw_bus_params params;
bool hw_init;
bool first_hw_init;
diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c
index 4667bf7561b1..9a33e3776b55 100644
--- a/sound/soc/codecs/rt274.c
+++ b/sound/soc/codecs/rt274.c
@@ -1221,7 +1221,7 @@ static struct i2c_driver rt274_i2c_driver = {
.of_match_table = of_match_ptr(rt274_of_match),
#endif
},
- .probe_new = rt274_i2c_probe,
+ .probe = rt274_i2c_probe,
.remove = rt274_i2c_remove,
.id_table = rt274_i2c_id,
};
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index ceb56647e369..981155b046fd 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -1263,7 +1263,7 @@ static struct i2c_driver rt286_i2c_driver = {
.name = "rt286",
.acpi_match_table = ACPI_PTR(rt286_acpi_match),
},
- .probe_new = rt286_i2c_probe,
+ .probe = rt286_i2c_probe,
.remove = rt286_i2c_remove,
.id_table = rt286_i2c_id,
};
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index cea26f3a02b6..8fbd25ad9b47 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -1311,7 +1311,7 @@ static struct i2c_driver rt298_i2c_driver = {
.name = "rt298",
.acpi_match_table = ACPI_PTR(rt298_acpi_match),
},
- .probe_new = rt298_i2c_probe,
+ .probe = rt298_i2c_probe,
.remove = rt298_i2c_remove,
.id_table = rt298_i2c_id,
};
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index b9bcf04d4dc9..b3aac2373357 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -1195,7 +1195,7 @@ static const struct regmap_config rt5514_regmap = {
.reg_read = rt5514_i2c_read,
.reg_write = rt5514_i2c_write,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5514_reg,
.num_reg_defaults = ARRAY_SIZE(rt5514_reg),
.use_single_read = true,
@@ -1328,7 +1328,7 @@ static struct i2c_driver rt5514_i2c_driver = {
.of_match_table = of_match_ptr(rt5514_of_match),
.pm = &rt5514_i2_pm_ops,
},
- .probe_new = rt5514_i2c_probe,
+ .probe = rt5514_i2c_probe,
.id_table = rt5514_i2c_id,
};
module_i2c_driver(rt5514_i2c_driver);
diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c
index 948abde10463..c13108b51eaf 100644
--- a/sound/soc/codecs/rt5616.c
+++ b/sound/soc/codecs/rt5616.c
@@ -1315,7 +1315,7 @@ static const struct regmap_config rt5616_regmap = {
RT5616_PR_SPACING),
.volatile_reg = rt5616_volatile_register,
.readable_reg = rt5616_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5616_reg,
.num_reg_defaults = ARRAY_SIZE(rt5616_reg),
.ranges = rt5616_ranges,
@@ -1404,7 +1404,7 @@ static struct i2c_driver rt5616_i2c_driver = {
.name = "rt5616",
.of_match_table = of_match_ptr(rt5616_of_match),
},
- .probe_new = rt5616_i2c_probe,
+ .probe = rt5616_i2c_probe,
.remove = rt5616_i2c_remove,
.shutdown = rt5616_i2c_shutdown,
.id_table = rt5616_i2c_id,
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 55c232413e2b..a64e66c2d3c4 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -1693,7 +1693,7 @@ static const struct regmap_config rt5631_regmap_config = {
.max_register = RT5631_VENDOR_ID2,
.reg_defaults = rt5631_reg,
.num_reg_defaults = ARRAY_SIZE(rt5631_reg),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -1728,7 +1728,7 @@ static struct i2c_driver rt5631_i2c_driver = {
.name = "rt5631",
.of_match_table = of_match_ptr(rt5631_i2c_dt_ids),
},
- .probe_new = rt5631_i2c_probe,
+ .probe = rt5631_i2c_probe,
.remove = rt5631_i2c_remove,
.id_table = rt5631_i2c_id,
};
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 139257055507..0ed4fa261abf 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -2949,7 +2949,7 @@ static const struct regmap_config rt5640_regmap = {
.volatile_reg = rt5640_volatile_register,
.readable_reg = rt5640_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5640_reg,
.num_reg_defaults = ARRAY_SIZE(rt5640_reg),
.ranges = rt5640_ranges,
@@ -3079,7 +3079,7 @@ static struct i2c_driver rt5640_i2c_driver = {
.acpi_match_table = ACPI_PTR(rt5640_acpi_match),
.of_match_table = of_match_ptr(rt5640_of_match),
},
- .probe_new = rt5640_i2c_probe,
+ .probe = rt5640_i2c_probe,
.id_table = rt5640_i2c_id,
};
module_i2c_driver(rt5640_i2c_driver);
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 7c7cbb6362ea..acc7fb1581b2 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3546,7 +3546,7 @@ static const struct regmap_config rt5645_regmap = {
.volatile_reg = rt5645_volatile_register,
.readable_reg = rt5645_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5645_reg,
.num_reg_defaults = ARRAY_SIZE(rt5645_reg),
.ranges = rt5645_ranges,
@@ -3563,7 +3563,7 @@ static const struct regmap_config rt5650_regmap = {
.volatile_reg = rt5645_volatile_register,
.readable_reg = rt5645_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5650_reg,
.num_reg_defaults = ARRAY_SIZE(rt5650_reg),
.ranges = rt5645_ranges,
@@ -4184,7 +4184,7 @@ static struct i2c_driver rt5645_i2c_driver = {
.of_match_table = of_match_ptr(rt5645_of_match),
.acpi_match_table = ACPI_PTR(rt5645_acpi_match),
},
- .probe_new = rt5645_i2c_probe,
+ .probe = rt5645_i2c_probe,
.remove = rt5645_i2c_remove,
.shutdown = rt5645_i2c_shutdown,
.id_table = rt5645_i2c_id,
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index df90af906563..0cee4fd1c84b 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -2172,7 +2172,7 @@ static const struct regmap_config rt5651_regmap = {
.volatile_reg = rt5651_volatile_register,
.readable_reg = rt5651_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5651_reg,
.num_reg_defaults = ARRAY_SIZE(rt5651_reg),
.ranges = rt5651_ranges,
@@ -2279,7 +2279,7 @@ static struct i2c_driver rt5651_i2c_driver = {
.acpi_match_table = ACPI_PTR(rt5651_acpi_match),
.of_match_table = of_match_ptr(rt5651_of_match),
},
- .probe_new = rt5651_i2c_probe,
+ .probe = rt5651_i2c_probe,
.id_table = rt5651_i2c_id,
};
module_i2c_driver(rt5651_i2c_driver);
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
index 5e21e3c37ab5..df6f0d769bbd 100644
--- a/sound/soc/codecs/rt5659.c
+++ b/sound/soc/codecs/rt5659.c
@@ -4141,13 +4141,9 @@ static int rt5659_i2c_probe(struct i2c_client *i2c)
regmap_write(rt5659->regmap, RT5659_RESET, 0);
/* Check if MCLK provided */
- rt5659->mclk = devm_clk_get(&i2c->dev, "mclk");
- if (IS_ERR(rt5659->mclk)) {
- if (PTR_ERR(rt5659->mclk) != -ENOENT)
- return PTR_ERR(rt5659->mclk);
- /* Otherwise mark the mclk pointer to NULL */
- rt5659->mclk = NULL;
- }
+ rt5659->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+ if (IS_ERR(rt5659->mclk))
+ return PTR_ERR(rt5659->mclk);
rt5659_calibrate(rt5659);
@@ -4340,7 +4336,7 @@ static struct i2c_driver rt5659_i2c_driver = {
.of_match_table = of_match_ptr(rt5659_of_match),
.acpi_match_table = ACPI_PTR(rt5659_acpi_match),
},
- .probe_new = rt5659_i2c_probe,
+ .probe = rt5659_i2c_probe,
.shutdown = rt5659_i2c_shutdown,
.id_table = rt5659_i2c_id,
};
diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c
index 341baa29fdb1..eade087b2d8b 100644
--- a/sound/soc/codecs/rt5660.c
+++ b/sound/soc/codecs/rt5660.c
@@ -1221,7 +1221,7 @@ static const struct regmap_config rt5660_regmap = {
.volatile_reg = rt5660_volatile_register,
.readable_reg = rt5660_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5660_reg,
.num_reg_defaults = ARRAY_SIZE(rt5660_reg),
.ranges = rt5660_ranges,
@@ -1341,7 +1341,7 @@ static struct i2c_driver rt5660_i2c_driver = {
.acpi_match_table = ACPI_PTR(rt5660_acpi_match),
.of_match_table = of_match_ptr(rt5660_of_match),
},
- .probe_new = rt5660_i2c_probe,
+ .probe = rt5660_i2c_probe,
.id_table = rt5660_i2c_id,
};
module_i2c_driver(rt5660_i2c_driver);
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index f73751dbde30..77246f84de29 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -3268,7 +3268,7 @@ static const struct regmap_config rt5663_v2_regmap = {
.max_register = 0x07fa,
.volatile_reg = rt5663_v2_volatile_register,
.readable_reg = rt5663_v2_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5663_v2_reg,
.num_reg_defaults = ARRAY_SIZE(rt5663_v2_reg),
};
@@ -3281,7 +3281,7 @@ static const struct regmap_config rt5663_regmap = {
.max_register = 0x03f3,
.volatile_reg = rt5663_volatile_register,
.readable_reg = rt5663_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5663_reg,
.num_reg_defaults = ARRAY_SIZE(rt5663_reg),
};
@@ -3733,7 +3733,7 @@ static struct i2c_driver rt5663_i2c_driver = {
.acpi_match_table = ACPI_PTR(rt5663_acpi_match),
.of_match_table = of_match_ptr(rt5663_of_match),
},
- .probe_new = rt5663_i2c_probe,
+ .probe = rt5663_i2c_probe,
.remove = rt5663_i2c_remove,
.shutdown = rt5663_i2c_shutdown,
.id_table = rt5663_i2c_id,
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index 17afaef85c77..83c367af91da 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -4626,7 +4626,7 @@ static const struct regmap_config rt5665_regmap = {
.max_register = 0x0400,
.volatile_reg = rt5665_volatile_register,
.readable_reg = rt5665_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5665_reg,
.num_reg_defaults = ARRAY_SIZE(rt5665_reg),
.use_single_read = true,
@@ -4968,7 +4968,7 @@ static struct i2c_driver rt5665_i2c_driver = {
.of_match_table = of_match_ptr(rt5665_of_match),
.acpi_match_table = ACPI_PTR(rt5665_acpi_match),
},
- .probe_new = rt5665_i2c_probe,
+ .probe = rt5665_i2c_probe,
.shutdown = rt5665_i2c_shutdown,
.id_table = rt5665_i2c_id,
};
diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c
index ecf3b0527dbe..f04c810fd710 100644
--- a/sound/soc/codecs/rt5668.c
+++ b/sound/soc/codecs/rt5668.c
@@ -2370,7 +2370,7 @@ static const struct regmap_config rt5668_regmap = {
.max_register = RT5668_I2C_MODE,
.volatile_reg = rt5668_volatile_register,
.readable_reg = rt5668_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5668_reg,
.num_reg_defaults = ARRAY_SIZE(rt5668_reg),
.use_single_read = true,
@@ -2618,7 +2618,7 @@ static struct i2c_driver rt5668_i2c_driver = {
.of_match_table = of_match_ptr(rt5668_of_match),
.acpi_match_table = ACPI_PTR(rt5668_acpi_match),
},
- .probe_new = rt5668_i2c_probe,
+ .probe = rt5668_i2c_probe,
.shutdown = rt5668_i2c_shutdown,
.id_table = rt5668_i2c_id,
};
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index a230f441559a..0e34293f3395 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -2863,7 +2863,7 @@ static const struct regmap_config rt5670_regmap = {
RT5670_PR_SPACING),
.volatile_reg = rt5670_volatile_register,
.readable_reg = rt5670_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5670_reg,
.num_reg_defaults = ARRAY_SIZE(rt5670_reg),
.ranges = rt5670_ranges,
@@ -3328,7 +3328,7 @@ static struct i2c_driver rt5670_i2c_driver = {
.name = "rt5670",
.acpi_match_table = ACPI_PTR(rt5670_acpi_match),
},
- .probe_new = rt5670_i2c_probe,
+ .probe = rt5670_i2c_probe,
.remove = rt5670_i2c_remove,
.id_table = rt5670_i2c_id,
};
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 3bf019b3f700..ad14d18860fc 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -5704,7 +5704,7 @@ static struct i2c_driver rt5677_i2c_driver = {
.of_match_table = rt5677_of_match,
.acpi_match_table = ACPI_PTR(rt5677_acpi_match),
},
- .probe_new = rt5677_i2c_probe,
+ .probe = rt5677_i2c_probe,
.remove = rt5677_i2c_remove,
};
module_i2c_driver(rt5677_i2c_driver);
@@ -5712,3 +5712,5 @@ module_i2c_driver(rt5677_i2c_driver);
MODULE_DESCRIPTION("ASoC RT5677 driver");
MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
MODULE_LICENSE("GPL v2");
+
+MODULE_FIRMWARE("rt5677_elf_vad");
diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c
index 5bc46b041786..fb8ffb5b2ff6 100644
--- a/sound/soc/codecs/rt5682-i2c.c
+++ b/sound/soc/codecs/rt5682-i2c.c
@@ -11,7 +11,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/pm_runtime.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
@@ -47,7 +46,7 @@ static const struct regmap_config rt5682_regmap = {
.max_register = RT5682_I2C_MODE,
.volatile_reg = rt5682_volatile_register,
.readable_reg = rt5682_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5682_reg,
.num_reg_defaults = RT5682_REG_NUM,
.use_single_read = true,
@@ -334,7 +333,7 @@ static struct i2c_driver rt5682_i2c_driver = {
.acpi_match_table = rt5682_acpi_match,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
- .probe_new = rt5682_i2c_probe,
+ .probe = rt5682_i2c_probe,
.remove = rt5682_i2c_remove,
.shutdown = rt5682_i2c_shutdown,
.id_table = rt5682_i2c_id,
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index 23f17f70d7e9..67404f45389f 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -79,7 +79,7 @@ static const struct regmap_config rt5682_sdw_indirect_regmap = {
.max_register = RT5682_I2C_MODE,
.volatile_reg = rt5682_volatile_register,
.readable_reg = rt5682_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5682_reg,
.num_reg_defaults = RT5682_REG_NUM,
.use_single_read = true,
@@ -500,9 +500,6 @@ static int rt5682_update_status(struct sdw_slave *slave,
{
struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev);
- /* Update the status */
- rt5682->status = status;
-
if (status == SDW_SLAVE_UNATTACHED)
rt5682->hw_init = false;
@@ -510,7 +507,7 @@ static int rt5682_update_status(struct sdw_slave *slave,
* Perform initialization only if slave status is present and
* hw_init flag is false
*/
- if (rt5682->hw_init || rt5682->status != SDW_SLAVE_ATTACHED)
+ if (rt5682->hw_init || status != SDW_SLAVE_ATTACHED)
return 0;
/* perform I/O transfers required for Slave initialization */
diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
index e8efd8a84a6c..1a43d595f341 100644
--- a/sound/soc/codecs/rt5682.h
+++ b/sound/soc/codecs/rt5682.h
@@ -1440,7 +1440,6 @@ struct rt5682_priv {
bool disable_irq;
struct mutex calibrate_mutex;
struct sdw_slave *slave;
- enum sdw_slave_status status;
struct sdw_bus_params params;
bool hw_init;
bool first_hw_init;
diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c
index 9c34dca58f54..c77c675bd5f5 100644
--- a/sound/soc/codecs/rt5682s.c
+++ b/sound/soc/codecs/rt5682s.c
@@ -11,7 +11,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/pm_runtime.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
@@ -2848,14 +2847,9 @@ static int rt5682s_dai_probe_clks(struct snd_soc_component *component)
int ret;
/* Check if MCLK provided */
- rt5682s->mclk = devm_clk_get(component->dev, "mclk");
- if (IS_ERR(rt5682s->mclk)) {
- if (PTR_ERR(rt5682s->mclk) != -ENOENT) {
- ret = PTR_ERR(rt5682s->mclk);
- return ret;
- }
- rt5682s->mclk = NULL;
- }
+ rt5682s->mclk = devm_clk_get_optional(component->dev, "mclk");
+ if (IS_ERR(rt5682s->mclk))
+ return PTR_ERR(rt5682s->mclk);
/* Register CCF DAI clock control */
ret = rt5682s_register_dai_clks(component);
@@ -3046,7 +3040,7 @@ static const struct regmap_config rt5682s_regmap = {
.max_register = RT5682S_MAX_REG,
.volatile_reg = rt5682s_volatile_register,
.readable_reg = rt5682s_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5682s_reg,
.num_reg_defaults = ARRAY_SIZE(rt5682s_reg),
.use_single_read = true,
@@ -3316,7 +3310,7 @@ static struct i2c_driver rt5682s_i2c_driver = {
.acpi_match_table = rt5682s_acpi_match,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
- .probe_new = rt5682s_i2c_probe,
+ .probe = rt5682s_i2c_probe,
.remove = rt5682s_i2c_remove,
.shutdown = rt5682s_i2c_shutdown,
.id_table = rt5682s_i2c_id,
diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c
index 96fc5f36d0d0..8b28e47775cc 100644
--- a/sound/soc/codecs/rt700-sdw.c
+++ b/sound/soc/codecs/rt700-sdw.c
@@ -292,7 +292,7 @@ static const struct regmap_config rt700_regmap = {
.max_register = 0x755800,
.reg_defaults = rt700_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(rt700_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
.reg_read = rt700_sdw_read,
@@ -315,9 +315,6 @@ static int rt700_update_status(struct sdw_slave *slave,
{
struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev);
- /* Update the status */
- rt700->status = status;
-
if (status == SDW_SLAVE_UNATTACHED)
rt700->hw_init = false;
@@ -325,7 +322,7 @@ static int rt700_update_status(struct sdw_slave *slave,
* Perform initialization only if slave status is present and
* hw_init flag is false
*/
- if (rt700->hw_init || rt700->status != SDW_SLAVE_ATTACHED)
+ if (rt700->hw_init || status != SDW_SLAVE_ATTACHED)
return 0;
/* perform I/O transfers required for Slave initialization */
diff --git a/sound/soc/codecs/rt700.h b/sound/soc/codecs/rt700.h
index 93c44005d38c..491774d207de 100644
--- a/sound/soc/codecs/rt700.h
+++ b/sound/soc/codecs/rt700.h
@@ -15,7 +15,6 @@ struct rt700_priv {
struct regmap *regmap;
struct regmap *sdw_regmap;
struct sdw_slave *slave;
- enum sdw_slave_status status;
struct sdw_bus_params params;
bool hw_init;
bool first_hw_init;
diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c
index 51f3335343e0..119e1f9605d7 100644
--- a/sound/soc/codecs/rt711-sdca-sdw.c
+++ b/sound/soc/codecs/rt711-sdca-sdw.c
@@ -119,7 +119,7 @@ static const struct regmap_config rt711_sdca_regmap = {
.max_register = 0x44ffffff,
.reg_defaults = rt711_sdca_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(rt711_sdca_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -133,7 +133,7 @@ static const struct regmap_config rt711_sdca_mbq_regmap = {
.max_register = 0x40800f12,
.reg_defaults = rt711_sdca_mbq_defaults,
.num_reg_defaults = ARRAY_SIZE(rt711_sdca_mbq_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -143,9 +143,6 @@ static int rt711_sdca_update_status(struct sdw_slave *slave,
{
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;
@@ -168,7 +165,7 @@ static int rt711_sdca_update_status(struct sdw_slave *slave,
* Perform initialization only if slave status is present and
* hw_init flag is false
*/
- if (rt711->hw_init || rt711->status != SDW_SLAVE_ATTACHED)
+ if (rt711->hw_init || status != SDW_SLAVE_ATTACHED)
return 0;
/* perform I/O transfers required for Slave initialization */
diff --git a/sound/soc/codecs/rt711-sdca.h b/sound/soc/codecs/rt711-sdca.h
index 22076f268577..11d421e8ab2b 100644
--- a/sound/soc/codecs/rt711-sdca.h
+++ b/sound/soc/codecs/rt711-sdca.h
@@ -19,7 +19,6 @@ 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;
diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c
index 4fe68bcf2a7c..87dafcb4545d 100644
--- a/sound/soc/codecs/rt711-sdw.c
+++ b/sound/soc/codecs/rt711-sdw.c
@@ -296,7 +296,7 @@ static const struct regmap_config rt711_regmap = {
.max_register = 0x755800,
.reg_defaults = rt711_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(rt711_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
.reg_read = rt711_sdw_read,
@@ -319,9 +319,6 @@ static int rt711_update_status(struct sdw_slave *slave,
{
struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev);
- /* Update the status */
- rt711->status = status;
-
if (status == SDW_SLAVE_UNATTACHED)
rt711->hw_init = false;
@@ -329,7 +326,7 @@ static int rt711_update_status(struct sdw_slave *slave,
* Perform initialization only if slave status is present and
* hw_init flag is false
*/
- if (rt711->hw_init || rt711->status != SDW_SLAVE_ATTACHED)
+ if (rt711->hw_init || status != SDW_SLAVE_ATTACHED)
return 0;
/* perform I/O transfers required for Slave initialization */
diff --git a/sound/soc/codecs/rt711.h b/sound/soc/codecs/rt711.h
index b31351f11df9..491e357191f9 100644
--- a/sound/soc/codecs/rt711.h
+++ b/sound/soc/codecs/rt711.h
@@ -15,7 +15,6 @@ struct rt711_priv {
struct regmap *sdw_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;
diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c
index 09807b6d6353..869cc7bfd178 100644
--- a/sound/soc/codecs/rt712-sdca-dmic.c
+++ b/sound/soc/codecs/rt712-sdca-dmic.c
@@ -110,7 +110,7 @@ static const struct regmap_config rt712_sdca_dmic_regmap = {
.max_register = 0x40981300,
.reg_defaults = rt712_sdca_dmic_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(rt712_sdca_dmic_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -124,7 +124,7 @@ static const struct regmap_config rt712_sdca_dmic_mbq_regmap = {
.max_register = 0x40800f14,
.reg_defaults = rt712_sdca_dmic_mbq_defaults,
.num_reg_defaults = ARRAY_SIZE(rt712_sdca_dmic_mbq_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -803,9 +803,6 @@ static int rt712_sdca_dmic_update_status(struct sdw_slave *slave,
{
struct rt712_sdca_dmic_priv *rt712 = dev_get_drvdata(&slave->dev);
- /* Update the status */
- rt712->status = status;
-
if (status == SDW_SLAVE_UNATTACHED)
rt712->hw_init = false;
@@ -813,7 +810,7 @@ static int rt712_sdca_dmic_update_status(struct sdw_slave *slave,
* Perform initialization only if slave status is present and
* hw_init flag is false
*/
- if (rt712->hw_init || rt712->status != SDW_SLAVE_ATTACHED)
+ if (rt712->hw_init || status != SDW_SLAVE_ATTACHED)
return 0;
/* perform I/O transfers required for Slave initialization */
diff --git a/sound/soc/codecs/rt712-sdca-dmic.h b/sound/soc/codecs/rt712-sdca-dmic.h
index 74c29677c251..110154e74efe 100644
--- a/sound/soc/codecs/rt712-sdca-dmic.h
+++ b/sound/soc/codecs/rt712-sdca-dmic.h
@@ -16,7 +16,6 @@ struct rt712_sdca_dmic_priv {
struct 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;
diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c
index 3f319459dfec..ad06267b0ea0 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -116,7 +116,7 @@ static const struct regmap_config rt712_sdca_regmap = {
.max_register = 0x44ffffff,
.reg_defaults = rt712_sdca_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(rt712_sdca_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -130,7 +130,7 @@ static const struct regmap_config rt712_sdca_mbq_regmap = {
.max_register = 0x41000312,
.reg_defaults = rt712_sdca_mbq_defaults,
.num_reg_defaults = ARRAY_SIZE(rt712_sdca_mbq_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -140,9 +140,6 @@ static int rt712_sdca_update_status(struct sdw_slave *slave,
{
struct rt712_sdca_priv *rt712 = dev_get_drvdata(&slave->dev);
- /* Update the status */
- rt712->status = status;
-
if (status == SDW_SLAVE_UNATTACHED)
rt712->hw_init = false;
@@ -165,7 +162,7 @@ static int rt712_sdca_update_status(struct sdw_slave *slave,
* Perform initialization only if slave status is present and
* hw_init flag is false
*/
- if (rt712->hw_init || rt712->status != SDW_SLAVE_ATTACHED)
+ if (rt712->hw_init || status != SDW_SLAVE_ATTACHED)
return 0;
/* perform I/O transfers required for Slave initialization */
diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h
index c6a94a23f46e..ff79e03118ce 100644
--- a/sound/soc/codecs/rt712-sdca.h
+++ b/sound/soc/codecs/rt712-sdca.h
@@ -20,7 +20,6 @@ struct rt712_sdca_priv {
struct 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;
diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c
index 38a82e4e2f95..df10916bab46 100644
--- a/sound/soc/codecs/rt715-sdca-sdw.c
+++ b/sound/soc/codecs/rt715-sdca-sdw.c
@@ -97,7 +97,7 @@ static const struct regmap_config rt715_sdca_regmap = {
.max_register = 0x43ffffff,
.reg_defaults = rt715_reg_defaults_sdca,
.num_reg_defaults = ARRAY_SIZE(rt715_reg_defaults_sdca),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -111,7 +111,7 @@ static const struct regmap_config rt715_sdca_mbq_regmap = {
.max_register = 0x43ffffff,
.reg_defaults = rt715_mbq_reg_defaults_sdca,
.num_reg_defaults = ARRAY_SIZE(rt715_mbq_reg_defaults_sdca),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@@ -121,14 +121,11 @@ static int rt715_sdca_update_status(struct sdw_slave *slave,
{
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)
+ if (rt715->hw_init || status != SDW_SLAVE_ATTACHED)
return 0;
/* perform I/O transfers required for Slave initialization */
diff --git a/sound/soc/codecs/rt715-sdca.h b/sound/soc/codecs/rt715-sdca.h
index 7577f3151934..e5d6928ecaba 100644
--- a/sound/soc/codecs/rt715-sdca.h
+++ b/sound/soc/codecs/rt715-sdca.h
@@ -24,7 +24,6 @@ struct rt715_sdca_priv {
int dbg_nid;
int dbg_vid;
int dbg_payload;
- enum sdw_slave_status status;
struct sdw_bus_params params;
bool hw_init;
bool first_hw_init;
diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c
index 4e61e16470ed..6db87442b783 100644
--- a/sound/soc/codecs/rt715-sdw.c
+++ b/sound/soc/codecs/rt715-sdw.c
@@ -354,7 +354,7 @@ static const struct regmap_config rt715_regmap = {
.max_register = 0x752039, /* Maximum number of register */
.reg_defaults = rt715_reg_defaults, /* Defaults */
.num_reg_defaults = ARRAY_SIZE(rt715_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
.reg_read = rt715_sdw_read,
@@ -417,13 +417,11 @@ static int rt715_update_status(struct sdw_slave *slave,
{
struct rt715_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)
+ if (rt715->hw_init || status != SDW_SLAVE_ATTACHED)
return 0;
/* perform I/O transfers required for Slave initialization */
diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h
index 17a8d041c1c3..12a0ae656d09 100644
--- a/sound/soc/codecs/rt715.h
+++ b/sound/soc/codecs/rt715.h
@@ -18,7 +18,6 @@ struct rt715_priv {
int dbg_nid;
int dbg_vid;
int dbg_payload;
- enum sdw_slave_status status;
struct sdw_bus_params params;
bool hw_init;
bool first_hw_init;
diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
new file mode 100644
index 000000000000..cc57e4e27805
--- /dev/null
+++ b/sound/soc/codecs/rt722-sdca-sdw.c
@@ -0,0 +1,507 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt722-sdca-sdw.c -- rt722 SDCA ALSA SoC audio driver
+//
+// Copyright(c) 2023 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm_runtime.h>
+#include <linux/soundwire/sdw_registers.h>
+
+#include "rt722-sdca.h"
+#include "rt722-sdca-sdw.h"
+
+static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f01 ... 0x2f0a:
+ case 0x2f35 ... 0x2f36:
+ case 0x2f50:
+ case 0x2f54:
+ case 0x2f58 ... 0x2f5d:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_SELECTED_MODE,
+ 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE,
+ 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER,
+ 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt722_sdca_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f01:
+ case 0x2f54:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE,
+ 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER,
+ 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2000000 ... 0x2000024:
+ case 0x2000029 ... 0x200004a:
+ case 0x2000051 ... 0x2000052:
+ case 0x200005a ... 0x200005b:
+ case 0x2000061 ... 0x2000069:
+ case 0x200006b:
+ case 0x2000070:
+ case 0x200007f:
+ case 0x2000082 ... 0x200008e:
+ case 0x2000090 ... 0x2000094:
+ case 0x5300000 ... 0x5300002:
+ case 0x5400002:
+ case 0x5600000 ... 0x5600007:
+ case 0x5700000 ... 0x5700004:
+ case 0x5800000 ... 0x5800004:
+ case 0x5b00003:
+ case 0x5c00011:
+ case 0x5d00006:
+ case 0x5f00000 ... 0x5f0000d:
+ case 0x5f00030:
+ case 0x6100000 ... 0x6100051:
+ case 0x6100055 ... 0x6100057:
+ case 0x6100062:
+ case 0x6100064 ... 0x6100065:
+ case 0x6100067:
+ case 0x6100070 ... 0x610007c:
+ case 0x6100080:
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_03):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_04):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME,
+ CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME,
+ CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME,
+ CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME,
+ CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44,
+ RT722_SDCA_CTL_FU_CH_GAIN, CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44,
+ RT722_SDCA_CTL_FU_CH_GAIN, CH_R):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt722_sdca_mbq_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2000000:
+ case 0x200000d:
+ case 0x2000019:
+ case 0x2000020:
+ case 0x2000030:
+ case 0x2000046:
+ case 0x2000067:
+ case 0x2000084:
+ case 0x2000086:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rt722_sdca_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt722_sdca_readable_register,
+ .volatile_reg = rt722_sdca_volatile_register,
+ .max_register = 0x44ffffff,
+ .reg_defaults = rt722_sdca_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt722_sdca_reg_defaults),
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static const struct regmap_config rt722_sdca_mbq_regmap = {
+ .name = "sdw-mbq",
+ .reg_bits = 32,
+ .val_bits = 16,
+ .readable_reg = rt722_sdca_mbq_readable_register,
+ .volatile_reg = rt722_sdca_mbq_volatile_register,
+ .max_register = 0x41000312,
+ .reg_defaults = rt722_sdca_mbq_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt722_sdca_mbq_defaults),
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt722_sdca_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt722_sdca_priv *rt722 = dev_get_drvdata(&slave->dev);
+
+ if (status == SDW_SLAVE_UNATTACHED)
+ rt722->hw_init = false;
+
+ if (status == SDW_SLAVE_ATTACHED) {
+ if (rt722->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 rt722_sdca_jack_init set.
+ */
+ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6);
+ sdw_write_no_pm(rt722->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 (rt722->hw_init || status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt722_sdca_io_init(&slave->dev, slave);
+}
+
+static int rt722_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->paging_support = true;
+
+ /*
+ * port = 1 for headphone playback
+ * port = 2 for headset-mic capture
+ * port = 3 for speaker playback
+ * port = 6 for digital-mic capture
+ */
+ prop->source_ports = BIT(6) | BIT(2); /* BITMAP: 01000100 */
+ prop->sink_ports = BIT(3) | BIT(1); /* BITMAP: 00001010 */
+
+ 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 = 200;
+
+ /* wake-up event */
+ prop->wake_capable = 1;
+
+ return 0;
+}
+
+static int rt722_sdca_interrupt_callback(struct sdw_slave *slave,
+ struct sdw_slave_intr_status *status)
+{
+ struct rt722_sdca_priv *rt722 = dev_get_drvdata(&slave->dev);
+ int ret, stat;
+ int count = 0, retry = 3;
+ unsigned int sdca_cascade, scp_sdca_stat1, scp_sdca_stat2 = 0;
+
+ if (cancel_delayed_work_sync(&rt722->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 (rt722->scp_sdca_stat2)
+ scp_sdca_stat2 = rt722->scp_sdca_stat2;
+ }
+
+ /*
+ * The critical section below intentionally protects a rather large piece of code.
+ * We don't want to allow the system suspend to disable an interrupt while we are
+ * processing it, which could be problematic given the quirky SoundWire interrupt
+ * scheme. We do want however to prevent new workqueues from being scheduled if
+ * the disable_irq flag was set during system suspend.
+ */
+ mutex_lock(&rt722->disable_irq_lock);
+
+ ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT1);
+ if (ret < 0)
+ goto io_error;
+ rt722->scp_sdca_stat1 = ret;
+ ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT2);
+ if (ret < 0)
+ goto io_error;
+ rt722->scp_sdca_stat2 = ret;
+ if (scp_sdca_stat2)
+ rt722->scp_sdca_stat2 |= scp_sdca_stat2;
+ do {
+ /* clear flag */
+ ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT1);
+ if (ret < 0)
+ goto io_error;
+ if (ret & SDW_SCP_SDCA_INTMASK_SDCA_0) {
+ ret = sdw_update_no_pm(rt722->slave, SDW_SCP_SDCA_INT1,
+ SDW_SCP_SDCA_INT_SDCA_0, SDW_SCP_SDCA_INT_SDCA_0);
+ if (ret < 0)
+ goto io_error;
+ } else if (ret & SDW_SCP_SDCA_INTMASK_SDCA_6) {
+ ret = sdw_update_no_pm(rt722->slave, SDW_SCP_SDCA_INT1,
+ SDW_SCP_SDCA_INT_SDCA_6, SDW_SCP_SDCA_INT_SDCA_6);
+ if (ret < 0)
+ goto io_error;
+ }
+ ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT2);
+ if (ret < 0)
+ goto io_error;
+ if (ret & SDW_SCP_SDCA_INTMASK_SDCA_8) {
+ ret = sdw_write_no_pm(rt722->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(rt722->slave, SDW_DP0_INT);
+ if (ret < 0)
+ goto io_error;
+ sdca_cascade = ret & SDW_DP0_SDCA_CASCADE;
+
+ ret = sdw_read_no_pm(rt722->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(rt722->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__,
+ rt722->scp_sdca_stat1, rt722->scp_sdca_stat2);
+
+ if (status->sdca_cascade && !rt722->disable_irq)
+ mod_delayed_work(system_power_efficient_wq,
+ &rt722->jack_detect_work, msecs_to_jiffies(30));
+
+ mutex_unlock(&rt722->disable_irq_lock);
+
+ return 0;
+
+io_error:
+ mutex_unlock(&rt722->disable_irq_lock);
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+ return ret;
+}
+
+static struct sdw_slave_ops rt722_sdca_slave_ops = {
+ .read_prop = rt722_sdca_read_prop,
+ .interrupt_callback = rt722_sdca_interrupt_callback,
+ .update_status = rt722_sdca_update_status,
+};
+
+static int rt722_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, &rt722_sdca_mbq_regmap);
+ if (IS_ERR(mbq_regmap))
+ return PTR_ERR(mbq_regmap);
+
+ regmap = devm_regmap_init_sdw(slave, &rt722_sdca_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt722_sdca_init(&slave->dev, regmap, mbq_regmap, slave);
+}
+
+static int rt722_sdca_sdw_remove(struct sdw_slave *slave)
+{
+ struct rt722_sdca_priv *rt722 = dev_get_drvdata(&slave->dev);
+
+ if (rt722->hw_init) {
+ cancel_delayed_work_sync(&rt722->jack_detect_work);
+ cancel_delayed_work_sync(&rt722->jack_btn_check_work);
+ }
+
+ if (rt722->first_hw_init)
+ pm_runtime_disable(&slave->dev);
+
+ mutex_destroy(&rt722->calibrate_mutex);
+ mutex_destroy(&rt722->disable_irq_lock);
+
+ return 0;
+}
+
+static const struct sdw_device_id rt722_sdca_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x722, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt722_sdca_id);
+
+static int __maybe_unused rt722_sdca_dev_suspend(struct device *dev)
+{
+ struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev);
+
+ if (!rt722->hw_init)
+ return 0;
+
+ cancel_delayed_work_sync(&rt722->jack_detect_work);
+ cancel_delayed_work_sync(&rt722->jack_btn_check_work);
+
+ regcache_cache_only(rt722->regmap, true);
+ regcache_cache_only(rt722->mbq_regmap, true);
+
+ return 0;
+}
+
+static int __maybe_unused rt722_sdca_dev_system_suspend(struct device *dev)
+{
+ struct rt722_sdca_priv *rt722_sdca = dev_get_drvdata(dev);
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ int ret1, ret2;
+
+ if (!rt722_sdca->hw_init)
+ return 0;
+
+ /*
+ * prevent new interrupts from being handled after the
+ * deferred work completes and before the parent disables
+ * interrupts on the link
+ */
+ mutex_lock(&rt722_sdca->disable_irq_lock);
+ rt722_sdca->disable_irq = true;
+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6, 0);
+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
+ mutex_unlock(&rt722_sdca->disable_irq_lock);
+
+ if (ret1 < 0 || ret2 < 0) {
+ /* log but don't prevent suspend from happening */
+ dev_dbg(&slave->dev, "%s: could not disable SDCA interrupts\n:", __func__);
+ }
+
+ return rt722_sdca_dev_suspend(dev);
+}
+
+#define RT722_PROBE_TIMEOUT 5000
+
+static int __maybe_unused rt722_sdca_dev_resume(struct device *dev)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev);
+ unsigned long time;
+
+ if (!rt722->first_hw_init)
+ return 0;
+
+ if (!slave->unattach_request)
+ goto regmap_sync;
+
+ time = wait_for_completion_timeout(&slave->initialization_complete,
+ msecs_to_jiffies(RT722_PROBE_TIMEOUT));
+ if (!time) {
+ dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ sdw_show_ping_status(slave->bus, true);
+
+ return -ETIMEDOUT;
+ }
+
+regmap_sync:
+ slave->unattach_request = 0;
+ regcache_cache_only(rt722->regmap, false);
+ regcache_sync(rt722->regmap);
+ regcache_cache_only(rt722->mbq_regmap, false);
+ regcache_sync(rt722->mbq_regmap);
+ return 0;
+}
+
+static const struct dev_pm_ops rt722_sdca_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rt722_sdca_dev_system_suspend, rt722_sdca_dev_resume)
+ SET_RUNTIME_PM_OPS(rt722_sdca_dev_suspend, rt722_sdca_dev_resume, NULL)
+};
+
+static struct sdw_driver rt722_sdca_sdw_driver = {
+ .driver = {
+ .name = "rt722-sdca",
+ .owner = THIS_MODULE,
+ .pm = &rt722_sdca_pm,
+ },
+ .probe = rt722_sdca_sdw_probe,
+ .remove = rt722_sdca_sdw_remove,
+ .ops = &rt722_sdca_slave_ops,
+ .id_table = rt722_sdca_id,
+};
+module_sdw_driver(rt722_sdca_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT722 SDCA SDW driver");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt722-sdca-sdw.h b/sound/soc/codecs/rt722-sdca-sdw.h
new file mode 100644
index 000000000000..5b43e86f75d1
--- /dev/null
+++ b/sound/soc/codecs/rt722-sdca-sdw.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt722-sdca-sdw.h -- RT722 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2023 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT722_SDW_H__
+#define __RT722_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw_registers.h>
+
+static const struct reg_default rt722_sdca_reg_defaults[] = {
+ { 0x202d, 0x00 },
+ { 0x2f01, 0x00 },
+ { 0x2f02, 0x09 },
+ { 0x2f03, 0x00 },
+ { 0x2f04, 0x00 },
+ { 0x2f05, 0x0b },
+ { 0x2f06, 0x01 },
+ { 0x2f08, 0x00 },
+ { 0x2f09, 0x00 },
+ { 0x2f0a, 0x00 },
+ { 0x2f35, 0x00 },
+ { 0x2f36, 0x00 },
+ { 0x2f50, 0xf0 },
+ { 0x2f58, 0x07 },
+ { 0x2f59, 0x07 },
+ { 0x2f5a, 0x07 },
+ { 0x2f5b, 0x07 },
+ { 0x2f5c, 0x27 },
+ { 0x2f5d, 0x07 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX,
+ 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX,
+ 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, RT722_SDCA_CTL_REQ_POWER_STATE,
+ 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, RT722_SDCA_CTL_REQ_POWER_STATE,
+ 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_MUTE, CH_L),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_MUTE, CH_R),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_MUTE, CH_L),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_MUTE, CH_R),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX,
+ 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_01),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_02),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_03),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_04),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, RT722_SDCA_CTL_REQ_POWER_STATE, 0),
+ 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26, RT722_SDCA_CTL_VENDOR_DEF, 0),
+ 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_MUTE, CH_L),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_MUTE, CH_R),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, RT722_SDCA_CTL_REQ_POWER_STATE, 0),
+ 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23, RT722_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
+};
+
+static const struct reg_default rt722_sdca_mbq_defaults[] = {
+ { 0x200003c, 0xc214 },
+ { 0x2000046, 0x8004 },
+ { 0x6100006, 0x0005 },
+ { 0x6100010, 0x2630 },
+ { 0x6100011, 0x152f },
+ { 0x6100013, 0x0102 },
+ { 0x6100015, 0x2200 },
+ { 0x6100017, 0x0102 },
+ { 0x6100025, 0x2a29 },
+ { 0x6100026, 0x2a00 },
+ { 0x6100028, 0x2a2a },
+ { 0x6100029, 0x4141 },
+ { 0x6100055, 0x0000 },
+ { 0x5810000, 0x702d },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME,
+ CH_L), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME,
+ CH_R), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME,
+ CH_L), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME,
+ CH_R), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, RT722_SDCA_CTL_FU_CH_GAIN,
+ CH_L), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, RT722_SDCA_CTL_FU_CH_GAIN,
+ CH_R), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_03), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_04), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_01),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_02),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_03),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_04),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_L),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_R),
+ 0x0000 },
+};
+
+#endif /* __RT722_SDW_H__ */
diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c
new file mode 100644
index 000000000000..9c0d34366c9e
--- /dev/null
+++ b/sound/soc/codecs/rt722-sdca.c
@@ -0,0 +1,1555 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt722-sdca.c -- rt722 SDCA ALSA SoC audio driver
+//
+// Copyright(c) 2023 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/bitops.h>
+#include <sound/core.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <sound/initval.h>
+#include <sound/jack.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <sound/pcm.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm_params.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/slab.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "rt722-sdca.h"
+
+int rt722_sdca_index_write(struct rt722_sdca_priv *rt722,
+ unsigned int nid, unsigned int reg, unsigned int value)
+{
+ struct regmap *regmap = rt722->mbq_regmap;
+ unsigned int addr = (nid << 20) | reg;
+ int ret;
+
+ ret = regmap_write(regmap, addr, value);
+ if (ret < 0)
+ dev_err(&rt722->slave->dev,
+ "Failed to set private value: %06x <= %04x ret=%d\n",
+ addr, value, ret);
+
+ return ret;
+}
+
+int rt722_sdca_index_read(struct rt722_sdca_priv *rt722,
+ unsigned int nid, unsigned int reg, unsigned int *value)
+{
+ int ret;
+ struct regmap *regmap = rt722->mbq_regmap;
+ unsigned int addr = (nid << 20) | reg;
+
+ ret = regmap_read(regmap, addr, value);
+ if (ret < 0)
+ dev_err(&rt722->slave->dev,
+ "Failed to get private value: %06x => %04x ret=%d\n",
+ addr, *value, ret);
+
+ return ret;
+}
+
+static int rt722_sdca_index_update_bits(struct rt722_sdca_priv *rt722,
+ unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val)
+{
+ unsigned int tmp;
+ int ret;
+
+ ret = rt722_sdca_index_read(rt722, nid, reg, &tmp);
+ if (ret < 0)
+ return ret;
+
+ set_mask_bits(&tmp, mask, val);
+ return rt722_sdca_index_write(rt722, nid, reg, tmp);
+}
+
+static int rt722_sdca_btn_type(unsigned char *buffer)
+{
+ if ((*buffer & 0xf0) == 0x10 || (*buffer & 0x0f) == 0x01 || (*(buffer + 1) == 0x01) ||
+ (*(buffer + 1) == 0x10))
+ return SND_JACK_BTN_2;
+ else if ((*buffer & 0xf0) == 0x20 || (*buffer & 0x0f) == 0x02 || (*(buffer + 1) == 0x02) ||
+ (*(buffer + 1) == 0x20))
+ return SND_JACK_BTN_3;
+ else if ((*buffer & 0xf0) == 0x40 || (*buffer & 0x0f) == 0x04 || (*(buffer + 1) == 0x04) ||
+ (*(buffer + 1) == 0x40))
+ return SND_JACK_BTN_0;
+ else if ((*buffer & 0xf0) == 0x80 || (*buffer & 0x0f) == 0x08 || (*(buffer + 1) == 0x08) ||
+ (*(buffer + 1) == 0x80))
+ return SND_JACK_BTN_1;
+
+ return 0;
+}
+
+static unsigned int rt722_sdca_button_detect(struct rt722_sdca_priv *rt722)
+{
+ unsigned int btn_type = 0, offset, idx, val, owner;
+ int ret;
+ unsigned char buf[3];
+
+ /* get current UMP message owner */
+ ret = regmap_read(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_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(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset);
+ if (ret < 0)
+ goto _end_btn_det_;
+
+ for (idx = 0; idx < sizeof(buf); idx++) {
+ ret = regmap_read(rt722->regmap,
+ RT722_BUF_ADDR_HID1 + offset + idx, &val);
+ if (ret < 0)
+ goto _end_btn_det_;
+ buf[idx] = val & 0xff;
+ }
+
+ if (buf[0] == 0x11)
+ btn_type = rt722_sdca_btn_type(&buf[1]);
+
+_end_btn_det_:
+ /* Host is owner, so set back to device */
+ if (owner == 0)
+ /* set owner to device */
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01);
+
+ return btn_type;
+}
+
+static int rt722_sdca_headset_detect(struct rt722_sdca_priv *rt722)
+{
+ unsigned int det_mode;
+ int ret;
+
+ /* get detected_mode */
+ ret = regmap_read(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49,
+ RT722_SDCA_CTL_DETECTED_MODE, 0), &det_mode);
+ if (ret < 0)
+ goto io_error;
+
+ switch (det_mode) {
+ case 0x00:
+ rt722->jack_type = 0;
+ break;
+ case 0x03:
+ rt722->jack_type = SND_JACK_HEADPHONE;
+ break;
+ case 0x05:
+ rt722->jack_type = SND_JACK_HEADSET;
+ break;
+ }
+
+ /* write selected_mode */
+ if (det_mode) {
+ ret = regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49,
+ RT722_SDCA_CTL_SELECTED_MODE, 0), det_mode);
+ if (ret < 0)
+ goto io_error;
+ }
+
+ dev_dbg(&rt722->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 rt722_sdca_jack_detect_handler(struct work_struct *work)
+{
+ struct rt722_sdca_priv *rt722 =
+ container_of(work, struct rt722_sdca_priv, jack_detect_work.work);
+ int btn_type = 0, ret;
+
+ if (!rt722->hs_jack)
+ return;
+
+ if (!rt722->component->card || !rt722->component->card->instantiated)
+ return;
+
+ /* SDW_SCP_SDCA_INT_SDCA_6 is used for jack detection */
+ if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_6 ||
+ rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) {
+ ret = rt722_sdca_headset_detect(rt722);
+ if (ret < 0)
+ return;
+ }
+
+ /* SDW_SCP_SDCA_INT_SDCA_8 is used for button detection */
+ if (rt722->scp_sdca_stat2 & SDW_SCP_SDCA_INT_SDCA_8)
+ btn_type = rt722_sdca_button_detect(rt722);
+
+ if (rt722->jack_type == 0)
+ btn_type = 0;
+
+ dev_dbg(&rt722->slave->dev,
+ "in %s, jack_type=%d\n", __func__, rt722->jack_type);
+ dev_dbg(&rt722->slave->dev,
+ "in %s, btn_type=0x%x\n", __func__, btn_type);
+ dev_dbg(&rt722->slave->dev,
+ "in %s, scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__,
+ rt722->scp_sdca_stat1, rt722->scp_sdca_stat2);
+
+ snd_soc_jack_report(rt722->hs_jack, rt722->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(rt722->hs_jack, rt722->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,
+ &rt722->jack_btn_check_work, msecs_to_jiffies(200));
+ }
+}
+
+static void rt722_sdca_btn_check_handler(struct work_struct *work)
+{
+ struct rt722_sdca_priv *rt722 =
+ container_of(work, struct rt722_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(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49,
+ RT722_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(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset);
+ if (ret < 0)
+ goto io_error;
+
+ for (idx = 0; idx < sizeof(buf); idx++) {
+ ret = regmap_read(rt722->regmap,
+ RT722_BUF_ADDR_HID1 + offset + idx, &val);
+ if (ret < 0)
+ goto io_error;
+ buf[idx] = val & 0xff;
+ }
+
+ if (buf[0] == 0x11)
+ btn_type = rt722_sdca_btn_type(&buf[1]);
+ } else
+ rt722->jack_type = 0;
+
+ dev_dbg(&rt722->slave->dev, "%s, btn_type=0x%x\n", __func__, btn_type);
+ snd_soc_jack_report(rt722->hs_jack, rt722->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(rt722->hs_jack, rt722->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,
+ &rt722->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 rt722_sdca_jack_init(struct rt722_sdca_priv *rt722)
+{
+ mutex_lock(&rt722->calibrate_mutex);
+ if (rt722->hs_jack) {
+ /* set SCP_SDCA_IntMask1[0]=1 */
+ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6);
+ /* set SCP_SDCA_IntMask2[0]=1 */
+ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8);
+ dev_dbg(&rt722->slave->dev, "in %s enable\n", __func__);
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_HDA_LEGACY_UNSOL_CTL, 0x016E);
+ /* set XU(et03h) & XU(et0Dh) to Not bypassed */
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU03,
+ RT722_SDCA_CTL_SELECTED_MODE, 0), 0);
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU0D,
+ RT722_SDCA_CTL_SELECTED_MODE, 0), 0);
+ /* trigger GE interrupt */
+ rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_GE_RELATED_CTL2, 0x4000, 0x4000);
+ }
+ mutex_unlock(&rt722->calibrate_mutex);
+}
+
+static int rt722_sdca_set_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *hs_jack, void *data)
+{
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ rt722->hs_jack = hs_jack;
+
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret < 0) {
+ if (ret != -EACCES) {
+ dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
+ return ret;
+ }
+ /* pm_runtime not enabled yet */
+ dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
+ return 0;
+ }
+
+ rt722_sdca_jack_init(rt722);
+
+ pm_runtime_mark_last_busy(component->dev);
+ pm_runtime_put_autosuspend(component->dev);
+
+ return 0;
+}
+
+/* For SDCA control DAC/ADC Gain */
+static int rt722_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned int read_l, read_r, gain_l_val, gain_r_val;
+ unsigned int adc_vol_flag = 0, changed = 0;
+ unsigned int lvalue, rvalue;
+ const unsigned int interval_offset = 0xc0;
+ const unsigned int tendB = 0xa00;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume") ||
+ strstr(ucontrol->id.name, "FU0F Capture Volume"))
+ adc_vol_flag = 1;
+
+ regmap_read(rt722->mbq_regmap, mc->reg, &lvalue);
+ regmap_read(rt722->mbq_regmap, mc->rreg, &rvalue);
+
+ /* L Channel */
+ gain_l_val = ucontrol->value.integer.value[0];
+ if (gain_l_val > mc->max)
+ gain_l_val = mc->max;
+
+ if (mc->shift == 8) /* boost gain */
+ gain_l_val = gain_l_val * tendB;
+ else {
+ /* ADC/DAC gain */
+ if (adc_vol_flag)
+ gain_l_val = 0x1e00 - ((mc->max - gain_l_val) * interval_offset);
+ else
+ gain_l_val = 0 - ((mc->max - gain_l_val) * interval_offset);
+ gain_l_val &= 0xffff;
+ }
+
+ /* R Channel */
+ gain_r_val = ucontrol->value.integer.value[1];
+ if (gain_r_val > mc->max)
+ gain_r_val = mc->max;
+
+ if (mc->shift == 8) /* boost gain */
+ gain_r_val = gain_r_val * tendB;
+ else {
+ /* ADC/DAC gain */
+ if (adc_vol_flag)
+ gain_r_val = 0x1e00 - ((mc->max - gain_r_val) * interval_offset);
+ else
+ gain_r_val = 0 - ((mc->max - gain_r_val) * interval_offset);
+ gain_r_val &= 0xffff;
+ }
+
+ if (lvalue != gain_l_val || rvalue != gain_r_val)
+ changed = 1;
+ else
+ return 0;
+
+ /* Lch*/
+ regmap_write(rt722->mbq_regmap, mc->reg, gain_l_val);
+
+ /* Rch */
+ regmap_write(rt722->mbq_regmap, mc->rreg, gain_r_val);
+
+ regmap_read(rt722->mbq_regmap, mc->reg, &read_l);
+ regmap_read(rt722->mbq_regmap, mc->rreg, &read_r);
+ if (read_r == gain_r_val && read_l == gain_l_val)
+ return changed;
+
+ return -EIO;
+}
+
+static int rt722_sdca_set_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt722_sdca_priv *rt722 = 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;
+ const unsigned int interval_offset = 0xc0;
+ const unsigned int tendB = 0xa00;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume") ||
+ strstr(ucontrol->id.name, "FU0F Capture Volume"))
+ adc_vol_flag = 1;
+
+ regmap_read(rt722->mbq_regmap, mc->reg, &read_l);
+ regmap_read(rt722->mbq_regmap, mc->rreg, &read_r);
+
+ if (mc->shift == 8) /* boost gain */
+ ctl_l = read_l / tendB;
+ else {
+ if (adc_vol_flag)
+ ctl_l = mc->max - (((0x1e00 - read_l) & 0xffff) / interval_offset);
+ else
+ ctl_l = mc->max - (((0 - read_l) & 0xffff) / interval_offset);
+ }
+
+ if (read_l != read_r) {
+ if (mc->shift == 8) /* boost gain */
+ ctl_r = read_r / tendB;
+ else { /* ADC/DAC gain */
+ if (adc_vol_flag)
+ ctl_r = mc->max - (((0x1e00 - read_r) & 0xffff) / interval_offset);
+ else
+ ctl_r = mc->max - (((0 - read_r) & 0xffff) / interval_offset);
+ }
+ } else {
+ ctl_r = ctl_l;
+ }
+
+ ucontrol->value.integer.value[0] = ctl_l;
+ ucontrol->value.integer.value[1] = ctl_r;
+
+ return 0;
+}
+
+static int rt722_sdca_set_fu1e_capture_ctl(struct rt722_sdca_priv *rt722)
+{
+ int err, i;
+ unsigned int ch_mute;
+
+ for (i = 0; i < ARRAY_SIZE(rt722->fu1e_mixer_mute); i++) {
+ ch_mute = rt722->fu1e_dapm_mute || rt722->fu1e_mixer_mute[i];
+ err = regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E,
+ RT722_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int rt722_sdca_fu1e_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ struct rt722_sdca_dmic_kctrl_priv *p =
+ (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ unsigned int i;
+
+ for (i = 0; i < p->count; i++)
+ ucontrol->value.integer.value[i] = !rt722->fu1e_mixer_mute[i];
+
+ return 0;
+}
+
+static int rt722_sdca_fu1e_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ struct rt722_sdca_dmic_kctrl_priv *p =
+ (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ int err, changed = 0, i;
+
+ for (i = 0; i < p->count; i++) {
+ if (rt722->fu1e_mixer_mute[i] != !ucontrol->value.integer.value[i])
+ changed = 1;
+ rt722->fu1e_mixer_mute[i] = !ucontrol->value.integer.value[i];
+ }
+
+ err = rt722_sdca_set_fu1e_capture_ctl(rt722);
+ if (err < 0)
+ return err;
+
+ return changed;
+}
+
+static int rt722_sdca_set_fu0f_capture_ctl(struct rt722_sdca_priv *rt722)
+{
+ int err;
+ unsigned int ch_l, ch_r;
+
+ ch_l = (rt722->fu0f_dapm_mute || rt722->fu0f_mixer_l_mute) ? 0x01 : 0x00;
+ ch_r = (rt722->fu0f_dapm_mute || rt722->fu0f_mixer_r_mute) ? 0x01 : 0x00;
+
+ err = regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F,
+ RT722_SDCA_CTL_FU_MUTE, CH_L), ch_l);
+ if (err < 0)
+ return err;
+
+ err = regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F,
+ RT722_SDCA_CTL_FU_MUTE, CH_R), ch_r);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int rt722_sdca_fu0f_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = !rt722->fu0f_mixer_l_mute;
+ ucontrol->value.integer.value[1] = !rt722->fu0f_mixer_r_mute;
+ return 0;
+}
+
+static int rt722_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ int err, changed = 0;
+
+ if (rt722->fu0f_mixer_l_mute != !ucontrol->value.integer.value[0] ||
+ rt722->fu0f_mixer_r_mute != !ucontrol->value.integer.value[1])
+ changed = 1;
+
+ rt722->fu0f_mixer_l_mute = !ucontrol->value.integer.value[0];
+ rt722->fu0f_mixer_r_mute = !ucontrol->value.integer.value[1];
+ err = rt722_sdca_set_fu0f_capture_ctl(rt722);
+ if (err < 0)
+ return err;
+
+ return changed;
+}
+
+static int rt722_sdca_fu_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct rt722_sdca_dmic_kctrl_priv *p =
+ (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+
+ if (p->max == 1)
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = p->count;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = p->max;
+ return 0;
+}
+
+static int rt722_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ struct rt722_sdca_dmic_kctrl_priv *p =
+ (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ unsigned int boost_step = 0x0a00;
+ unsigned int vol_max = 0x1e00;
+ unsigned int regvalue, ctl, i;
+ unsigned int adc_vol_flag = 0;
+ const unsigned int interval_offset = 0xc0;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume"))
+ adc_vol_flag = 1;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ regmap_read(rt722->mbq_regmap, p->reg_base + i, &regvalue);
+
+ if (!adc_vol_flag) /* boost gain */
+ ctl = regvalue / boost_step;
+ else { /* ADC gain */
+ if (adc_vol_flag)
+ ctl = p->max - (((vol_max - regvalue) & 0xffff) / interval_offset);
+ else
+ ctl = p->max - (((0 - regvalue) & 0xffff) / interval_offset);
+ }
+
+ ucontrol->value.integer.value[i] = ctl;
+ }
+
+ return 0;
+}
+
+static int rt722_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt722_sdca_dmic_kctrl_priv *p =
+ (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned int boost_step = 0x0a00;
+ unsigned int vol_max = 0x1e00;
+ unsigned int gain_val[4];
+ unsigned int i, adc_vol_flag = 0, changed = 0;
+ unsigned int regvalue[4];
+ const unsigned int interval_offset = 0xc0;
+ int err;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume"))
+ adc_vol_flag = 1;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ regmap_read(rt722->mbq_regmap, p->reg_base + i, &regvalue[i]);
+
+ gain_val[i] = ucontrol->value.integer.value[i];
+ if (gain_val[i] > p->max)
+ gain_val[i] = p->max;
+
+ if (!adc_vol_flag) /* boost gain */
+ gain_val[i] = gain_val[i] * boost_step;
+ else { /* ADC gain */
+ gain_val[i] = vol_max - ((p->max - gain_val[i]) * interval_offset);
+ gain_val[i] &= 0xffff;
+ }
+
+ if (regvalue[i] != gain_val[i])
+ changed = 1;
+ }
+
+ if (!changed)
+ return 0;
+
+ for (i = 0; i < p->count; i++) {
+ err = regmap_write(rt722->mbq_regmap, p->reg_base + i, gain_val[i]);
+ if (err < 0)
+ dev_err(&rt722->slave->dev, "%#08x can't be set\n", p->reg_base + i);
+ }
+
+ return changed;
+}
+
+#define RT722_SDCA_PR_VALUE(xreg_base, xcount, xmax, xinvert) \
+ ((unsigned long)&(struct rt722_sdca_dmic_kctrl_priv) \
+ {.reg_base = xreg_base, .count = xcount, .max = xmax, \
+ .invert = xinvert})
+
+#define RT722_SDCA_FU_CTRL(xname, reg_base, xmax, xinvert, xcount) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .info = rt722_sdca_fu_info, \
+ .get = rt722_sdca_fu1e_capture_get, \
+ .put = rt722_sdca_fu1e_capture_put, \
+ .private_value = RT722_SDCA_PR_VALUE(reg_base, xcount, xmax, xinvert)}
+
+#define RT722_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\
+ xhandler_put, xcount, xmax, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .tlv.p = (tlv_array), \
+ .info = rt722_sdca_fu_info, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = RT722_SDCA_PR_VALUE(reg_base, xcount, xmax, 0) }
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(boost_vol_tlv, 0, 1000, 0);
+
+static const struct snd_kcontrol_new rt722_sdca_controls[] = {
+ /* Headphone playback settings */
+ SOC_DOUBLE_R_EXT_TLV("FU05 Playback Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x57, 0,
+ rt722_sdca_set_gain_get, rt722_sdca_set_gain_put, out_vol_tlv),
+ /* Headset mic capture settings */
+ SOC_DOUBLE_EXT("FU0F Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0,
+ rt722_sdca_fu0f_capture_get, rt722_sdca_fu0f_capture_put),
+ SOC_DOUBLE_R_EXT_TLV("FU0F Capture Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F,
+ RT722_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F,
+ RT722_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x3f, 0,
+ rt722_sdca_set_gain_get, rt722_sdca_set_gain_put, mic_vol_tlv),
+ SOC_DOUBLE_R_EXT_TLV("FU33 Boost Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44,
+ RT722_SDCA_CTL_FU_CH_GAIN, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44,
+ RT722_SDCA_CTL_FU_CH_GAIN, CH_R), 8, 3, 0,
+ rt722_sdca_set_gain_get, rt722_sdca_set_gain_put, boost_vol_tlv),
+ /* AMP playback settings */
+ SOC_DOUBLE_R_EXT_TLV("FU06 Playback Volume",
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x57, 0,
+ rt722_sdca_set_gain_get, rt722_sdca_set_gain_put, out_vol_tlv),
+ /* DMIC capture settings */
+ RT722_SDCA_FU_CTRL("FU1E Capture Switch",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E,
+ RT722_SDCA_CTL_FU_MUTE, CH_01), 1, 1, 4),
+ RT722_SDCA_EXT_TLV("FU1E Capture Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E,
+ RT722_SDCA_CTL_FU_VOLUME, CH_01),
+ rt722_sdca_dmic_set_gain_get, rt722_sdca_dmic_set_gain_put,
+ 4, 0x3f, mic_vol_tlv),
+ RT722_SDCA_EXT_TLV("FU15 Boost Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15,
+ RT722_SDCA_CTL_FU_CH_GAIN, CH_01),
+ rt722_sdca_dmic_set_gain_get, rt722_sdca_dmic_set_gain_put,
+ 4, 3, boost_vol_tlv),
+};
+
+static int rt722_sdca_adc_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_kcontrol_component(kcontrol);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned int val = 0, mask_sft;
+
+ if (strstr(ucontrol->id.name, "ADC 22 Mux"))
+ mask_sft = 12;
+ 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;
+
+ rt722_sdca_index_read(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_HDA_LEGACY_MUX_CTL0, &val);
+
+ ucontrol->value.enumerated.item[0] = (val >> mask_sft) & 0x7;
+
+ return 0;
+}
+
+static int rt722_sdca_adc_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 rt722_sdca_priv *rt722 = 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 24 Mux"))
+ mask_sft = 4;
+ else if (strstr(ucontrol->id.name, "ADC 25 Mux"))
+ mask_sft = 0;
+ else
+ return -EINVAL;
+
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+
+ rt722_sdca_index_read(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_HDA_LEGACY_MUX_CTL0, &val2);
+ val2 = (0x7 << mask_sft) & val2;
+
+ if (val == val2)
+ change = 0;
+ else
+ change = 1;
+
+ if (change)
+ rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_HDA_LEGACY_MUX_CTL0, 0x7 << mask_sft,
+ val << mask_sft);
+
+ snd_soc_dapm_mux_update_power(dapm, kcontrol,
+ item[0], e, NULL);
+
+ return change;
+}
+
+static const char * const adc22_mux_text[] = {
+ "MIC2",
+ "LINE1",
+ "LINE2",
+};
+
+static const char * const adc07_10_mux_text[] = {
+ "DMIC1",
+ "DMIC2",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt722_adc22_enum, SND_SOC_NOPM, 0, adc22_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt722_adc24_enum, SND_SOC_NOPM, 0, adc07_10_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt722_adc25_enum, SND_SOC_NOPM, 0, adc07_10_mux_text);
+
+static const struct snd_kcontrol_new rt722_sdca_adc22_mux =
+ SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt722_adc22_enum,
+ rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put);
+
+static const struct snd_kcontrol_new rt722_sdca_adc24_mux =
+ SOC_DAPM_ENUM_EXT("ADC 24 Mux", rt722_adc24_enum,
+ rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put);
+
+static const struct snd_kcontrol_new rt722_sdca_adc25_mux =
+ SOC_DAPM_ENUM_EXT("ADC 25 Mux", rt722_adc25_enum,
+ rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put);
+
+static int rt722_sdca_fu42_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned char unmute = 0x0, mute = 0x1;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_MUTE, CH_L), unmute);
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_MUTE, CH_R), unmute);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_MUTE, CH_L), mute);
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_MUTE, CH_R), mute);
+ break;
+ }
+ return 0;
+}
+
+static int rt722_sdca_fu21_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned char unmute = 0x0, mute = 0x1;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_MUTE, CH_L), unmute);
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_MUTE, CH_R), unmute);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_MUTE, CH_L), mute);
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_MUTE, CH_R), mute);
+ break;
+ }
+ return 0;
+}
+
+static int rt722_sdca_fu113_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt722->fu1e_dapm_mute = false;
+ rt722_sdca_set_fu1e_capture_ctl(rt722);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt722->fu1e_dapm_mute = true;
+ rt722_sdca_set_fu1e_capture_ctl(rt722);
+ break;
+ }
+ return 0;
+}
+
+static int rt722_sdca_fu36_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt722->fu0f_dapm_mute = false;
+ rt722_sdca_set_fu0f_capture_ctl(rt722);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt722->fu0f_dapm_mute = true;
+ rt722_sdca_set_fu0f_capture_ctl(rt722);
+ break;
+ }
+ return 0;
+}
+
+static int rt722_sdca_pde47_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt722_sdca_pde23_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt722_sdca_pde11_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt722_sdca_pde12_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt722_sdca_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("HP"),
+ SND_SOC_DAPM_OUTPUT("SPK"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("LINE1"),
+ SND_SOC_DAPM_INPUT("LINE2"),
+ SND_SOC_DAPM_INPUT("DMIC1_2"),
+ SND_SOC_DAPM_INPUT("DMIC3_4"),
+
+ SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0,
+ rt722_sdca_pde23_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 47", SND_SOC_NOPM, 0, 0,
+ rt722_sdca_pde47_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0,
+ rt722_sdca_pde11_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 12", SND_SOC_NOPM, 0, 0,
+ rt722_sdca_pde12_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_DAC_E("FU 21", NULL, SND_SOC_NOPM, 0, 0,
+ rt722_sdca_fu21_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("FU 42", NULL, SND_SOC_NOPM, 0, 0,
+ rt722_sdca_fu42_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("FU 36", NULL, SND_SOC_NOPM, 0, 0,
+ rt722_sdca_fu36_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("FU 113", NULL, SND_SOC_NOPM, 0, 0,
+ rt722_sdca_fu113_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0,
+ &rt722_sdca_adc22_mux),
+ SND_SOC_DAPM_MUX("ADC 24 Mux", SND_SOC_NOPM, 0, 0,
+ &rt722_sdca_adc24_mux),
+ SND_SOC_DAPM_MUX("ADC 25 Mux", SND_SOC_NOPM, 0, 0,
+ &rt722_sdca_adc25_mux),
+
+ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Headphone Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Headset Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Speaker Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP6TX", "DP6 DMic Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt722_sdca_audio_map[] = {
+ {"FU 42", NULL, "DP1RX"},
+ {"FU 21", NULL, "DP3RX"},
+
+ {"ADC 22 Mux", "MIC2", "MIC2"},
+ {"ADC 22 Mux", "LINE1", "LINE1"},
+ {"ADC 22 Mux", "LINE2", "LINE2"},
+ {"ADC 24 Mux", "DMIC1", "DMIC1_2"},
+ {"ADC 24 Mux", "DMIC2", "DMIC3_4"},
+ {"ADC 25 Mux", "DMIC1", "DMIC1_2"},
+ {"ADC 25 Mux", "DMIC2", "DMIC3_4"},
+ {"FU 36", NULL, "PDE 12"},
+ {"FU 36", NULL, "ADC 22 Mux"},
+ {"FU 113", NULL, "PDE 11"},
+ {"FU 113", NULL, "ADC 24 Mux"},
+ {"FU 113", NULL, "ADC 25 Mux"},
+ {"DP2TX", NULL, "FU 36"},
+ {"DP6TX", NULL, "FU 113"},
+
+ {"HP", NULL, "PDE 47"},
+ {"HP", NULL, "FU 42"},
+ {"SPK", NULL, "PDE 23"},
+ {"SPK", NULL, "FU 21"},
+};
+
+static int rt722_sdca_parse_dt(struct rt722_sdca_priv *rt722, struct device *dev)
+{
+ device_property_read_u32(dev, "realtek,jd-src", &rt722->jd_src);
+
+ return 0;
+}
+
+static int rt722_sdca_probe(struct snd_soc_component *component)
+{
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ rt722_sdca_parse_dt(rt722, &rt722->slave->dev);
+ rt722->component = component;
+
+ ret = pm_runtime_resume(component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_sdca_dev_rt722 = {
+ .probe = rt722_sdca_probe,
+ .controls = rt722_sdca_controls,
+ .num_controls = ARRAY_SIZE(rt722_sdca_controls),
+ .dapm_widgets = rt722_sdca_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt722_sdca_dapm_widgets),
+ .dapm_routes = rt722_sdca_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rt722_sdca_audio_map),
+ .set_jack = rt722_sdca_set_jack_detect,
+ .endianness = 1,
+};
+
+static int rt722_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+ int direction)
+{
+ snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+
+ return 0;
+}
+
+static void rt722_sdca_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int rt722_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 rt722_sdca_priv *rt722 = 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_runtime *sdw_stream;
+ int retval, port, num_channels;
+ unsigned int sampling_rate;
+
+ dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+ sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ if (!rt722->slave)
+ return -EINVAL;
+
+ /*
+ * RT722_AIF1 with port = 1 for headphone playback
+ * RT722_AIF1 with port = 2 for headset-mic capture
+ * RT722_AIF2 with port = 3 for speaker playback
+ * RT722_AIF3 with port = 6 for digital-mic capture
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ direction = SDW_DATA_DIR_RX;
+ if (dai->id == RT722_AIF1)
+ port = 1;
+ else if (dai->id == RT722_AIF2)
+ port = 3;
+ else
+ return -EINVAL;
+ } else {
+ direction = SDW_DATA_DIR_TX;
+ if (dai->id == RT722_AIF1)
+ port = 2;
+ else if (dai->id == RT722_AIF3)
+ port = 6;
+ 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(rt722->slave, &stream_config,
+ &port_config, 1, 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 = RT722_SDCA_RATE_44100HZ;
+ break;
+ case 48000:
+ sampling_rate = RT722_SDCA_RATE_48000HZ;
+ break;
+ case 96000:
+ sampling_rate = RT722_SDCA_RATE_96000HZ;
+ break;
+ case 192000:
+ sampling_rate = RT722_SDCA_RATE_192000HZ;
+ break;
+ default:
+ dev_err(component->dev, "Rate %d is not supported\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ /* set sampling frequency */
+ if (dai->id == RT722_AIF1) {
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+ }
+
+ if (dai->id == RT722_AIF2)
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+
+ if (dai->id == RT722_AIF3)
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+
+ return 0;
+}
+
+static int rt722_sdca_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_runtime *sdw_stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt722->slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt722->slave, sdw_stream);
+ return 0;
+}
+
+#define RT722_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define RT722_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops rt722_sdca_ops = {
+ .hw_params = rt722_sdca_pcm_hw_params,
+ .hw_free = rt722_sdca_pcm_hw_free,
+ .set_stream = rt722_sdca_set_sdw_stream,
+ .shutdown = rt722_sdca_shutdown,
+};
+
+static struct snd_soc_dai_driver rt722_sdca_dai[] = {
+ {
+ .name = "rt722-sdca-aif1",
+ .id = RT722_AIF1,
+ .playback = {
+ .stream_name = "DP1 Headphone Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT722_STEREO_RATES,
+ .formats = RT722_FORMATS,
+ },
+ .capture = {
+ .stream_name = "DP2 Headset Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT722_STEREO_RATES,
+ .formats = RT722_FORMATS,
+ },
+ .ops = &rt722_sdca_ops,
+ },
+ {
+ .name = "rt722-sdca-aif2",
+ .id = RT722_AIF2,
+ .playback = {
+ .stream_name = "DP3 Speaker Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT722_STEREO_RATES,
+ .formats = RT722_FORMATS,
+ },
+ .ops = &rt722_sdca_ops,
+ },
+ {
+ .name = "rt722-sdca-aif3",
+ .id = RT722_AIF3,
+ .capture = {
+ .stream_name = "DP6 DMic Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT722_STEREO_RATES,
+ .formats = RT722_FORMATS,
+ },
+ .ops = &rt722_sdca_ops,
+ }
+};
+
+int rt722_sdca_init(struct device *dev, struct regmap *regmap,
+ struct regmap *mbq_regmap, struct sdw_slave *slave)
+{
+ struct rt722_sdca_priv *rt722;
+
+ rt722 = devm_kzalloc(dev, sizeof(*rt722), GFP_KERNEL);
+ if (!rt722)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt722);
+ rt722->slave = slave;
+ rt722->regmap = regmap;
+ rt722->mbq_regmap = mbq_regmap;
+
+ mutex_init(&rt722->calibrate_mutex);
+ mutex_init(&rt722->disable_irq_lock);
+
+ INIT_DELAYED_WORK(&rt722->jack_detect_work, rt722_sdca_jack_detect_handler);
+ INIT_DELAYED_WORK(&rt722->jack_btn_check_work, rt722_sdca_btn_check_handler);
+
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt722->hw_init = false;
+ rt722->first_hw_init = false;
+ rt722->fu1e_dapm_mute = true;
+ rt722->fu0f_dapm_mute = true;
+ rt722->fu0f_mixer_l_mute = rt722->fu0f_mixer_r_mute = true;
+ rt722->fu1e_mixer_mute[0] = rt722->fu1e_mixer_mute[1] =
+ rt722->fu1e_mixer_mute[2] = rt722->fu1e_mixer_mute[3] = true;
+
+ return devm_snd_soc_register_component(dev,
+ &soc_sdca_dev_rt722, rt722_sdca_dai, ARRAY_SIZE(rt722_sdca_dai));
+}
+
+static void rt722_sdca_dmic_preset(struct rt722_sdca_priv *rt722)
+{
+ /* Set AD07 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_ADC0A_08_PDE_FLOAT_CTL, 0x2a29);
+ /* Set AD10 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_ADC10_PDE_FLOAT_CTL, 0x2a00);
+ /* Set DMIC1/DMIC2 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_DMIC1_2_PDE_FLOAT_CTL, 0x2a2a);
+ /* Set DMIC2 IT entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_DMIC_ENT_FLOAT_CTL, 0x2626);
+ /* Set AD10 FU entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_ADC_ENT_FLOAT_CTL, 0x1e00);
+ /* Set DMIC2 FU entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_DMIC_GAIN_ENT_FLOAT_CTL0, 0x1515);
+ /* Set AD10 FU channel floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_ADC_VOL_CH_FLOAT_CTL, 0x0304);
+ /* Set DMIC2 FU channel floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_DMIC_GAIN_ENT_FLOAT_CTL2, 0x0304);
+ /* vf71f_r12_07_06 and vf71f_r13_07_06 = 2’b00 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_HDA_LEGACY_CONFIG_CTL0, 0x0000);
+ /* Enable vf707_r12_05/vf707_r13_05 */
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26,
+ RT722_SDCA_CTL_VENDOR_DEF, 0), 0x01);
+ /* Fine tune PDE2A latency */
+ regmap_write(rt722->regmap, 0x2f5c, 0x25);
+}
+
+static void rt722_sdca_amp_preset(struct rt722_sdca_priv *rt722)
+{
+ /* Set DVQ=01 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_CLSD_CTRL6,
+ 0xc215);
+ /* Reset dc_cal_top */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DC_CALIB_CTRL,
+ 0x702c);
+ /* W1C Trigger Calibration */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DC_CALIB_CTRL,
+ 0xf02d);
+ /* Set DAC02/ClassD power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_AMP_PDE_FLOAT_CTL,
+ 0x2323);
+ /* Set EAPD high */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_EAPD_CTL,
+ 0x0002);
+ /* Enable vf707_r14 */
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23,
+ RT722_SDCA_CTL_VENDOR_DEF, CH_08), 0x04);
+}
+
+static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722)
+{
+ int loop_check, chk_cnt = 100, ret;
+ unsigned int calib_status = 0;
+
+ /* Read eFuse */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_SPK_EFUSE, RT722_DC_CALIB_CTRL,
+ 0x4808);
+ /* Button A, B, C, D bypass mode */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL4,
+ 0xcf00);
+ /* HID1 slot enable */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL5,
+ 0x000f);
+ /* Report ID for HID1 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL0,
+ 0x1100);
+ /* OSC/OOC for slot 2, 3 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL7,
+ 0x0c12);
+ /* Set JD de-bounce clock control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_JD_CTRL1,
+ 0x7002);
+ /* Set DVQ=01 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_CLSD_CTRL6,
+ 0xc215);
+ /* FSM switch to calibration manual mode */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_FSM_CTL,
+ 0x4100);
+ /* W1C Trigger DC calibration (HP) */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DAC_DC_CALI_CTL3,
+ 0x008d);
+ /* check HP calibration FSM status */
+ for (loop_check = 0; loop_check < chk_cnt; loop_check++) {
+ ret = rt722_sdca_index_read(rt722, RT722_VENDOR_CALI,
+ RT722_DAC_DC_CALI_CTL3, &calib_status);
+ if (ret < 0 || loop_check == chk_cnt)
+ dev_dbg(&rt722->slave->dev, "calibration failed!, ret=%d\n", ret);
+ if ((calib_status & 0x0040) == 0x0)
+ break;
+ }
+ /* Release HP-JD, EN_CBJ_TIE_GL/R open, en_osw gating auto done bit */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_DIGITAL_MISC_CTRL4,
+ 0x0010);
+ /* Set ADC09 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ADC0A_08_PDE_FLOAT_CTL,
+ 0x2a12);
+ /* Set MIC2 and LINE1 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_MIC2_LINE2_PDE_FLOAT_CTL,
+ 0x3429);
+ /* Set ET41h and LINE2 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ET41_LINE2_PDE_FLOAT_CTL,
+ 0x4112);
+ /* Set DAC03 and HP power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_DAC03_HP_PDE_FLOAT_CTL,
+ 0x4040);
+ /* Fine tune PDE40 latency */
+ regmap_write(rt722->regmap, 0x2f58, 0x07);
+}
+
+int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev);
+
+ rt722->disable_irq = false;
+
+ if (rt722->hw_init)
+ return 0;
+
+ if (rt722->first_hw_init) {
+ regcache_cache_only(rt722->regmap, false);
+ regcache_cache_bypass(rt722->regmap, true);
+ regcache_cache_only(rt722->mbq_regmap, false);
+ regcache_cache_bypass(rt722->mbq_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);
+
+ rt722_sdca_dmic_preset(rt722);
+ rt722_sdca_amp_preset(rt722);
+ rt722_sdca_jack_preset(rt722);
+
+ if (rt722->first_hw_init) {
+ regcache_cache_bypass(rt722->regmap, false);
+ regcache_mark_dirty(rt722->regmap);
+ regcache_cache_bypass(rt722->mbq_regmap, false);
+ regcache_mark_dirty(rt722->mbq_regmap);
+ } else
+ rt722->first_hw_init = true;
+
+ /* Mark Slave initialization complete */
+ rt722->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 RT722 SDCA SDW driver");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt722-sdca.h b/sound/soc/codecs/rt722-sdca.h
new file mode 100644
index 000000000000..44af8901352e
--- /dev/null
+++ b/sound/soc/codecs/rt722-sdca.h
@@ -0,0 +1,237 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt722-sdca.h -- RT722 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2023 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT722_H__
+#define __RT722_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 rt722_sdca_priv {
+ struct regmap *regmap;
+ struct regmap *mbq_regmap;
+ struct snd_soc_component *component;
+ struct sdw_slave *slave;
+ struct sdw_bus_params params;
+ bool hw_init;
+ bool first_hw_init;
+ struct mutex calibrate_mutex;
+ struct mutex disable_irq_lock;
+ bool disable_irq;
+ /* For Headset jack & Headphone */
+ unsigned int scp_sdca_stat1;
+ unsigned int scp_sdca_stat2;
+ struct snd_soc_jack *hs_jack;
+ struct delayed_work jack_detect_work;
+ struct delayed_work jack_btn_check_work;
+ int jack_type;
+ int jd_src;
+ bool fu0f_dapm_mute;
+ bool fu0f_mixer_l_mute;
+ bool fu0f_mixer_r_mute;
+ /* For DMIC */
+ bool fu1e_dapm_mute;
+ bool fu1e_mixer_mute[4];
+};
+
+struct rt722_sdca_dmic_kctrl_priv {
+ unsigned int reg_base;
+ unsigned int count;
+ unsigned int max;
+ unsigned int invert;
+};
+
+/* NID */
+#define RT722_VENDOR_REG 0x20
+#define RT722_VENDOR_CALI 0x58
+#define RT722_VENDOR_SPK_EFUSE 0x5c
+#define RT722_VENDOR_IMS_DRE 0x5b
+#define RT722_VENDOR_ANALOG_CTL 0x5f
+#define RT722_VENDOR_HDA_CTL 0x61
+
+/* Index (NID:20h) */
+#define RT722_JD_PRODUCT_NUM 0x00
+#define RT722_ANALOG_BIAS_CTL3 0x04
+#define RT722_JD_CTRL1 0x09
+#define RT722_LDO2_3_CTL1 0x0e
+#define RT722_LDO1_CTL 0x1a
+#define RT722_HP_JD_CTRL 0x24
+#define RT722_CLSD_CTRL6 0x3c
+#define RT722_COMBO_JACK_AUTO_CTL1 0x45
+#define RT722_COMBO_JACK_AUTO_CTL2 0x46
+#define RT722_COMBO_JACK_AUTO_CTL3 0x47
+#define RT722_DIGITAL_MISC_CTRL4 0x4a
+#define RT722_FSM_CTL 0x67
+#define RT722_SDCA_INTR_REC 0x82
+#define RT722_SW_CONFIG1 0x8a
+#define RT722_SW_CONFIG2 0x8b
+
+/* Index (NID:58h) */
+#define RT722_DAC_DC_CALI_CTL0 0x00
+#define RT722_DAC_DC_CALI_CTL1 0x01
+#define RT722_DAC_DC_CALI_CTL2 0x02
+#define RT722_DAC_DC_CALI_CTL3 0x03
+
+/* Index (NID:59h) */
+#define RT722_ULTRA_SOUND_DETECTOR6 0x1e
+
+/* Index (NID:5bh) */
+#define RT722_IMS_DIGITAL_CTL1 0x00
+#define RT722_IMS_DIGITAL_CTL5 0x05
+#define RT722_HP_DETECT_RLDET_CTL1 0x29
+#define RT722_HP_DETECT_RLDET_CTL2 0x2a
+
+/* Index (NID:5fh) */
+#define RT722_MISC_POWER_CTL0 0x00
+#define RT722_MISC_POWER_CTL7 0x08
+
+/* Index (NID:61h) */
+#define RT722_HDA_LEGACY_MUX_CTL0 0x00
+#define RT722_HDA_LEGACY_UNSOL_CTL 0x03
+#define RT722_HDA_LEGACY_CONFIG_CTL0 0x06
+#define RT722_HDA_LEGACY_RESET_CTL 0x08
+#define RT722_HDA_LEGACY_GPIO_WAKE_EN_CTL 0x0e
+#define RT722_DMIC_ENT_FLOAT_CTL 0x10
+#define RT722_DMIC_GAIN_ENT_FLOAT_CTL0 0x11
+#define RT722_DMIC_GAIN_ENT_FLOAT_CTL2 0x13
+#define RT722_ADC_ENT_FLOAT_CTL 0x15
+#define RT722_ADC_VOL_CH_FLOAT_CTL 0x17
+#define RT722_ADC_SAMPLE_RATE_FLOAT 0x18
+#define RT722_DAC03_HP_PDE_FLOAT_CTL 0x22
+#define RT722_MIC2_LINE2_PDE_FLOAT_CTL 0x23
+#define RT722_ET41_LINE2_PDE_FLOAT_CTL 0x24
+#define RT722_ADC0A_08_PDE_FLOAT_CTL 0x25
+#define RT722_ADC10_PDE_FLOAT_CTL 0x26
+#define RT722_DMIC1_2_PDE_FLOAT_CTL 0x28
+#define RT722_AMP_PDE_FLOAT_CTL 0x29
+#define RT722_I2S_IN_OUT_PDE_FLOAT_CTL 0x2f
+#define RT722_GE_RELATED_CTL1 0x45
+#define RT722_GE_RELATED_CTL2 0x46
+#define RT722_MIXER_CTL0 0x52
+#define RT722_MIXER_CTL1 0x53
+#define RT722_EAPD_CTL 0x55
+#define RT722_UMP_HID_CTL0 0x60
+#define RT722_UMP_HID_CTL1 0x61
+#define RT722_UMP_HID_CTL2 0x62
+#define RT722_UMP_HID_CTL3 0x63
+#define RT722_UMP_HID_CTL4 0x64
+#define RT722_UMP_HID_CTL5 0x65
+#define RT722_UMP_HID_CTL6 0x66
+#define RT722_UMP_HID_CTL7 0x67
+#define RT722_UMP_HID_CTL8 0x68
+
+/* Parameter & Verb control 01 (0x1a)(NID:20h) */
+#define RT722_HIDDEN_REG_SW_RESET (0x1 << 14)
+
+/* combo jack auto switch control 2 (0x46)(NID:20h) */
+#define RT722_COMBOJACK_AUTO_DET_STATUS (0x1 << 11)
+#define RT722_COMBOJACK_AUTO_DET_TRS (0x1 << 10)
+#define RT722_COMBOJACK_AUTO_DET_CTIA (0x1 << 9)
+#define RT722_COMBOJACK_AUTO_DET_OMTP (0x1 << 8)
+
+/* DAC calibration control (0x00)(NID:58h) */
+#define RT722_DC_CALIB_CTRL (0x1 << 16)
+/* DAC DC offset calibration control-1 (0x01)(NID:58h) */
+#define RT722_PDM_DC_CALIB_STATUS (0x1 << 15)
+
+#define RT722_EAPD_HIGH 0x2
+#define RT722_EAPD_LOW 0x0
+
+/* Buffer address for HID */
+#define RT722_BUF_ADDR_HID1 0x44030000
+#define RT722_BUF_ADDR_HID2 0x44030020
+
+/* RT722 SDCA Control - function number */
+#define FUNC_NUM_JACK_CODEC 0x01
+#define FUNC_NUM_MIC_ARRAY 0x02
+#define FUNC_NUM_HID 0x03
+#define FUNC_NUM_AMP 0x04
+
+/* RT722 SDCA entity */
+#define RT722_SDCA_ENT_HID01 0x01
+#define RT722_SDCA_ENT_GE49 0x49
+#define RT722_SDCA_ENT_USER_FU05 0x05
+#define RT722_SDCA_ENT_USER_FU06 0x06
+#define RT722_SDCA_ENT_USER_FU0F 0x0f
+#define RT722_SDCA_ENT_USER_FU10 0x19
+#define RT722_SDCA_ENT_USER_FU1E 0x1e
+#define RT722_SDCA_ENT_FU15 0x15
+#define RT722_SDCA_ENT_PDE23 0x23
+#define RT722_SDCA_ENT_PDE40 0x40
+#define RT722_SDCA_ENT_PDE11 0x11
+#define RT722_SDCA_ENT_PDE12 0x12
+#define RT722_SDCA_ENT_PDE2A 0x2a
+#define RT722_SDCA_ENT_CS01 0x01
+#define RT722_SDCA_ENT_CS11 0x11
+#define RT722_SDCA_ENT_CS1F 0x1f
+#define RT722_SDCA_ENT_CS1C 0x1c
+#define RT722_SDCA_ENT_CS31 0x31
+#define RT722_SDCA_ENT_OT23 0x42
+#define RT722_SDCA_ENT_IT26 0x26
+#define RT722_SDCA_ENT_IT09 0x09
+#define RT722_SDCA_ENT_PLATFORM_FU15 0x15
+#define RT722_SDCA_ENT_PLATFORM_FU44 0x44
+#define RT722_SDCA_ENT_XU03 0x03
+#define RT722_SDCA_ENT_XU0D 0x0d
+
+/* RT722 SDCA control */
+#define RT722_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10
+#define RT722_SDCA_CTL_FU_MUTE 0x01
+#define RT722_SDCA_CTL_FU_VOLUME 0x02
+#define RT722_SDCA_CTL_HIDTX_CURRENT_OWNER 0x10
+#define RT722_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE 0x11
+#define RT722_SDCA_CTL_HIDTX_MESSAGE_OFFSET 0x12
+#define RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH 0x13
+#define RT722_SDCA_CTL_SELECTED_MODE 0x01
+#define RT722_SDCA_CTL_DETECTED_MODE 0x02
+#define RT722_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT722_SDCA_CTL_VENDOR_DEF 0x30
+#define RT722_SDCA_CTL_FU_CH_GAIN 0x0b
+
+/* RT722 SDCA channel */
+#define CH_L 0x01
+#define CH_R 0x02
+#define CH_01 0x01
+#define CH_02 0x02
+#define CH_03 0x03
+#define CH_04 0x04
+#define CH_08 0x08
+
+/* sample frequency index */
+#define RT722_SDCA_RATE_16000HZ 0x04
+#define RT722_SDCA_RATE_32000HZ 0x07
+#define RT722_SDCA_RATE_44100HZ 0x08
+#define RT722_SDCA_RATE_48000HZ 0x09
+#define RT722_SDCA_RATE_96000HZ 0x0b
+#define RT722_SDCA_RATE_192000HZ 0x0d
+
+enum {
+ RT722_AIF1, /* For headset mic and headphone */
+ RT722_AIF2, /* For speaker */
+ RT722_AIF3, /* For dmic */
+ RT722_AIFS,
+};
+
+enum rt722_sdca_jd_src {
+ RT722_JD_NULL,
+ RT722_JD1,
+};
+
+int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave);
+int rt722_sdca_init(struct device *dev, struct regmap *regmap,
+ struct regmap *mbq_regmap, struct sdw_slave *slave);
+int rt722_sdca_index_write(struct rt722_sdca_priv *rt722,
+ unsigned int nid, unsigned int reg, unsigned int value);
+int rt722_sdca_index_read(struct rt722_sdca_priv *rt722,
+ unsigned int nid, unsigned int reg, unsigned int *value);
+
+int rt722_sdca_jack_detect(struct rt722_sdca_priv *rt722, bool *hp, bool *mic);
+#endif /* __RT722_H__ */
diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c
index fcf4fbaed3c7..733a7d130a95 100644
--- a/sound/soc/codecs/rt9120.c
+++ b/sound/soc/codecs/rt9120.c
@@ -633,7 +633,7 @@ static struct i2c_driver rt9120_driver = {
.of_match_table = rt9120_device_table,
.pm = &rt9120_pm_ops,
},
- .probe_new = rt9120_probe,
+ .probe = rt9120_probe,
.remove = rt9120_remove,
};
module_i2c_driver(rt9120_driver);
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index a916f4619ea3..b22ba95bd0c0 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -1826,7 +1826,7 @@ static struct i2c_driver sgtl5000_i2c_driver = {
.name = "sgtl5000",
.of_match_table = sgtl5000_dt_ids,
},
- .probe_new = sgtl5000_i2c_probe,
+ .probe = sgtl5000_i2c_probe,
.remove = sgtl5000_i2c_remove,
.shutdown = sgtl5000_i2c_shutdown,
.id_table = sgtl5000_id,
diff --git a/sound/soc/codecs/sma1303.c b/sound/soc/codecs/sma1303.c
index b6c132edf3bd..7b9abbc1bd94 100644
--- a/sound/soc/codecs/sma1303.c
+++ b/sound/soc/codecs/sma1303.c
@@ -1807,7 +1807,7 @@ static struct i2c_driver sma1303_i2c_driver = {
.name = "sma1303",
.of_match_table = sma1303_of_match,
},
- .probe_new = sma1303_i2c_probe,
+ .probe = sma1303_i2c_probe,
.remove = sma1303_i2c_remove,
.id_table = sma1303_i2c_id,
};
diff --git a/sound/soc/codecs/src4xxx-i2c.c b/sound/soc/codecs/src4xxx-i2c.c
index a40fd20df984..93af8e209b05 100644
--- a/sound/soc/codecs/src4xxx-i2c.c
+++ b/sound/soc/codecs/src4xxx-i2c.c
@@ -36,7 +36,7 @@ static struct i2c_driver src4xxx_i2c_driver = {
.name = "src4xxx",
.of_match_table = of_match_ptr(src4xxx_of_match),
},
- .probe_new = src4xxx_i2c_probe,
+ .probe = src4xxx_i2c_probe,
.id_table = src4xxx_i2c_ids,
};
module_i2c_driver(src4xxx_i2c_driver);
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index 22cb3b7c8283..d20d897407eb 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -803,7 +803,7 @@ static struct i2c_driver ssm2518_driver = {
.name = "ssm2518",
.of_match_table = of_match_ptr(ssm2518_dt_ids),
},
- .probe_new = ssm2518_i2c_probe,
+ .probe = ssm2518_i2c_probe,
.id_table = ssm2518_i2c_ids,
};
module_i2c_driver(ssm2518_driver);
diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c
index 3c85772901f5..596096466cd4 100644
--- a/sound/soc/codecs/ssm2602-i2c.c
+++ b/sound/soc/codecs/ssm2602-i2c.c
@@ -49,7 +49,7 @@ static struct i2c_driver ssm2602_i2c_driver = {
.name = "ssm2602",
.of_match_table = ssm2602_of_match,
},
- .probe_new = ssm2602_i2c_probe,
+ .probe = ssm2602_i2c_probe,
.id_table = ssm2602_i2c_id,
};
module_i2c_driver(ssm2602_i2c_driver);
diff --git a/sound/soc/codecs/ssm3515.c b/sound/soc/codecs/ssm3515.c
new file mode 100644
index 000000000000..008cb3eb5758
--- /dev/null
+++ b/sound/soc/codecs/ssm3515.c
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+//
+// Analog Devices' SSM3515 audio amp driver
+//
+// Copyright (C) The Asahi Linux Contributors
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+
+#define SSM3515_PWR 0x00
+#define SSM3515_PWR_APWDN_EN BIT(7)
+#define SSM3515_PWR_BSNS_PWDN BIT(6)
+#define SSM3515_PWR_S_RST BIT(1)
+#define SSM3515_PWR_SPWDN BIT(0)
+
+#define SSM3515_GEC 0x01
+#define SSM3515_GEC_EDGE BIT(4)
+#define SSM3515_GEC_EDGE_SHIFT 4
+#define SSM3515_GEC_ANA_GAIN GENMASK(1, 0)
+
+#define SSM3515_DAC 0x02
+#define SSM3515_DAC_HV BIT(7)
+#define SSM3515_DAC_MUTE BIT(6)
+#define SSM3515_DAC_HPF BIT(5)
+#define SSM3515_DAC_LPM BIT(4)
+#define SSM3515_DAC_FS GENMASK(2, 0)
+
+#define SSM3515_DAC_VOL 0x03
+
+#define SSM3515_SAI1 0x04
+#define SSM3515_SAI1_DAC_POL BIT(7)
+#define SSM3515_SAI1_BCLK_POL BIT(6)
+#define SSM3515_SAI1_TDM_BCLKS GENMASK(5, 3)
+#define SSM3515_SAI1_FSYNC_MODE BIT(2)
+#define SSM3515_SAI1_SDATA_FMT BIT(1)
+#define SSM3515_SAI1_SAI_MODE BIT(0)
+
+#define SSM3515_SAI2 0x05
+#define SSM3515_SAI2_DATA_WIDTH BIT(7)
+#define SSM3515_SAI2_AUTO_SLOT BIT(4)
+#define SSM3515_SAI2_TDM_SLOT GENMASK(3, 0)
+
+#define SSM3515_VBAT_OUT 0x06
+
+#define SSM3515_STATUS 0x0a
+#define SSM3515_STATUS_UVLO_REG BIT(6)
+#define SSM3515_STATUS_LIM_EG BIT(5)
+#define SSM3515_STATUS_CLIP BIT(4)
+#define SSM3515_STATUS_AMP_OC BIT(3)
+#define SSM3515_STATUS_OTF BIT(2)
+#define SSM3515_STATUS_OTW BIT(1)
+#define SSM3515_STATUS_BAT_WARN BIT(0)
+
+static bool ssm3515_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SSM3515_STATUS:
+ case SSM3515_VBAT_OUT:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static const struct reg_default ssm3515_reg_defaults[] = {
+ { SSM3515_PWR, 0x81 },
+ { SSM3515_GEC, 0x01 },
+ { SSM3515_DAC, 0x32 },
+ { SSM3515_DAC_VOL, 0x40 },
+ { SSM3515_SAI1, 0x11 },
+ { SSM3515_SAI2, 0x00 },
+};
+
+static const struct regmap_config ssm3515_i2c_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_reg = ssm3515_volatile_reg,
+ .max_register = 0xb,
+ .reg_defaults = ssm3515_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(ssm3515_reg_defaults),
+ .cache_type = REGCACHE_FLAT,
+};
+
+struct ssm3515_data {
+ struct device *dev;
+ struct regmap *regmap;
+};
+
+// The specced range is -71.25...24.00 dB with step size of 0.375 dB,
+// and a mute item below that. This is represented by -71.62...24.00 dB
+// with the mute item mapped onto the low end.
+static DECLARE_TLV_DB_MINMAX_MUTE(ssm3515_dac_volume, -7162, 2400);
+
+static const char * const ssm3515_ana_gain_text[] = {
+ "8.4 V Span", "12.6 V Span", "14 V Span", "15 V Span",
+};
+
+static SOC_ENUM_SINGLE_DECL(ssm3515_ana_gain_enum, SSM3515_GEC,
+ __bf_shf(SSM3515_GEC_ANA_GAIN),
+ ssm3515_ana_gain_text);
+
+static const struct snd_kcontrol_new ssm3515_snd_controls[] = {
+ SOC_SINGLE_TLV("DAC Playback Volume", SSM3515_DAC_VOL,
+ 0, 255, 1, ssm3515_dac_volume),
+ SOC_SINGLE("Low EMI Mode Switch", SSM3515_GEC,
+ __bf_shf(SSM3515_GEC_EDGE), 1, 0),
+ SOC_SINGLE("Soft Volume Ramping Switch", SSM3515_DAC,
+ __bf_shf(SSM3515_DAC_HV), 1, 1),
+ SOC_SINGLE("HPF Switch", SSM3515_DAC,
+ __bf_shf(SSM3515_DAC_HPF), 1, 0),
+ SOC_SINGLE("DAC Invert Switch", SSM3515_SAI1,
+ __bf_shf(SSM3515_SAI1_DAC_POL), 1, 0),
+ SOC_ENUM("DAC Analog Gain Select", ssm3515_ana_gain_enum),
+};
+
+static void ssm3515_read_faults(struct snd_soc_component *component)
+{
+ int ret;
+
+ ret = snd_soc_component_read(component, SSM3515_STATUS);
+ if (ret <= 0) {
+ /*
+ * If the read was erroneous, ASoC core has printed a message,
+ * and that's all that's appropriate in handling the error here.
+ */
+ return;
+ }
+
+ dev_err(component->dev, "device reports:%s%s%s%s%s%s%s\n",
+ FIELD_GET(SSM3515_STATUS_UVLO_REG, ret) ? " voltage regulator fault" : "",
+ FIELD_GET(SSM3515_STATUS_LIM_EG, ret) ? " limiter engaged" : "",
+ FIELD_GET(SSM3515_STATUS_CLIP, ret) ? " clipping detected" : "",
+ FIELD_GET(SSM3515_STATUS_AMP_OC, ret) ? " amp over-current fault" : "",
+ FIELD_GET(SSM3515_STATUS_OTF, ret) ? " overtemperature fault" : "",
+ FIELD_GET(SSM3515_STATUS_OTW, ret) ? " overtemperature warning" : "",
+ FIELD_GET(SSM3515_STATUS_BAT_WARN, ret) ? " bat voltage low warning" : "");
+}
+
+static int ssm3515_probe(struct snd_soc_component *component)
+{
+ int ret;
+
+ /* Start out muted */
+ ret = snd_soc_component_update_bits(component, SSM3515_DAC,
+ SSM3515_DAC_MUTE, SSM3515_DAC_MUTE);
+ if (ret < 0)
+ return ret;
+
+ /* Disable the 'master power-down' */
+ ret = snd_soc_component_update_bits(component, SSM3515_PWR,
+ SSM3515_PWR_SPWDN, 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int ssm3515_mute(struct snd_soc_dai *dai, int mute, int direction)
+{
+ int ret;
+
+ ret = snd_soc_component_update_bits(dai->component,
+ SSM3515_DAC,
+ SSM3515_DAC_MUTE,
+ FIELD_PREP(SSM3515_DAC_MUTE, mute));
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int ssm3515_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;
+ int ret, rateval;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16:
+ case SNDRV_PCM_FORMAT_S24:
+ ret = snd_soc_component_update_bits(component,
+ SSM3515_SAI2, SSM3515_SAI2_DATA_WIDTH,
+ FIELD_PREP(SSM3515_SAI2_DATA_WIDTH,
+ params_width(params) == 16));
+ if (ret < 0)
+ return ret;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch (params_rate(params)) {
+ case 8000 ... 12000:
+ rateval = 0;
+ break;
+ case 16000 ... 24000:
+ rateval = 1;
+ break;
+ case 32000 ... 48000:
+ rateval = 2;
+ break;
+ case 64000 ... 96000:
+ rateval = 3;
+ break;
+ case 128000 ... 192000:
+ rateval = 4;
+ break;
+ case 48001 ... 63999: /* this is ...72000 but overlaps */
+ rateval = 5;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = snd_soc_component_update_bits(component,
+ SSM3515_DAC, SSM3515_DAC_FS,
+ FIELD_PREP(SSM3515_DAC_FS, rateval));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int ssm3515_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ bool fpol_inv = false; /* non-inverted: frame starts with low-to-high FSYNC */
+ int ret;
+ u8 sai1 = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_NF:
+ case SND_SOC_DAIFMT_IB_IF:
+ sai1 |= SSM3515_SAI1_BCLK_POL;
+ break;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ fpol_inv = 1;
+ sai1 &= ~SSM3515_SAI1_SDATA_FMT; /* 1 bit start delay */
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ fpol_inv = 0;
+ sai1 |= SSM3515_SAI1_SDATA_FMT; /* no start delay */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_IF:
+ case SND_SOC_DAIFMT_IB_IF:
+ fpol_inv ^= 1;
+ break;
+ }
+
+ /* Set the serial input to 'TDM mode' */
+ sai1 |= SSM3515_SAI1_SAI_MODE;
+
+ if (fpol_inv) {
+ /*
+ * We configure the codec in a 'TDM mode', in which the
+ * FSYNC_MODE bit of SAI1 is supposed to select between
+ * what the datasheet calls 'Pulsed FSYNC mode' and '50%
+ * FSYNC mode'.
+ *
+ * Experiments suggest that this bit in fact simply selects
+ * the FSYNC polarity, so go with that.
+ */
+ sai1 |= SSM3515_SAI1_FSYNC_MODE;
+ }
+
+ ret = snd_soc_component_update_bits(component, SSM3515_SAI1,
+ SSM3515_SAI1_BCLK_POL | SSM3515_SAI1_SDATA_FMT |
+ SSM3515_SAI1_SAI_MODE | SSM3515_SAI1_FSYNC_MODE, sai1);
+
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int ssm3515_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;
+ int slot, tdm_bclks_val, ret;
+
+ if (tx_mask == 0 || rx_mask != 0)
+ return -EINVAL;
+
+ slot = __ffs(tx_mask);
+
+ if (tx_mask & ~BIT(slot))
+ return -EINVAL;
+
+ switch (slot_width) {
+ case 16:
+ tdm_bclks_val = 0;
+ break;
+ case 24:
+ tdm_bclks_val = 1;
+ break;
+ case 32:
+ tdm_bclks_val = 2;
+ break;
+ case 48:
+ tdm_bclks_val = 3;
+ break;
+ case 64:
+ tdm_bclks_val = 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = snd_soc_component_update_bits(component, SSM3515_SAI1,
+ SSM3515_SAI1_TDM_BCLKS,
+ FIELD_PREP(SSM3515_SAI1_TDM_BCLKS, tdm_bclks_val));
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_component_update_bits(component, SSM3515_SAI2,
+ SSM3515_SAI2_TDM_SLOT,
+ FIELD_PREP(SSM3515_SAI2_TDM_SLOT, slot));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int ssm3515_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ /*
+ * We don't get live notification of faults, so at least at
+ * this time, when playback is over, check if we have tripped
+ * over anything and if so, log it.
+ */
+ ssm3515_read_faults(dai->component);
+ return 0;
+}
+
+static const struct snd_soc_dai_ops ssm3515_dai_ops = {
+ .mute_stream = ssm3515_mute,
+ .hw_params = ssm3515_hw_params,
+ .set_fmt = ssm3515_set_fmt,
+ .set_tdm_slot = ssm3515_set_tdm_slot,
+ .hw_free = ssm3515_hw_free,
+};
+
+static struct snd_soc_dai_driver ssm3515_dai_driver = {
+ .name = "SSM3515 SAI",
+ .id = 0,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .ops = &ssm3515_dai_ops,
+};
+
+static const struct snd_soc_dapm_widget ssm3515_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_OUTPUT("OUT"),
+};
+
+static const struct snd_soc_dapm_route ssm3515_dapm_routes[] = {
+ {"OUT", NULL, "DAC"},
+ {"DAC", NULL, "Playback"},
+};
+
+static const struct snd_soc_component_driver ssm3515_asoc_component = {
+ .probe = ssm3515_probe,
+ .controls = ssm3515_snd_controls,
+ .num_controls = ARRAY_SIZE(ssm3515_snd_controls),
+ .dapm_widgets = ssm3515_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ssm3515_dapm_widgets),
+ .dapm_routes = ssm3515_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(ssm3515_dapm_routes),
+ .endianness = 1,
+};
+
+static int ssm3515_i2c_probe(struct i2c_client *client)
+{
+ struct ssm3515_data *data;
+ int ret;
+
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->dev = &client->dev;
+ i2c_set_clientdata(client, data);
+
+ data->regmap = devm_regmap_init_i2c(client, &ssm3515_i2c_regmap);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(data->dev, PTR_ERR(data->regmap),
+ "initializing register map\n");
+
+ /* Perform a reset */
+ ret = regmap_update_bits(data->regmap, SSM3515_PWR,
+ SSM3515_PWR_S_RST, SSM3515_PWR_S_RST);
+ if (ret < 0)
+ return dev_err_probe(data->dev, ret,
+ "performing software reset\n");
+ regmap_reinit_cache(data->regmap, &ssm3515_i2c_regmap);
+
+ return devm_snd_soc_register_component(data->dev,
+ &ssm3515_asoc_component,
+ &ssm3515_dai_driver, 1);
+}
+
+static const struct of_device_id ssm3515_of_match[] = {
+ { .compatible = "adi,ssm3515" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ssm3515_of_match);
+
+static struct i2c_driver ssm3515_i2c_driver = {
+ .driver = {
+ .name = "ssm3515",
+ .of_match_table = of_match_ptr(ssm3515_of_match),
+ },
+ .probe = ssm3515_i2c_probe,
+};
+module_i2c_driver(ssm3515_i2c_driver);
+
+MODULE_AUTHOR("Martin Povišer <povik+lin@cutebit.org>");
+MODULE_DESCRIPTION("ASoC SSM3515 audio amp driver");
+MODULE_LICENSE("Dual MIT/GPL");
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
index 4b0265617c7b..0a6f04d8f636 100644
--- a/sound/soc/codecs/ssm4567.c
+++ b/sound/soc/codecs/ssm4567.c
@@ -500,7 +500,7 @@ static struct i2c_driver ssm4567_driver = {
.of_match_table = of_match_ptr(ssm4567_of_match),
.acpi_match_table = ACPI_PTR(ssm4567_acpi_match),
},
- .probe_new = ssm4567_i2c_probe,
+ .probe = ssm4567_i2c_probe,
.id_table = ssm4567_i2c_ids,
};
module_i2c_driver(ssm4567_driver);
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 29af9595dac1..4a694d0bfd68 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -1167,7 +1167,7 @@ static struct i2c_driver sta32x_i2c_driver = {
.name = "sta32x",
.of_match_table = of_match_ptr(st32x_dt_ids),
},
- .probe_new = sta32x_i2c_probe,
+ .probe = sta32x_i2c_probe,
.id_table = sta32x_i2c_id,
};
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
index b033a5fcd6c0..d05f3fd57661 100644
--- a/sound/soc/codecs/sta350.c
+++ b/sound/soc/codecs/sta350.c
@@ -1249,7 +1249,7 @@ static struct i2c_driver sta350_i2c_driver = {
.name = "sta350",
.of_match_table = of_match_ptr(st350_dt_ids),
},
- .probe_new = sta350_i2c_probe,
+ .probe = sta350_i2c_probe,
.remove = sta350_i2c_remove,
.id_table = sta350_i2c_id,
};
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index 313957099145..0ac08478ddac 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -379,7 +379,7 @@ static struct i2c_driver sta529_i2c_driver = {
.name = "sta529",
.of_match_table = sta529_of_match,
},
- .probe_new = sta529_i2c_probe,
+ .probe = sta529_i2c_probe,
.id_table = sta529_i2c_id,
};
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index 59a4ea5f6e30..8c9dc318b0e8 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -761,7 +761,7 @@ static struct i2c_driver tas2552_i2c_driver = {
.of_match_table = of_match_ptr(tas2552_of_match),
.pm = &tas2552_pm,
},
- .probe_new = tas2552_probe,
+ .probe = tas2552_probe,
.remove = tas2552_i2c_remove,
.id_table = tas2552_id,
};
diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c
index b486d0bd86c9..962c2cdfa017 100644
--- a/sound/soc/codecs/tas2562.c
+++ b/sound/soc/codecs/tas2562.c
@@ -8,7 +8,6 @@
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/i2c.h>
-#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/gpio/consumer.h>
@@ -784,7 +783,7 @@ static struct i2c_driver tas2562_i2c_driver = {
.name = "tas2562",
.of_match_table = of_match_ptr(tas2562_of_match),
},
- .probe_new = tas2562_probe,
+ .probe = tas2562_probe,
.id_table = tas2562_id,
};
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 2e0ed3e68fa5..a9838e0738cc 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -756,7 +756,7 @@ static struct i2c_driver tas2764_i2c_driver = {
.name = "tas2764",
.of_match_table = of_match_ptr(tas2764_of_match),
},
- .probe_new = tas2764_i2c_probe,
+ .probe = tas2764_i2c_probe,
.id_table = tas2764_i2c_id,
};
module_i2c_driver(tas2764_i2c_driver);
diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index 8557759acb1f..99bf402eb566 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -720,7 +720,7 @@ static struct i2c_driver tas2770_i2c_driver = {
.name = "tas2770",
.of_match_table = of_match_ptr(tas2770_of_match),
},
- .probe_new = tas2770_i2c_probe,
+ .probe = tas2770_i2c_probe,
.id_table = tas2770_i2c_id,
};
module_i2c_driver(tas2770_i2c_driver);
diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c
index 09e7ada1bca4..86bd6c18a944 100644
--- a/sound/soc/codecs/tas2780.c
+++ b/sound/soc/codecs/tas2780.c
@@ -645,7 +645,7 @@ static struct i2c_driver tas2780_i2c_driver = {
.name = "tas2780",
.of_match_table = of_match_ptr(tas2780_of_match),
},
- .probe_new = tas2780_i2c_probe,
+ .probe = tas2780_i2c_probe,
.id_table = tas2780_i2c_id,
};
module_i2c_driver(tas2780_i2c_driver);
diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c
new file mode 100644
index 000000000000..a88c6c28a394
--- /dev/null
+++ b/sound/soc/codecs/tas2781-comlib.c
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// tas2781-lib.c -- TAS2781 Common functions for HDA and ASoC Audio drivers
+//
+// Copyright 2023 Texas Instruments, Inc.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+
+#include <linux/crc8.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tas2781.h>
+
+#define TASDEVICE_CRC8_POLYNOMIAL 0x4d
+
+static const struct regmap_range_cfg tasdevice_ranges[] = {
+ {
+ .range_min = 0,
+ .range_max = 256 * 128,
+ .selector_reg = TASDEVICE_PAGE_SELECT,
+ .selector_mask = 0xff,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 128,
+ },
+};
+
+static const struct regmap_config tasdevice_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_RBTREE,
+ .ranges = tasdevice_ranges,
+ .num_ranges = ARRAY_SIZE(tasdevice_ranges),
+ .max_register = 256 * 128,
+};
+
+static int tasdevice_change_chn_book(struct tasdevice_priv *tas_priv,
+ unsigned short chn, int book)
+{
+ struct i2c_client *client = (struct i2c_client *)tas_priv->client;
+ int ret = 0;
+
+ if (chn < tas_priv->ndev) {
+ struct tasdevice *tasdev = &tas_priv->tasdevice[chn];
+ struct regmap *map = tas_priv->regmap;
+
+ if (client->addr != tasdev->dev_addr) {
+ client->addr = tasdev->dev_addr;
+ if (tasdev->cur_book == book) {
+ ret = regmap_write(map,
+ TASDEVICE_PAGE_SELECT, 0);
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "%s, E=%d\n",
+ __func__, ret);
+ goto out;
+ }
+ }
+ goto out;
+ }
+
+ if (tasdev->cur_book != book) {
+ ret = regmap_write(map, TASDEVICE_BOOKCTL_REG, book);
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "%s, E=%d\n",
+ __func__, ret);
+ goto out;
+ }
+ tasdev->cur_book = book;
+ }
+ } else {
+ ret = -EINVAL;
+ dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
+ chn);
+ }
+
+out:
+ return ret;
+}
+
+int tasdevice_dev_read(struct tasdevice_priv *tas_priv,
+ unsigned short chn, unsigned int reg, unsigned int *val)
+{
+ int ret = 0;
+
+ if (chn < tas_priv->ndev) {
+ struct regmap *map = tas_priv->regmap;
+
+ ret = tasdevice_change_chn_book(tas_priv, chn,
+ TASDEVICE_BOOK_ID(reg));
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_read(map, TASDEVICE_PGRG(reg), val);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+ } else {
+ ret = -EINVAL;
+ dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
+ chn);
+ }
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tasdevice_dev_read);
+
+int tasdevice_dev_write(struct tasdevice_priv *tas_priv,
+ unsigned short chn, unsigned int reg, unsigned int value)
+{
+ int ret = 0;
+
+ if (chn < tas_priv->ndev) {
+ struct regmap *map = tas_priv->regmap;
+
+ ret = tasdevice_change_chn_book(tas_priv, chn,
+ TASDEVICE_BOOK_ID(reg));
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_write(map, TASDEVICE_PGRG(reg),
+ value);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+ } else {
+ ret = -EINVAL;
+ dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
+ chn);
+ }
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tasdevice_dev_write);
+
+int tasdevice_dev_bulk_write(
+ struct tasdevice_priv *tas_priv, unsigned short chn,
+ unsigned int reg, unsigned char *data,
+ unsigned int len)
+{
+ int ret = 0;
+
+ if (chn < tas_priv->ndev) {
+ struct regmap *map = tas_priv->regmap;
+
+ ret = tasdevice_change_chn_book(tas_priv, chn,
+ TASDEVICE_BOOK_ID(reg));
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_bulk_write(map, TASDEVICE_PGRG(reg),
+ data, len);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+ } else {
+ ret = -EINVAL;
+ dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
+ chn);
+ }
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tasdevice_dev_bulk_write);
+
+int tasdevice_dev_bulk_read(struct tasdevice_priv *tas_priv,
+ unsigned short chn, unsigned int reg, unsigned char *data,
+ unsigned int len)
+{
+ int ret = 0;
+
+ if (chn < tas_priv->ndev) {
+ struct regmap *map = tas_priv->regmap;
+
+ ret = tasdevice_change_chn_book(tas_priv, chn,
+ TASDEVICE_BOOK_ID(reg));
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_bulk_read(map, TASDEVICE_PGRG(reg), data, len);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+ } else
+ dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
+ chn);
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tasdevice_dev_bulk_read);
+
+int tasdevice_dev_update_bits(
+ struct tasdevice_priv *tas_priv, unsigned short chn,
+ unsigned int reg, unsigned int mask, unsigned int value)
+{
+ int ret = 0;
+
+ if (chn < tas_priv->ndev) {
+ struct regmap *map = tas_priv->regmap;
+
+ ret = tasdevice_change_chn_book(tas_priv, chn,
+ TASDEVICE_BOOK_ID(reg));
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_update_bits(map, TASDEVICE_PGRG(reg),
+ mask, value);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+ } else {
+ dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
+ chn);
+ ret = -EINVAL;
+ }
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tasdevice_dev_update_bits);
+
+struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c)
+{
+ struct tasdevice_priv *tas_priv;
+
+ tas_priv = devm_kzalloc(&i2c->dev, sizeof(*tas_priv), GFP_KERNEL);
+ if (!tas_priv)
+ return NULL;
+ tas_priv->dev = &i2c->dev;
+ tas_priv->client = (void *)i2c;
+
+ return tas_priv;
+}
+EXPORT_SYMBOL_GPL(tasdevice_kzalloc);
+
+void tas2781_reset(struct tasdevice_priv *tas_dev)
+{
+ int ret, i;
+
+ if (tas_dev->reset) {
+ gpiod_set_value_cansleep(tas_dev->reset, 0);
+ usleep_range(500, 1000);
+ gpiod_set_value_cansleep(tas_dev->reset, 1);
+ } else {
+ for (i = 0; i < tas_dev->ndev; i++) {
+ ret = tasdevice_dev_write(tas_dev, i,
+ TAS2781_REG_SWRESET,
+ TAS2781_REG_SWRESET_RESET);
+ if (ret < 0)
+ dev_err(tas_dev->dev,
+ "dev %d swreset fail, %d\n",
+ i, ret);
+ }
+ }
+ usleep_range(1000, 1050);
+}
+EXPORT_SYMBOL_GPL(tas2781_reset);
+
+int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
+ void (*cont)(const struct firmware *fw, void *context))
+{
+ int ret = 0;
+
+ /* Codec Lock Hold to ensure that codec_probe and firmware parsing and
+ * loading do not simultaneously execute.
+ */
+ mutex_lock(&tas_priv->codec_lock);
+
+ scnprintf(tas_priv->rca_binaryname, 64, "%sRCA%d.bin",
+ tas_priv->dev_name, tas_priv->ndev);
+ crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL);
+ tas_priv->codec = codec;
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
+ tas_priv->rca_binaryname, tas_priv->dev, GFP_KERNEL, tas_priv,
+ cont);
+ if (ret)
+ dev_err(tas_priv->dev, "request_firmware_nowait err:0x%08x\n",
+ ret);
+
+ /* Codec Lock Release*/
+ mutex_unlock(&tas_priv->codec_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tascodec_init);
+
+int tasdevice_init(struct tasdevice_priv *tas_priv)
+{
+ int ret = 0;
+ int i;
+
+ tas_priv->regmap = devm_regmap_init_i2c(tas_priv->client,
+ &tasdevice_regmap);
+ if (IS_ERR(tas_priv->regmap)) {
+ ret = PTR_ERR(tas_priv->regmap);
+ dev_err(tas_priv->dev, "Failed to allocate register map: %d\n",
+ ret);
+ goto out;
+ }
+
+ tas_priv->cur_prog = -1;
+ tas_priv->cur_conf = -1;
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ tas_priv->tasdevice[i].cur_book = -1;
+ tas_priv->tasdevice[i].cur_prog = -1;
+ tas_priv->tasdevice[i].cur_conf = -1;
+ }
+
+ dev_set_drvdata(tas_priv->dev, tas_priv);
+
+ mutex_init(&tas_priv->codec_lock);
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tasdevice_init);
+
+static void tasdev_dsp_prog_blk_remove(struct tasdevice_prog *prog)
+{
+ struct tasdevice_data *tas_dt;
+ struct tasdev_blk *blk;
+ unsigned int i;
+
+ if (!prog)
+ return;
+
+ tas_dt = &(prog->dev_data);
+
+ if (!tas_dt->dev_blks)
+ return;
+
+ for (i = 0; i < tas_dt->nr_blk; i++) {
+ blk = &(tas_dt->dev_blks[i]);
+ kfree(blk->data);
+ }
+ kfree(tas_dt->dev_blks);
+}
+
+static void tasdev_dsp_prog_remove(struct tasdevice_prog *prog,
+ unsigned short nr)
+{
+ int i;
+
+ for (i = 0; i < nr; i++)
+ tasdev_dsp_prog_blk_remove(&prog[i]);
+ kfree(prog);
+}
+
+static void tasdev_dsp_cfg_blk_remove(struct tasdevice_config *cfg)
+{
+ struct tasdevice_data *tas_dt;
+ struct tasdev_blk *blk;
+ unsigned int i;
+
+ if (cfg) {
+ tas_dt = &(cfg->dev_data);
+
+ if (!tas_dt->dev_blks)
+ return;
+
+ for (i = 0; i < tas_dt->nr_blk; i++) {
+ blk = &(tas_dt->dev_blks[i]);
+ kfree(blk->data);
+ }
+ kfree(tas_dt->dev_blks);
+ }
+}
+
+static void tasdev_dsp_cfg_remove(struct tasdevice_config *config,
+ unsigned short nr)
+{
+ int i;
+
+ for (i = 0; i < nr; i++)
+ tasdev_dsp_cfg_blk_remove(&config[i]);
+ kfree(config);
+}
+
+void tasdevice_dsp_remove(void *context)
+{
+ struct tasdevice_priv *tas_dev = (struct tasdevice_priv *) context;
+ struct tasdevice_fw *tas_fmw = tas_dev->fmw;
+
+ if (!tas_dev->fmw)
+ return;
+
+ if (tas_fmw->programs)
+ tasdev_dsp_prog_remove(tas_fmw->programs,
+ tas_fmw->nr_programs);
+ if (tas_fmw->configs)
+ tasdev_dsp_cfg_remove(tas_fmw->configs,
+ tas_fmw->nr_configurations);
+ kfree(tas_fmw);
+ tas_dev->fmw = NULL;
+}
+EXPORT_SYMBOL_GPL(tasdevice_dsp_remove);
+
+void tasdevice_remove(struct tasdevice_priv *tas_priv)
+{
+ if (gpio_is_valid(tas_priv->irq_info.irq_gpio))
+ gpio_free(tas_priv->irq_info.irq_gpio);
+ kfree(tas_priv->acpi_subsystem_id);
+ mutex_destroy(&tas_priv->codec_lock);
+}
+EXPORT_SYMBOL_GPL(tasdevice_remove);
+
+static int tasdevice_clamp(int val, int max, unsigned int invert)
+{
+ if (val > max)
+ val = max;
+ if (invert)
+ val = max - val;
+ if (val < 0)
+ val = 0;
+ return val;
+}
+
+int tasdevice_amp_putvol(struct tasdevice_priv *tas_priv,
+ struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
+{
+ unsigned int invert = mc->invert;
+ unsigned char mask;
+ int max = mc->max;
+ int err_cnt = 0;
+ int val, i, ret;
+
+ mask = (1 << fls(max)) - 1;
+ mask <<= mc->shift;
+ val = tasdevice_clamp(ucontrol->value.integer.value[0], max, invert);
+ for (i = 0; i < tas_priv->ndev; i++) {
+ ret = tasdevice_dev_update_bits(tas_priv, i,
+ mc->reg, mask, (unsigned int)(val << mc->shift));
+ if (!ret)
+ continue;
+ err_cnt++;
+ dev_err(tas_priv->dev, "set AMP vol error in dev %d\n", i);
+ }
+
+ /* All the devices set error, return 0 */
+ return (err_cnt == tas_priv->ndev) ? 0 : 1;
+}
+EXPORT_SYMBOL_GPL(tasdevice_amp_putvol);
+
+int tasdevice_amp_getvol(struct tasdevice_priv *tas_priv,
+ struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
+{
+ unsigned int invert = mc->invert;
+ unsigned char mask = 0;
+ int max = mc->max;
+ int ret = 0;
+ int val;
+
+ /* Read the primary device */
+ ret = tasdevice_dev_read(tas_priv, 0, mc->reg, &val);
+ if (ret) {
+ dev_err(tas_priv->dev, "%s, get AMP vol error\n", __func__);
+ goto out;
+ }
+
+ mask = (1 << fls(max)) - 1;
+ mask <<= mc->shift;
+ val = (val & mask) >> mc->shift;
+ val = tasdevice_clamp(val, max, invert);
+ ucontrol->value.integer.value[0] = val;
+
+out:
+ return ret;
+
+}
+EXPORT_SYMBOL_GPL(tasdevice_amp_getvol);
+
+int tasdevice_digital_putvol(struct tasdevice_priv *tas_priv,
+ struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
+{
+ unsigned int invert = mc->invert;
+ int max = mc->max;
+ int err_cnt = 0;
+ int ret;
+ int val, i;
+
+ val = tasdevice_clamp(ucontrol->value.integer.value[0], max, invert);
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ ret = tasdevice_dev_write(tas_priv, i, mc->reg,
+ (unsigned int)val);
+ if (!ret)
+ continue;
+ err_cnt++;
+ dev_err(tas_priv->dev,
+ "set digital vol err in dev %d\n", i);
+ }
+
+ /* All the devices set error, return 0 */
+ return (err_cnt == tas_priv->ndev) ? 0 : 1;
+
+}
+EXPORT_SYMBOL_GPL(tasdevice_digital_putvol);
+
+int tasdevice_digital_getvol(struct tasdevice_priv *tas_priv,
+ struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
+{
+ unsigned int invert = mc->invert;
+ int max = mc->max;
+ int ret, val;
+
+ /* Read the primary device as the whole */
+ ret = tasdevice_dev_read(tas_priv, 0, mc->reg, &val);
+ if (ret) {
+ dev_err(tas_priv->dev, "%s, get digital vol error\n",
+ __func__);
+ goto out;
+ }
+
+ val = tasdevice_clamp(val, max, invert);
+ ucontrol->value.integer.value[0] = val;
+
+out:
+ return ret;
+
+}
+EXPORT_SYMBOL_GPL(tasdevice_digital_getvol);
+
+MODULE_DESCRIPTION("TAS2781 common library");
+MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
new file mode 100644
index 000000000000..eb55abae0d7b
--- /dev/null
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -0,0 +1,2428 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// tasdevice-fmw.c -- TASDEVICE firmware support
+//
+// Copyright 2023 Texas Instruments, Inc.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+
+#include <linux/crc8.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/tas2781.h>
+
+
+#define ERROR_PRAM_CRCCHK 0x0000000
+#define ERROR_YRAM_CRCCHK 0x0000001
+#define PPC_DRIVER_CRCCHK 0x00000200
+
+#define TAS2781_SA_COEFF_SWAP_REG TASDEVICE_REG(0, 0x35, 0x2c)
+#define TAS2781_YRAM_BOOK1 140
+#define TAS2781_YRAM1_PAGE 42
+#define TAS2781_YRAM1_START_REG 88
+
+#define TAS2781_YRAM2_START_PAGE 43
+#define TAS2781_YRAM2_END_PAGE 49
+#define TAS2781_YRAM2_START_REG 8
+#define TAS2781_YRAM2_END_REG 127
+
+#define TAS2781_YRAM3_PAGE 50
+#define TAS2781_YRAM3_START_REG 8
+#define TAS2781_YRAM3_END_REG 27
+
+/*should not include B0_P53_R44-R47 */
+#define TAS2781_YRAM_BOOK2 0
+#define TAS2781_YRAM4_START_PAGE 50
+#define TAS2781_YRAM4_END_PAGE 60
+
+#define TAS2781_YRAM5_PAGE 61
+#define TAS2781_YRAM5_START_REG TAS2781_YRAM3_START_REG
+#define TAS2781_YRAM5_END_REG TAS2781_YRAM3_END_REG
+
+#define TASDEVICE_MAXPROGRAM_NUM_KERNEL 5
+#define TASDEVICE_MAXCONFIG_NUM_KERNEL_MULTIPLE_AMPS 64
+#define TASDEVICE_MAXCONFIG_NUM_KERNEL 10
+#define MAIN_ALL_DEVICES_1X 0x01
+#define MAIN_DEVICE_A_1X 0x02
+#define MAIN_DEVICE_B_1X 0x03
+#define MAIN_DEVICE_C_1X 0x04
+#define MAIN_DEVICE_D_1X 0x05
+#define COEFF_DEVICE_A_1X 0x12
+#define COEFF_DEVICE_B_1X 0x13
+#define COEFF_DEVICE_C_1X 0x14
+#define COEFF_DEVICE_D_1X 0x15
+#define PRE_DEVICE_A_1X 0x22
+#define PRE_DEVICE_B_1X 0x23
+#define PRE_DEVICE_C_1X 0x24
+#define PRE_DEVICE_D_1X 0x25
+#define PRE_SOFTWARE_RESET_DEVICE_A 0x41
+#define PRE_SOFTWARE_RESET_DEVICE_B 0x42
+#define PRE_SOFTWARE_RESET_DEVICE_C 0x43
+#define PRE_SOFTWARE_RESET_DEVICE_D 0x44
+#define POST_SOFTWARE_RESET_DEVICE_A 0x45
+#define POST_SOFTWARE_RESET_DEVICE_B 0x46
+#define POST_SOFTWARE_RESET_DEVICE_C 0x47
+#define POST_SOFTWARE_RESET_DEVICE_D 0x48
+
+struct tas_crc {
+ unsigned char offset;
+ unsigned char len;
+};
+
+static const char deviceNumber[TASDEVICE_DSP_TAS_MAX_DEVICE] = {
+ 1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4
+};
+
+static struct tasdevice_config_info *tasdevice_add_config(
+ struct tasdevice_priv *tas_priv, unsigned char *config_data,
+ unsigned int config_size, int *status)
+{
+ struct tasdevice_config_info *cfg_info;
+ struct tasdev_blk_data **bk_da;
+ unsigned int config_offset = 0;
+ unsigned int i;
+
+ /* In most projects are many audio cases, such as music, handfree,
+ * receiver, games, audio-to-haptics, PMIC record, bypass mode,
+ * portrait, landscape, etc. Even in multiple audios, one or
+ * two of the chips will work for the special case, such as
+ * ultrasonic application. In order to support these variable-numbers
+ * of audio cases, flexible configs have been introduced in the
+ * dsp firmware.
+ */
+ cfg_info = kzalloc(sizeof(struct tasdevice_config_info), GFP_KERNEL);
+ if (!cfg_info) {
+ *status = -ENOMEM;
+ goto out;
+ }
+
+ if (tas_priv->rcabin.fw_hdr.binary_version_num >= 0x105) {
+ if (config_offset + 64 > (int)config_size) {
+ *status = -EINVAL;
+ dev_err(tas_priv->dev, "add conf: Out of boundary\n");
+ goto out;
+ }
+ config_offset += 64;
+ }
+
+ if (config_offset + 4 > (int)config_size) {
+ *status = -EINVAL;
+ dev_err(tas_priv->dev, "add config: Out of boundary\n");
+ goto out;
+ }
+
+ /* convert data[offset], data[offset + 1], data[offset + 2] and
+ * data[offset + 3] into host
+ */
+ cfg_info->nblocks =
+ be32_to_cpup((__be32 *)&config_data[config_offset]);
+ config_offset += 4;
+
+ /* Several kinds of dsp/algorithm firmwares can run on tas2781,
+ * the number and size of blk are not fixed and different among
+ * these firmwares.
+ */
+ bk_da = cfg_info->blk_data = kcalloc(cfg_info->nblocks,
+ sizeof(struct tasdev_blk_data *), GFP_KERNEL);
+ if (!bk_da) {
+ *status = -ENOMEM;
+ goto out;
+ }
+ cfg_info->real_nblocks = 0;
+ for (i = 0; i < cfg_info->nblocks; i++) {
+ if (config_offset + 12 > config_size) {
+ *status = -EINVAL;
+ dev_err(tas_priv->dev,
+ "%s: Out of boundary: i = %d nblocks = %u!\n",
+ __func__, i, cfg_info->nblocks);
+ break;
+ }
+ bk_da[i] = kzalloc(sizeof(struct tasdev_blk_data), GFP_KERNEL);
+ if (!bk_da[i]) {
+ *status = -ENOMEM;
+ break;
+ }
+
+ bk_da[i]->dev_idx = config_data[config_offset];
+ config_offset++;
+
+ bk_da[i]->block_type = config_data[config_offset];
+ config_offset++;
+
+ if (bk_da[i]->block_type == TASDEVICE_BIN_BLK_PRE_POWER_UP) {
+ if (bk_da[i]->dev_idx == 0)
+ cfg_info->active_dev =
+ (1 << tas_priv->ndev) - 1;
+ else
+ cfg_info->active_dev |= 1 <<
+ (bk_da[i]->dev_idx - 1);
+
+ }
+ bk_da[i]->yram_checksum =
+ be16_to_cpup((__be16 *)&config_data[config_offset]);
+ config_offset += 2;
+ bk_da[i]->block_size =
+ be32_to_cpup((__be32 *)&config_data[config_offset]);
+ config_offset += 4;
+
+ bk_da[i]->n_subblks =
+ be32_to_cpup((__be32 *)&config_data[config_offset]);
+
+ config_offset += 4;
+
+ if (config_offset + bk_da[i]->block_size > config_size) {
+ *status = -EINVAL;
+ dev_err(tas_priv->dev,
+ "%s: Out of boundary: i = %d blks = %u!\n",
+ __func__, i, cfg_info->nblocks);
+ break;
+ }
+ /* instead of kzalloc+memcpy */
+ bk_da[i]->regdata = kmemdup(&config_data[config_offset],
+ bk_da[i]->block_size, GFP_KERNEL);
+ if (!bk_da[i]->regdata) {
+ *status = -ENOMEM;
+ goto out;
+ }
+
+ config_offset += bk_da[i]->block_size;
+ cfg_info->real_nblocks += 1;
+ }
+
+out:
+ return cfg_info;
+}
+
+int tasdevice_rca_parser(void *context, const struct firmware *fmw)
+{
+ struct tasdevice_priv *tas_priv = context;
+ struct tasdevice_config_info **cfg_info;
+ struct tasdevice_rca_hdr *fw_hdr;
+ struct tasdevice_rca *rca;
+ unsigned int total_config_sz = 0;
+ unsigned char *buf;
+ int offset = 0;
+ int ret = 0;
+ int i;
+
+ rca = &(tas_priv->rcabin);
+ fw_hdr = &(rca->fw_hdr);
+ if (!fmw || !fmw->data) {
+ dev_err(tas_priv->dev, "Failed to read %s\n",
+ tas_priv->rca_binaryname);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ ret = -EINVAL;
+ goto out;
+ }
+ buf = (unsigned char *)fmw->data;
+
+ fw_hdr->img_sz = be32_to_cpup((__be32 *)&buf[offset]);
+ offset += 4;
+ if (fw_hdr->img_sz != fmw->size) {
+ dev_err(tas_priv->dev,
+ "File size not match, %d %u", (int)fmw->size,
+ fw_hdr->img_sz);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ ret = -EINVAL;
+ goto out;
+ }
+
+ fw_hdr->checksum = be32_to_cpup((__be32 *)&buf[offset]);
+ offset += 4;
+ fw_hdr->binary_version_num = be32_to_cpup((__be32 *)&buf[offset]);
+ if (fw_hdr->binary_version_num < 0x103) {
+ dev_err(tas_priv->dev, "File version 0x%04x is too low",
+ fw_hdr->binary_version_num);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ ret = -EINVAL;
+ goto out;
+ }
+ offset += 4;
+ fw_hdr->drv_fw_version = be32_to_cpup((__be32 *)&buf[offset]);
+ offset += 8;
+ fw_hdr->plat_type = buf[offset];
+ offset += 1;
+ fw_hdr->dev_family = buf[offset];
+ offset += 1;
+ fw_hdr->reserve = buf[offset];
+ offset += 1;
+ fw_hdr->ndev = buf[offset];
+ offset += 1;
+ if (fw_hdr->ndev != tas_priv->ndev) {
+ dev_err(tas_priv->dev,
+ "ndev(%u) in rcabin mismatch ndev(%u) in DTS\n",
+ fw_hdr->ndev, tas_priv->ndev);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ ret = -EINVAL;
+ goto out;
+ }
+ if (offset + TASDEVICE_DEVICE_SUM > fw_hdr->img_sz) {
+ dev_err(tas_priv->dev, "rca_ready: Out of boundary!\n");
+ ret = -EINVAL;
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ goto out;
+ }
+
+ for (i = 0; i < TASDEVICE_DEVICE_SUM; i++, offset++)
+ fw_hdr->devs[i] = buf[offset];
+
+ fw_hdr->nconfig = be32_to_cpup((__be32 *)&buf[offset]);
+ offset += 4;
+
+ for (i = 0; i < TASDEVICE_CONFIG_SUM; i++) {
+ fw_hdr->config_size[i] = be32_to_cpup((__be32 *)&buf[offset]);
+ offset += 4;
+ total_config_sz += fw_hdr->config_size[i];
+ }
+
+ if (fw_hdr->img_sz - total_config_sz != (unsigned int)offset) {
+ dev_err(tas_priv->dev, "Bin file error!\n");
+ ret = -EINVAL;
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ goto out;
+ }
+
+ cfg_info = kcalloc(fw_hdr->nconfig, sizeof(*cfg_info), GFP_KERNEL);
+ if (!cfg_info) {
+ ret = -ENOMEM;
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ goto out;
+ }
+ rca->cfg_info = cfg_info;
+ rca->ncfgs = 0;
+ for (i = 0; i < (int)fw_hdr->nconfig; i++) {
+ rca->ncfgs += 1;
+ cfg_info[i] = tasdevice_add_config(tas_priv, &buf[offset],
+ fw_hdr->config_size[i], &ret);
+ if (ret) {
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ goto out;
+ }
+ offset += (int)fw_hdr->config_size[i];
+ }
+out:
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_rca_parser, SND_SOC_TAS2781_FMWLIB);
+
+static int fw_parse_block_data_kernel(struct tasdevice_fw *tas_fmw,
+ struct tasdev_blk *block, const struct firmware *fmw, int offset)
+{
+ const unsigned char *data = fmw->data;
+
+ if (offset + 16 > fmw->size) {
+ dev_err(tas_fmw->dev, "%s: File Size error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+
+ /* convert data[offset], data[offset + 1], data[offset + 2] and
+ * data[offset + 3] into host
+ */
+ block->type = be32_to_cpup((__be32 *)&data[offset]);
+ offset += 4;
+
+ block->is_pchksum_present = data[offset];
+ offset++;
+
+ block->pchksum = data[offset];
+ offset++;
+
+ block->is_ychksum_present = data[offset];
+ offset++;
+
+ block->ychksum = data[offset];
+ offset++;
+
+ block->blk_size = be32_to_cpup((__be32 *)&data[offset]);
+ offset += 4;
+
+ block->nr_subblocks = be32_to_cpup((__be32 *)&data[offset]);
+ offset += 4;
+
+ if (offset + block->blk_size > fmw->size) {
+ dev_err(tas_fmw->dev, "%s: nSublocks error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ /* instead of kzalloc+memcpy */
+ block->data = kmemdup(&data[offset], block->blk_size, GFP_KERNEL);
+ if (!block->data) {
+ offset = -ENOMEM;
+ goto out;
+ }
+ offset += block->blk_size;
+
+out:
+ return offset;
+}
+
+static int fw_parse_data_kernel(struct tasdevice_fw *tas_fmw,
+ struct tasdevice_data *img_data, const struct firmware *fmw,
+ int offset)
+{
+ const unsigned char *data = fmw->data;
+ struct tasdev_blk *blk;
+ unsigned int i;
+
+ if (offset + 4 > fmw->size) {
+ dev_err(tas_fmw->dev, "%s: File Size error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ img_data->nr_blk = be32_to_cpup((__be32 *)&data[offset]);
+ offset += 4;
+
+ img_data->dev_blks = kcalloc(img_data->nr_blk,
+ sizeof(struct tasdev_blk), GFP_KERNEL);
+ if (!img_data->dev_blks) {
+ offset = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < img_data->nr_blk; i++) {
+ blk = &(img_data->dev_blks[i]);
+ offset = fw_parse_block_data_kernel(tas_fmw, blk, fmw, offset);
+ if (offset < 0) {
+ offset = -EINVAL;
+ break;
+ }
+ }
+
+out:
+ return offset;
+}
+
+static int fw_parse_program_data_kernel(
+ struct tasdevice_priv *tas_priv, struct tasdevice_fw *tas_fmw,
+ const struct firmware *fmw, int offset)
+{
+ struct tasdevice_prog *program;
+ unsigned int i;
+
+ for (i = 0; i < tas_fmw->nr_programs; i++) {
+ program = &(tas_fmw->programs[i]);
+ if (offset + 72 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: mpName error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ /*skip 72 unused byts*/
+ offset += 72;
+
+ offset = fw_parse_data_kernel(tas_fmw, &(program->dev_data),
+ fmw, offset);
+ if (offset < 0)
+ goto out;
+ }
+
+out:
+ return offset;
+}
+
+static int fw_parse_configuration_data_kernel(
+ struct tasdevice_priv *tas_priv,
+ struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset)
+{
+ const unsigned char *data = fmw->data;
+ struct tasdevice_config *config;
+ unsigned int i;
+
+ for (i = 0; i < tas_fmw->nr_configurations; i++) {
+ config = &(tas_fmw->configs[i]);
+ if (offset + 80 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: mpName error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ memcpy(config->name, &data[offset], 64);
+ /*skip extra 16 bytes*/
+ offset += 80;
+
+ offset = fw_parse_data_kernel(tas_fmw, &(config->dev_data),
+ fmw, offset);
+ if (offset < 0)
+ goto out;
+ }
+
+out:
+ return offset;
+}
+
+static int fw_parse_variable_header_kernel(
+ struct tasdevice_priv *tas_priv, const struct firmware *fmw,
+ int offset)
+{
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct tasdevice_dspfw_hdr *fw_hdr = &(tas_fmw->fw_hdr);
+ struct tasdevice_prog *program;
+ struct tasdevice_config *config;
+ const unsigned char *buf = fmw->data;
+ unsigned short max_confs;
+ unsigned int i;
+
+ if (offset + 12 + 4 * TASDEVICE_MAXPROGRAM_NUM_KERNEL > fmw->size) {
+ dev_err(tas_priv->dev, "%s: File Size error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ fw_hdr->device_family = be16_to_cpup((__be16 *)&buf[offset]);
+ if (fw_hdr->device_family != 0) {
+ dev_err(tas_priv->dev, "%s:not TAS device\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += 2;
+ fw_hdr->device = be16_to_cpup((__be16 *)&buf[offset]);
+ if (fw_hdr->device >= TASDEVICE_DSP_TAS_MAX_DEVICE ||
+ fw_hdr->device == 6) {
+ dev_err(tas_priv->dev, "Unsupported dev %d\n", fw_hdr->device);
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += 2;
+ fw_hdr->ndev = deviceNumber[fw_hdr->device];
+
+ if (fw_hdr->ndev != tas_priv->ndev) {
+ dev_err(tas_priv->dev,
+ "%s: ndev(%u) in dspbin mismatch ndev(%u) in DTS\n",
+ __func__, fw_hdr->ndev, tas_priv->ndev);
+ offset = -EINVAL;
+ goto out;
+ }
+
+ tas_fmw->nr_programs = be32_to_cpup((__be32 *)&buf[offset]);
+ offset += 4;
+
+ if (tas_fmw->nr_programs == 0 || tas_fmw->nr_programs >
+ TASDEVICE_MAXPROGRAM_NUM_KERNEL) {
+ dev_err(tas_priv->dev, "mnPrograms is invalid\n");
+ offset = -EINVAL;
+ goto out;
+ }
+
+ tas_fmw->programs = kcalloc(tas_fmw->nr_programs,
+ sizeof(struct tasdevice_prog), GFP_KERNEL);
+ if (!tas_fmw->programs) {
+ offset = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < tas_fmw->nr_programs; i++) {
+ program = &(tas_fmw->programs[i]);
+ program->prog_size = be32_to_cpup((__be32 *)&buf[offset]);
+ offset += 4;
+ }
+
+ /* Skip the unused prog_size */
+ offset += 4 * (TASDEVICE_MAXPROGRAM_NUM_KERNEL - tas_fmw->nr_programs);
+
+ tas_fmw->nr_configurations = be32_to_cpup((__be32 *)&buf[offset]);
+ offset += 4;
+
+ /* The max number of config in firmware greater than 4 pieces of
+ * tas2781s is different from the one lower than 4 pieces of
+ * tas2781s.
+ */
+ max_confs = (fw_hdr->ndev >= 4) ?
+ TASDEVICE_MAXCONFIG_NUM_KERNEL_MULTIPLE_AMPS :
+ TASDEVICE_MAXCONFIG_NUM_KERNEL;
+ if (tas_fmw->nr_configurations == 0 ||
+ tas_fmw->nr_configurations > max_confs) {
+ dev_err(tas_priv->dev, "%s: Conf is invalid\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+
+ if (offset + 4 * max_confs > fmw->size) {
+ dev_err(tas_priv->dev, "%s: mpConfigurations err\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+
+ tas_fmw->configs = kcalloc(tas_fmw->nr_configurations,
+ sizeof(struct tasdevice_config), GFP_KERNEL);
+ if (!tas_fmw->configs) {
+ offset = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < tas_fmw->nr_programs; i++) {
+ config = &(tas_fmw->configs[i]);
+ config->cfg_size = be32_to_cpup((__be32 *)&buf[offset]);
+ offset += 4;
+ }
+
+ /* Skip the unused configs */
+ offset += 4 * (max_confs - tas_fmw->nr_programs);
+
+out:
+ return offset;
+}
+
+static int tasdevice_process_block(void *context, unsigned char *data,
+ unsigned char dev_idx, int sublocksize)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context;
+ int subblk_offset, chn, chnend, rc;
+ unsigned char subblk_typ = data[1];
+ int blktyp = dev_idx & 0xC0;
+ int idx = dev_idx & 0x3F;
+ bool is_err = false;
+
+ if (idx) {
+ chn = idx - 1;
+ chnend = idx;
+ } else {
+ chn = 0;
+ chnend = tas_priv->ndev;
+ }
+
+ for (; chn < chnend; chn++) {
+ if (tas_priv->tasdevice[chn].is_loading == false)
+ continue;
+
+ is_err = false;
+ subblk_offset = 2;
+ switch (subblk_typ) {
+ case TASDEVICE_CMD_SING_W: {
+ int i;
+ unsigned short len = be16_to_cpup((__be16 *)&data[2]);
+
+ subblk_offset += 2;
+ if (subblk_offset + 4 * len > sublocksize) {
+ dev_err(tas_priv->dev,
+ "process_block: Out of boundary\n");
+ is_err = true;
+ break;
+ }
+
+ for (i = 0; i < len; i++) {
+ rc = tasdevice_dev_write(tas_priv, chn,
+ TASDEVICE_REG(data[subblk_offset],
+ data[subblk_offset + 1],
+ data[subblk_offset + 2]),
+ data[subblk_offset + 3]);
+ if (rc < 0) {
+ is_err = true;
+ dev_err(tas_priv->dev,
+ "process_block: single write error\n");
+ }
+ subblk_offset += 4;
+ }
+ }
+ break;
+ case TASDEVICE_CMD_BURST: {
+ unsigned short len = be16_to_cpup((__be16 *)&data[2]);
+
+ subblk_offset += 2;
+ if (subblk_offset + 4 + len > sublocksize) {
+ dev_err(tas_priv->dev,
+ "%s: BST Out of boundary\n",
+ __func__);
+ is_err = true;
+ break;
+ }
+ if (len % 4) {
+ dev_err(tas_priv->dev,
+ "%s:Bst-len(%u)not div by 4\n",
+ __func__, len);
+ break;
+ }
+
+ rc = tasdevice_dev_bulk_write(tas_priv, chn,
+ TASDEVICE_REG(data[subblk_offset],
+ data[subblk_offset + 1],
+ data[subblk_offset + 2]),
+ &(data[subblk_offset + 4]), len);
+ if (rc < 0) {
+ is_err = true;
+ dev_err(tas_priv->dev,
+ "%s: bulk_write error = %d\n",
+ __func__, rc);
+ }
+ subblk_offset += (len + 4);
+ }
+ break;
+ case TASDEVICE_CMD_DELAY: {
+ unsigned int sleep_time = 0;
+
+ if (subblk_offset + 2 > sublocksize) {
+ dev_err(tas_priv->dev,
+ "%s: delay Out of boundary\n",
+ __func__);
+ is_err = true;
+ break;
+ }
+ sleep_time = be16_to_cpup((__be16 *)&data[2]) * 1000;
+ usleep_range(sleep_time, sleep_time + 50);
+ subblk_offset += 2;
+ }
+ break;
+ case TASDEVICE_CMD_FIELD_W:
+ if (subblk_offset + 6 > sublocksize) {
+ dev_err(tas_priv->dev,
+ "%s: bit write Out of boundary\n",
+ __func__);
+ is_err = true;
+ break;
+ }
+ rc = tasdevice_dev_update_bits(tas_priv, chn,
+ TASDEVICE_REG(data[subblk_offset + 2],
+ data[subblk_offset + 3],
+ data[subblk_offset + 4]),
+ data[subblk_offset + 1],
+ data[subblk_offset + 5]);
+ if (rc < 0) {
+ is_err = true;
+ dev_err(tas_priv->dev,
+ "%s: update_bits error = %d\n",
+ __func__, rc);
+ }
+ subblk_offset += 6;
+ break;
+ default:
+ break;
+ }
+ if (is_err == true && blktyp != 0) {
+ if (blktyp == 0x80) {
+ tas_priv->tasdevice[chn].cur_prog = -1;
+ tas_priv->tasdevice[chn].cur_conf = -1;
+ } else
+ tas_priv->tasdevice[chn].cur_conf = -1;
+ }
+ }
+
+ return subblk_offset;
+}
+
+void tasdevice_select_cfg_blk(void *pContext, int conf_no,
+ unsigned char block_type)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) pContext;
+ struct tasdevice_rca *rca = &(tas_priv->rcabin);
+ struct tasdevice_config_info **cfg_info = rca->cfg_info;
+ struct tasdev_blk_data **blk_data;
+ int j, k, chn, chnend;
+
+ if (conf_no >= rca->ncfgs || conf_no < 0 || !cfg_info) {
+ dev_err(tas_priv->dev, "conf_no should be not more than %u\n",
+ rca->ncfgs);
+ return;
+ }
+ blk_data = cfg_info[conf_no]->blk_data;
+
+ for (j = 0; j < (int)cfg_info[conf_no]->real_nblocks; j++) {
+ unsigned int length = 0, rc = 0;
+
+ if (block_type > 5 || block_type < 2) {
+ dev_err(tas_priv->dev,
+ "block_type should be in range from 2 to 5\n");
+ break;
+ }
+ if (block_type != blk_data[j]->block_type)
+ continue;
+
+ for (k = 0; k < (int)blk_data[j]->n_subblks; k++) {
+ if (blk_data[j]->dev_idx) {
+ chn = blk_data[j]->dev_idx - 1;
+ chnend = blk_data[j]->dev_idx;
+ } else {
+ chn = 0;
+ chnend = tas_priv->ndev;
+ }
+ for (; chn < chnend; chn++)
+ tas_priv->tasdevice[chn].is_loading = true;
+
+ rc = tasdevice_process_block(tas_priv,
+ blk_data[j]->regdata + length,
+ blk_data[j]->dev_idx,
+ blk_data[j]->block_size - length);
+ length += rc;
+ if (blk_data[j]->block_size < length) {
+ dev_err(tas_priv->dev,
+ "%s: %u %u out of boundary\n",
+ __func__, length,
+ blk_data[j]->block_size);
+ break;
+ }
+ }
+ if (length != blk_data[j]->block_size)
+ dev_err(tas_priv->dev, "%s: %u %u size is not same\n",
+ __func__, length, blk_data[j]->block_size);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_select_cfg_blk, SND_SOC_TAS2781_FMWLIB);
+
+static int tasdevice_load_block_kernel(
+ struct tasdevice_priv *tasdevice, struct tasdev_blk *block)
+{
+ struct tasdevice_dspfw_hdr *fw_hdr = &(tasdevice->fmw->fw_hdr);
+ struct tasdevice_fw_fixed_hdr *fw_fixed_hdr = &(fw_hdr->fixed_hdr);
+ const unsigned int blk_size = block->blk_size;
+ unsigned int i, length;
+ unsigned char *data = block->data;
+ unsigned char dev_idx = 0;
+
+ if (fw_fixed_hdr->ppcver >= PPC3_VERSION_TAS2781) {
+ switch (block->type) {
+ case MAIN_ALL_DEVICES_1X:
+ dev_idx = 0x80;
+ break;
+ case MAIN_DEVICE_A_1X:
+ dev_idx = 0x81;
+ break;
+ case COEFF_DEVICE_A_1X:
+ case PRE_DEVICE_A_1X:
+ case PRE_SOFTWARE_RESET_DEVICE_A:
+ case POST_SOFTWARE_RESET_DEVICE_A:
+ dev_idx = 0xC1;
+ break;
+ case MAIN_DEVICE_B_1X:
+ dev_idx = 0x82;
+ break;
+ case COEFF_DEVICE_B_1X:
+ case PRE_DEVICE_B_1X:
+ case PRE_SOFTWARE_RESET_DEVICE_B:
+ case POST_SOFTWARE_RESET_DEVICE_B:
+ dev_idx = 0xC2;
+ break;
+ case MAIN_DEVICE_C_1X:
+ dev_idx = 0x83;
+ break;
+ case COEFF_DEVICE_C_1X:
+ case PRE_DEVICE_C_1X:
+ case PRE_SOFTWARE_RESET_DEVICE_C:
+ case POST_SOFTWARE_RESET_DEVICE_C:
+ dev_idx = 0xC3;
+ break;
+ case MAIN_DEVICE_D_1X:
+ dev_idx = 0x84;
+ break;
+ case COEFF_DEVICE_D_1X:
+ case PRE_DEVICE_D_1X:
+ case PRE_SOFTWARE_RESET_DEVICE_D:
+ case POST_SOFTWARE_RESET_DEVICE_D:
+ dev_idx = 0xC4;
+ break;
+ default:
+ dev_info(tasdevice->dev,
+ "%s: load block: Other Type = 0x%02x\n",
+ __func__, block->type);
+ break;
+ }
+ } else if (fw_fixed_hdr->ppcver >=
+ PPC3_VERSION) {
+ switch (block->type) {
+ case MAIN_ALL_DEVICES_1X:
+ dev_idx = 0x80;
+ break;
+ case MAIN_DEVICE_A_1X:
+ dev_idx = 0x81;
+ break;
+ case COEFF_DEVICE_A_1X:
+ case PRE_DEVICE_A_1X:
+ dev_idx = 0xC1;
+ break;
+ case MAIN_DEVICE_B_1X:
+ dev_idx = 0x82;
+ break;
+ case COEFF_DEVICE_B_1X:
+ case PRE_DEVICE_B_1X:
+ dev_idx = 0xC2;
+ break;
+ case MAIN_DEVICE_C_1X:
+ dev_idx = 0x83;
+ break;
+ case COEFF_DEVICE_C_1X:
+ case PRE_DEVICE_C_1X:
+ dev_idx = 0xC3;
+ break;
+ case MAIN_DEVICE_D_1X:
+ dev_idx = 0x84;
+ break;
+ case COEFF_DEVICE_D_1X:
+ case PRE_DEVICE_D_1X:
+ dev_idx = 0xC4;
+ break;
+ default:
+ dev_info(tasdevice->dev,
+ "%s: load block: Other Type = 0x%02x\n",
+ __func__, block->type);
+ break;
+ }
+ } else {
+ switch (block->type) {
+ case MAIN_ALL_DEVICES:
+ dev_idx = 0|0x80;
+ break;
+ case MAIN_DEVICE_A:
+ dev_idx = 0x81;
+ break;
+ case COEFF_DEVICE_A:
+ case PRE_DEVICE_A:
+ dev_idx = 0xC1;
+ break;
+ case MAIN_DEVICE_B:
+ dev_idx = 0x82;
+ break;
+ case COEFF_DEVICE_B:
+ case PRE_DEVICE_B:
+ dev_idx = 0xC2;
+ break;
+ case MAIN_DEVICE_C:
+ dev_idx = 0x83;
+ break;
+ case COEFF_DEVICE_C:
+ case PRE_DEVICE_C:
+ dev_idx = 0xC3;
+ break;
+ case MAIN_DEVICE_D:
+ dev_idx = 0x84;
+ break;
+ case COEFF_DEVICE_D:
+ case PRE_DEVICE_D:
+ dev_idx = 0xC4;
+ break;
+ default:
+ dev_info(tasdevice->dev,
+ "%s: load block: Other Type = 0x%02x\n",
+ __func__, block->type);
+ break;
+ }
+ }
+
+ for (i = 0, length = 0; i < block->nr_subblocks; i++) {
+ int rc = tasdevice_process_block(tasdevice, data + length,
+ dev_idx, blk_size - length);
+ if (rc < 0) {
+ dev_err(tasdevice->dev,
+ "%s: %u %u sublock write error\n",
+ __func__, length, blk_size);
+ break;
+ }
+ length += (unsigned int)rc;
+ if (blk_size < length) {
+ dev_err(tasdevice->dev, "%s: %u %u out of boundary\n",
+ __func__, length, blk_size);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int fw_parse_variable_hdr(struct tasdevice_priv
+ *tas_priv, struct tasdevice_dspfw_hdr *fw_hdr,
+ const struct firmware *fmw, int offset)
+{
+ const unsigned char *buf = fmw->data;
+ int len = strlen((char *)&buf[offset]);
+
+ len++;
+
+ if (offset + len + 8 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: File Size error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+
+ offset += len;
+
+ fw_hdr->device_family = be32_to_cpup((__be32 *)&buf[offset]);
+ if (fw_hdr->device_family != 0) {
+ dev_err(tas_priv->dev, "%s: not TAS device\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += 4;
+
+ fw_hdr->device = be32_to_cpup((__be32 *)&buf[offset]);
+ if (fw_hdr->device >= TASDEVICE_DSP_TAS_MAX_DEVICE ||
+ fw_hdr->device == 6) {
+ dev_err(tas_priv->dev, "Unsupported dev %d\n", fw_hdr->device);
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += 4;
+ fw_hdr->ndev = deviceNumber[fw_hdr->device];
+
+out:
+ return offset;
+}
+
+static int fw_parse_variable_header_git(struct tasdevice_priv
+ *tas_priv, const struct firmware *fmw, int offset)
+{
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct tasdevice_dspfw_hdr *fw_hdr = &(tas_fmw->fw_hdr);
+
+ offset = fw_parse_variable_hdr(tas_priv, fw_hdr, fmw, offset);
+ if (offset < 0)
+ goto out;
+ if (fw_hdr->ndev != tas_priv->ndev) {
+ dev_err(tas_priv->dev,
+ "%s: ndev(%u) in dspbin mismatch ndev(%u) in DTS\n",
+ __func__, fw_hdr->ndev, tas_priv->ndev);
+ offset = -EINVAL;
+ }
+
+out:
+ return offset;
+}
+
+static int fw_parse_block_data(struct tasdevice_fw *tas_fmw,
+ struct tasdev_blk *block, const struct firmware *fmw, int offset)
+{
+ unsigned char *data = (unsigned char *)fmw->data;
+ int n;
+
+ if (offset + 8 > fmw->size) {
+ dev_err(tas_fmw->dev, "%s: Type error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ block->type = be32_to_cpup((__be32 *)&data[offset]);
+ offset += 4;
+
+ if (tas_fmw->fw_hdr.fixed_hdr.drv_ver >= PPC_DRIVER_CRCCHK) {
+ if (offset + 8 > fmw->size) {
+ dev_err(tas_fmw->dev, "PChkSumPresent error\n");
+ offset = -EINVAL;
+ goto out;
+ }
+ block->is_pchksum_present = data[offset];
+ offset++;
+
+ block->pchksum = data[offset];
+ offset++;
+
+ block->is_ychksum_present = data[offset];
+ offset++;
+
+ block->ychksum = data[offset];
+ offset++;
+ } else {
+ block->is_pchksum_present = 0;
+ block->is_ychksum_present = 0;
+ }
+
+ block->nr_cmds = be32_to_cpup((__be32 *)&data[offset]);
+ offset += 4;
+
+ n = block->nr_cmds * 4;
+ if (offset + n > fmw->size) {
+ dev_err(tas_fmw->dev,
+ "%s: File Size(%lu) error offset = %d n = %d\n",
+ __func__, (unsigned long)fmw->size, offset, n);
+ offset = -EINVAL;
+ goto out;
+ }
+ /* instead of kzalloc+memcpy */
+ block->data = kmemdup(&data[offset], n, GFP_KERNEL);
+ if (!block->data) {
+ offset = -ENOMEM;
+ goto out;
+ }
+ offset += n;
+
+out:
+ return offset;
+}
+
+/* When parsing error occurs, all the memory resource will be released
+ * in the end of tasdevice_rca_ready.
+ */
+static int fw_parse_data(struct tasdevice_fw *tas_fmw,
+ struct tasdevice_data *img_data, const struct firmware *fmw,
+ int offset)
+{
+ const unsigned char *data = (unsigned char *)fmw->data;
+ struct tasdev_blk *blk;
+ unsigned int i;
+ int n;
+
+ if (offset + 64 > fmw->size) {
+ dev_err(tas_fmw->dev, "%s: Name error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ memcpy(img_data->name, &data[offset], 64);
+ offset += 64;
+
+ n = strlen((char *)&data[offset]);
+ n++;
+ if (offset + n + 2 > fmw->size) {
+ dev_err(tas_fmw->dev, "%s: Description error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += n;
+ img_data->nr_blk = be16_to_cpup((__be16 *)&data[offset]);
+ offset += 2;
+
+ img_data->dev_blks = kcalloc(img_data->nr_blk,
+ sizeof(struct tasdev_blk), GFP_KERNEL);
+ if (!img_data->dev_blks) {
+ offset = -ENOMEM;
+ goto out;
+ }
+ for (i = 0; i < img_data->nr_blk; i++) {
+ blk = &(img_data->dev_blks[i]);
+ offset = fw_parse_block_data(tas_fmw, blk, fmw, offset);
+ if (offset < 0) {
+ offset = -EINVAL;
+ goto out;
+ }
+ }
+
+out:
+ return offset;
+}
+
+/* When parsing error occurs, all the memory resource will be released
+ * in the end of tasdevice_rca_ready.
+ */
+static int fw_parse_program_data(struct tasdevice_priv *tas_priv,
+ struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset)
+{
+ unsigned char *buf = (unsigned char *)fmw->data;
+ struct tasdevice_prog *program;
+ int i;
+
+ if (offset + 2 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: File Size error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ tas_fmw->nr_programs = be16_to_cpup((__be16 *)&buf[offset]);
+ offset += 2;
+
+ if (tas_fmw->nr_programs == 0) {
+ /*Not error in calibration Data file, return directly*/
+ dev_info(tas_priv->dev, "%s: No Programs data, maybe calbin\n",
+ __func__);
+ goto out;
+ }
+
+ tas_fmw->programs =
+ kcalloc(tas_fmw->nr_programs, sizeof(struct tasdevice_prog),
+ GFP_KERNEL);
+ if (!tas_fmw->programs) {
+ offset = -ENOMEM;
+ goto out;
+ }
+ for (i = 0; i < tas_fmw->nr_programs; i++) {
+ int n = 0;
+
+ program = &(tas_fmw->programs[i]);
+ if (offset + 64 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: mpName error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += 64;
+
+ n = strlen((char *)&buf[offset]);
+ /* skip '\0' and 5 unused bytes */
+ n += 6;
+ if (offset + n > fmw->size) {
+ dev_err(tas_priv->dev, "Description err\n");
+ offset = -EINVAL;
+ goto out;
+ }
+
+ offset += n;
+
+ offset = fw_parse_data(tas_fmw, &(program->dev_data), fmw,
+ offset);
+ if (offset < 0)
+ goto out;
+ }
+
+out:
+ return offset;
+}
+
+/* When parsing error occurs, all the memory resource will be released
+ * in the end of tasdevice_rca_ready.
+ */
+static int fw_parse_configuration_data(
+ struct tasdevice_priv *tas_priv,
+ struct tasdevice_fw *tas_fmw,
+ const struct firmware *fmw, int offset)
+{
+ unsigned char *data = (unsigned char *)fmw->data;
+ struct tasdevice_config *config;
+ unsigned int i;
+ int n;
+
+ if (offset + 2 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: File Size error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ tas_fmw->nr_configurations = be16_to_cpup((__be16 *)&data[offset]);
+ offset += 2;
+
+ if (tas_fmw->nr_configurations == 0) {
+ dev_err(tas_priv->dev, "%s: Conf is zero\n", __func__);
+ /*Not error for calibration Data file, return directly*/
+ goto out;
+ }
+ tas_fmw->configs = kcalloc(tas_fmw->nr_configurations,
+ sizeof(struct tasdevice_config), GFP_KERNEL);
+ if (!tas_fmw->configs) {
+ offset = -ENOMEM;
+ goto out;
+ }
+ for (i = 0; i < tas_fmw->nr_configurations; i++) {
+ config = &(tas_fmw->configs[i]);
+ if (offset + 64 > fmw->size) {
+ dev_err(tas_priv->dev, "File Size err\n");
+ offset = -EINVAL;
+ goto out;
+ }
+ memcpy(config->name, &data[offset], 64);
+ offset += 64;
+
+ n = strlen((char *)&data[offset]);
+ n += 15;
+ if (offset + n > fmw->size) {
+ dev_err(tas_priv->dev, "Description err\n");
+ offset = -EINVAL;
+ goto out;
+ }
+
+ offset += n;
+
+ offset = fw_parse_data(tas_fmw, &(config->dev_data),
+ fmw, offset);
+ if (offset < 0)
+ goto out;
+ }
+
+out:
+ return offset;
+}
+
+static bool check_inpage_yram_rg(struct tas_crc *cd,
+ unsigned char reg, unsigned char len)
+{
+ bool in = false;
+
+
+ if (reg <= TAS2781_YRAM5_END_REG &&
+ reg >= TAS2781_YRAM5_START_REG) {
+ if (reg + len > TAS2781_YRAM5_END_REG)
+ cd->len = TAS2781_YRAM5_END_REG - reg + 1;
+ else
+ cd->len = len;
+ cd->offset = reg;
+ in = true;
+ } else if (reg < TAS2781_YRAM5_START_REG) {
+ if (reg + len > TAS2781_YRAM5_START_REG) {
+ cd->offset = TAS2781_YRAM5_START_REG;
+ cd->len = len - TAS2781_YRAM5_START_REG + reg;
+ in = true;
+ }
+ }
+
+ return in;
+}
+
+static bool check_inpage_yram_bk1(struct tas_crc *cd,
+ unsigned char page, unsigned char reg, unsigned char len)
+{
+ bool in = false;
+
+ if (page == TAS2781_YRAM1_PAGE) {
+ if (reg >= TAS2781_YRAM1_START_REG) {
+ cd->offset = reg;
+ cd->len = len;
+ in = true;
+ } else if (reg + len > TAS2781_YRAM1_START_REG) {
+ cd->offset = TAS2781_YRAM1_START_REG;
+ cd->len = len - TAS2781_YRAM1_START_REG + reg;
+ in = true;
+ }
+ } else if (page == TAS2781_YRAM3_PAGE)
+ in = check_inpage_yram_rg(cd, reg, len);
+
+ return in;
+}
+
+/* Return Code:
+ * true -- the registers are in the inpage yram
+ * false -- the registers are NOT in the inpage yram
+ */
+static bool check_inpage_yram(struct tas_crc *cd, unsigned char book,
+ unsigned char page, unsigned char reg, unsigned char len)
+{
+ bool in = false;
+
+ if (book == TAS2781_YRAM_BOOK1) {
+ in = check_inpage_yram_bk1(cd, page, reg, len);
+ goto end;
+ }
+ if (book == TAS2781_YRAM_BOOK2 && page == TAS2781_YRAM5_PAGE)
+ in = check_inpage_yram_rg(cd, reg, len);
+
+end:
+ return in;
+}
+
+static bool check_inblock_yram_bk(struct tas_crc *cd,
+ unsigned char page, unsigned char reg, unsigned char len)
+{
+ bool in = false;
+
+ if ((page >= TAS2781_YRAM4_START_PAGE &&
+ page <= TAS2781_YRAM4_END_PAGE) ||
+ (page >= TAS2781_YRAM2_START_PAGE &&
+ page <= TAS2781_YRAM2_END_PAGE)) {
+ if (reg <= TAS2781_YRAM2_END_REG &&
+ reg >= TAS2781_YRAM2_START_REG) {
+ cd->offset = reg;
+ cd->len = len;
+ in = true;
+ } else if (reg < TAS2781_YRAM2_START_REG) {
+ if (reg + len - 1 >= TAS2781_YRAM2_START_REG) {
+ cd->offset = TAS2781_YRAM2_START_REG;
+ cd->len = reg + len - TAS2781_YRAM2_START_REG;
+ in = true;
+ }
+ }
+ }
+
+ return in;
+}
+
+/* Return Code:
+ * true -- the registers are in the inblock yram
+ * false -- the registers are NOT in the inblock yram
+ */
+static bool check_inblock_yram(struct tas_crc *cd, unsigned char book,
+ unsigned char page, unsigned char reg, unsigned char len)
+{
+ bool in = false;
+
+ if (book == TAS2781_YRAM_BOOK1 || book == TAS2781_YRAM_BOOK2)
+ in = check_inblock_yram_bk(cd, page, reg, len);
+
+ return in;
+}
+
+static bool check_yram(struct tas_crc *cd, unsigned char book,
+ unsigned char page, unsigned char reg, unsigned char len)
+{
+ bool in;
+
+ in = check_inpage_yram(cd, book, page, reg, len);
+ if (in)
+ goto end;
+ in = check_inblock_yram(cd, book, page, reg, len);
+
+end:
+ return in;
+}
+
+static int tasdev_multibytes_chksum(struct tasdevice_priv *tasdevice,
+ unsigned short chn, unsigned char book, unsigned char page,
+ unsigned char reg, unsigned int len)
+{
+ struct tas_crc crc_data;
+ unsigned char crc_chksum = 0;
+ unsigned char nBuf1[128];
+ int ret = 0;
+ int i;
+ bool in;
+
+ if ((reg + len - 1) > 127) {
+ ret = -EINVAL;
+ dev_err(tasdevice->dev, "firmware error\n");
+ goto end;
+ }
+
+ if ((book == TASDEVICE_BOOK_ID(TAS2781_SA_COEFF_SWAP_REG))
+ && (page == TASDEVICE_PAGE_ID(TAS2781_SA_COEFF_SWAP_REG))
+ && (reg == TASDEVICE_PAGE_REG(TAS2781_SA_COEFF_SWAP_REG))
+ && (len == 4)) {
+ /*DSP swap command, pass */
+ ret = 0;
+ goto end;
+ }
+
+ in = check_yram(&crc_data, book, page, reg, len);
+ if (!in)
+ goto end;
+
+ if (len == 1) {
+ dev_err(tasdevice->dev, "firmware error\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ ret = tasdevice_dev_bulk_read(tasdevice, chn,
+ TASDEVICE_REG(book, page, crc_data.offset),
+ nBuf1, crc_data.len);
+ if (ret < 0)
+ goto end;
+
+ for (i = 0; i < crc_data.len; i++) {
+ if ((book == TASDEVICE_BOOK_ID(TAS2781_SA_COEFF_SWAP_REG))
+ && (page == TASDEVICE_PAGE_ID(
+ TAS2781_SA_COEFF_SWAP_REG))
+ && ((i + crc_data.offset)
+ >= TASDEVICE_PAGE_REG(TAS2781_SA_COEFF_SWAP_REG))
+ && ((i + crc_data.offset)
+ <= (TASDEVICE_PAGE_REG(TAS2781_SA_COEFF_SWAP_REG)
+ + 4)))
+ /*DSP swap command, bypass */
+ continue;
+ else
+ crc_chksum += crc8(tasdevice->crc8_lkp_tbl, &nBuf1[i],
+ 1, 0);
+ }
+
+ ret = crc_chksum;
+
+end:
+ return ret;
+}
+
+static int do_singlereg_checksum(struct tasdevice_priv *tasdevice,
+ unsigned short chl, unsigned char book, unsigned char page,
+ unsigned char reg, unsigned char val)
+{
+ struct tas_crc crc_data;
+ unsigned int nData1;
+ int ret = 0;
+ bool in;
+
+ if ((book == TASDEVICE_BOOK_ID(TAS2781_SA_COEFF_SWAP_REG))
+ && (page == TASDEVICE_PAGE_ID(TAS2781_SA_COEFF_SWAP_REG))
+ && (reg >= TASDEVICE_PAGE_REG(TAS2781_SA_COEFF_SWAP_REG))
+ && (reg <= (TASDEVICE_PAGE_REG(
+ TAS2781_SA_COEFF_SWAP_REG) + 4))) {
+ /*DSP swap command, pass */
+ ret = 0;
+ goto end;
+ }
+
+ in = check_yram(&crc_data, book, page, reg, 1);
+ if (!in)
+ goto end;
+ ret = tasdevice_dev_read(tasdevice, chl,
+ TASDEVICE_REG(book, page, reg), &nData1);
+ if (ret < 0)
+ goto end;
+
+ if (nData1 != val) {
+ dev_err(tasdevice->dev,
+ "B[0x%x]P[0x%x]R[0x%x] W[0x%x], R[0x%x]\n",
+ book, page, reg, val, nData1);
+ tasdevice->tasdevice[chl].err_code |= ERROR_YRAM_CRCCHK;
+ ret = -EAGAIN;
+ goto end;
+ }
+
+ ret = crc8(tasdevice->crc8_lkp_tbl, &val, 1, 0);
+
+end:
+ return ret;
+}
+
+static void set_err_prg_cfg(unsigned int type, struct tasdevice *dev)
+{
+ if ((type == MAIN_ALL_DEVICES) || (type == MAIN_DEVICE_A)
+ || (type == MAIN_DEVICE_B) || (type == MAIN_DEVICE_C)
+ || (type == MAIN_DEVICE_D))
+ dev->cur_prog = -1;
+ else
+ dev->cur_conf = -1;
+}
+
+static int tasdev_bytes_chksum(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block, int chn, unsigned char book,
+ unsigned char page, unsigned char reg, unsigned int len,
+ unsigned char val, unsigned char *crc_chksum)
+{
+ int ret;
+
+ if (len > 1)
+ ret = tasdev_multibytes_chksum(tas_priv, chn, book, page, reg,
+ len);
+ else
+ ret = do_singlereg_checksum(tas_priv, chn, book, page, reg,
+ val);
+
+ if (ret > 0) {
+ *crc_chksum += (unsigned char)ret;
+ goto end;
+ }
+
+ if (ret != -EAGAIN)
+ goto end;
+
+ block->nr_retry--;
+ if (block->nr_retry > 0)
+ goto end;
+
+ set_err_prg_cfg(block->type, &tas_priv->tasdevice[chn]);
+
+end:
+ return ret;
+}
+
+static int tasdev_multibytes_wr(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block, int chn, unsigned char book,
+ unsigned char page, unsigned char reg, unsigned char *data,
+ unsigned int len, unsigned int *nr_cmds,
+ unsigned char *crc_chksum)
+{
+ int ret;
+
+ if (len > 1) {
+ ret = tasdevice_dev_bulk_write(tas_priv, chn,
+ TASDEVICE_REG(book, page, reg), data + 3, len);
+ if (ret < 0)
+ goto end;
+ if (block->is_ychksum_present)
+ ret = tasdev_bytes_chksum(tas_priv, block, chn,
+ book, page, reg, len, 0, crc_chksum);
+ } else {
+ ret = tasdevice_dev_write(tas_priv, chn,
+ TASDEVICE_REG(book, page, reg), data[3]);
+ if (ret < 0)
+ goto end;
+ if (block->is_ychksum_present)
+ ret = tasdev_bytes_chksum(tas_priv, block, chn, book,
+ page, reg, 1, data[3], crc_chksum);
+ }
+
+ if (!block->is_ychksum_present || ret >= 0) {
+ *nr_cmds += 1;
+ if (len >= 2)
+ *nr_cmds += ((len - 2) / 4) + 1;
+ }
+
+end:
+ return ret;
+}
+
+static int tasdev_block_chksum(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block, int chn)
+{
+ unsigned int nr_value;
+ int ret;
+
+ ret = tasdevice_dev_read(tas_priv, chn, TASDEVICE_I2CChecksum,
+ &nr_value);
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "%s: Chn %d\n", __func__, chn);
+ set_err_prg_cfg(block->type, &tas_priv->tasdevice[chn]);
+ goto end;
+ }
+
+ if ((nr_value & 0xff) != block->pchksum) {
+ dev_err(tas_priv->dev, "%s: Blk PChkSum Chn %d ", __func__,
+ chn);
+ dev_err(tas_priv->dev, "PChkSum = 0x%x, Reg = 0x%x\n",
+ block->pchksum, (nr_value & 0xff));
+ tas_priv->tasdevice[chn].err_code |= ERROR_PRAM_CRCCHK;
+ ret = -EAGAIN;
+ block->nr_retry--;
+
+ if (block->nr_retry <= 0)
+ set_err_prg_cfg(block->type,
+ &tas_priv->tasdevice[chn]);
+ } else
+ tas_priv->tasdevice[chn].err_code &= ~ERROR_PRAM_CRCCHK;
+
+end:
+ return ret;
+}
+
+static int tasdev_load_blk(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block, int chn)
+{
+ unsigned int sleep_time;
+ unsigned int len;
+ unsigned int nr_cmds;
+ unsigned char *data = block->data;
+ unsigned char crc_chksum = 0;
+ unsigned char offset;
+ unsigned char book;
+ unsigned char page;
+ unsigned char val;
+ int ret = 0;
+
+ while (block->nr_retry > 0) {
+ if (block->is_pchksum_present) {
+ ret = tasdevice_dev_write(tas_priv, chn,
+ TASDEVICE_I2CChecksum, 0);
+ if (ret < 0)
+ break;
+ }
+
+ if (block->is_ychksum_present)
+ crc_chksum = 0;
+
+ nr_cmds = 0;
+
+ while (nr_cmds < block->nr_cmds) {
+ data = block->data + nr_cmds * 4;
+
+ book = data[0];
+ page = data[1];
+ offset = data[2];
+ val = data[3];
+
+ nr_cmds++;
+ /*Single byte write*/
+ if (offset <= 0x7F) {
+ ret = tasdevice_dev_write(tas_priv, chn,
+ TASDEVICE_REG(book, page, offset),
+ val);
+ if (ret < 0)
+ goto end;
+ if (block->is_ychksum_present) {
+ ret = tasdev_bytes_chksum(tas_priv,
+ block, chn, book, page, offset,
+ 1, val, &crc_chksum);
+ if (ret < 0)
+ break;
+ }
+ continue;
+ }
+ /*sleep command*/
+ if (offset == 0x81) {
+ /*book -- data[0] page -- data[1]*/
+ sleep_time = ((book << 8) + page)*1000;
+ usleep_range(sleep_time, sleep_time + 50);
+ continue;
+ }
+ /*Multiple bytes write*/
+ if (offset == 0x85) {
+ data += 4;
+ len = (book << 8) + page;
+ book = data[0];
+ page = data[1];
+ offset = data[2];
+ ret = tasdev_multibytes_wr(tas_priv,
+ block, chn, book, page, offset, data,
+ len, &nr_cmds, &crc_chksum);
+ if (ret < 0)
+ break;
+ }
+ }
+ if (ret == -EAGAIN) {
+ if (block->nr_retry > 0)
+ continue;
+ } else if (ret < 0) /*err in current device, skip it*/
+ break;
+
+ if (block->is_pchksum_present) {
+ ret = tasdev_block_chksum(tas_priv, block, chn);
+ if (ret == -EAGAIN) {
+ if (block->nr_retry > 0)
+ continue;
+ } else if (ret < 0) /*err in current device, skip it*/
+ break;
+ }
+
+ if (block->is_ychksum_present) {
+ /* TBD, open it when FW ready */
+ dev_err(tas_priv->dev,
+ "Blk YChkSum: FW = 0x%x, YCRC = 0x%x\n",
+ block->ychksum, crc_chksum);
+
+ tas_priv->tasdevice[chn].err_code &=
+ ~ERROR_YRAM_CRCCHK;
+ ret = 0;
+ }
+ /*skip current blk*/
+ break;
+ }
+
+end:
+ return ret;
+}
+
+static int tasdevice_load_block(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block)
+{
+ int chnend = 0;
+ int ret = 0;
+ int chn = 0;
+ int rc = 0;
+
+ switch (block->type) {
+ case MAIN_ALL_DEVICES:
+ chn = 0;
+ chnend = tas_priv->ndev;
+ break;
+ case MAIN_DEVICE_A:
+ case COEFF_DEVICE_A:
+ case PRE_DEVICE_A:
+ chn = 0;
+ chnend = 1;
+ break;
+ case MAIN_DEVICE_B:
+ case COEFF_DEVICE_B:
+ case PRE_DEVICE_B:
+ chn = 1;
+ chnend = 2;
+ break;
+ case MAIN_DEVICE_C:
+ case COEFF_DEVICE_C:
+ case PRE_DEVICE_C:
+ chn = 2;
+ chnend = 3;
+ break;
+ case MAIN_DEVICE_D:
+ case COEFF_DEVICE_D:
+ case PRE_DEVICE_D:
+ chn = 3;
+ chnend = 4;
+ break;
+ default:
+ dev_dbg(tas_priv->dev, "load blk: Other Type = 0x%02x\n",
+ block->type);
+ break;
+ }
+
+ for (; chn < chnend; chn++) {
+ block->nr_retry = 6;
+ if (tas_priv->tasdevice[chn].is_loading == false)
+ continue;
+ ret = tasdev_load_blk(tas_priv, block, chn);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "dev %d, Blk (%d) load error\n",
+ chn, block->type);
+ rc |= ret;
+ }
+
+ return rc;
+}
+
+static int dspfw_default_callback(struct tasdevice_priv *tas_priv,
+ unsigned int drv_ver, unsigned int ppcver)
+{
+ int rc = 0;
+
+ if (drv_ver == 0x100) {
+ if (ppcver >= PPC3_VERSION) {
+ tas_priv->fw_parse_variable_header =
+ fw_parse_variable_header_kernel;
+ tas_priv->fw_parse_program_data =
+ fw_parse_program_data_kernel;
+ tas_priv->fw_parse_configuration_data =
+ fw_parse_configuration_data_kernel;
+ tas_priv->tasdevice_load_block =
+ tasdevice_load_block_kernel;
+ } else {
+ switch (ppcver) {
+ case 0x00:
+ tas_priv->fw_parse_variable_header =
+ fw_parse_variable_header_git;
+ tas_priv->fw_parse_program_data =
+ fw_parse_program_data;
+ tas_priv->fw_parse_configuration_data =
+ fw_parse_configuration_data;
+ tas_priv->tasdevice_load_block =
+ tasdevice_load_block;
+ break;
+ default:
+ dev_err(tas_priv->dev,
+ "%s: PPCVer must be 0x0 or 0x%02x",
+ __func__, PPC3_VERSION);
+ dev_err(tas_priv->dev, " Current:0x%02x\n",
+ ppcver);
+ rc = -EINVAL;
+ break;
+ }
+ }
+ } else {
+ dev_err(tas_priv->dev,
+ "DrvVer must be 0x0, 0x230 or above 0x230 ");
+ dev_err(tas_priv->dev, "current is 0x%02x\n", drv_ver);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static int load_calib_data(struct tasdevice_priv *tas_priv,
+ struct tasdevice_data *dev_data)
+{
+ struct tasdev_blk *block;
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < dev_data->nr_blk; i++) {
+ block = &(dev_data->dev_blks[i]);
+ ret = tasdevice_load_block(tas_priv, block);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static int fw_parse_header(struct tasdevice_priv *tas_priv,
+ struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset)
+{
+ struct tasdevice_dspfw_hdr *fw_hdr = &(tas_fmw->fw_hdr);
+ struct tasdevice_fw_fixed_hdr *fw_fixed_hdr = &(fw_hdr->fixed_hdr);
+ const unsigned char magic_number[] = { 0x35, 0x35, 0x35, 0x32 };
+ const unsigned char *buf = (unsigned char *)fmw->data;
+
+ if (offset + 92 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: File Size error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ if (memcmp(&buf[offset], magic_number, 4)) {
+ dev_err(tas_priv->dev, "%s: Magic num NOT match\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += 4;
+
+ /* Convert data[offset], data[offset + 1], data[offset + 2] and
+ * data[offset + 3] into host
+ */
+ fw_fixed_hdr->fwsize = be32_to_cpup((__be32 *)&buf[offset]);
+ offset += 4;
+ if (fw_fixed_hdr->fwsize != fmw->size) {
+ dev_err(tas_priv->dev, "File size not match, %lu %u",
+ (unsigned long)fmw->size, fw_fixed_hdr->fwsize);
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += 4;
+ fw_fixed_hdr->ppcver = be32_to_cpup((__be32 *)&buf[offset]);
+ offset += 8;
+ fw_fixed_hdr->drv_ver = be32_to_cpup((__be32 *)&buf[offset]);
+ offset += 72;
+
+ out:
+ return offset;
+}
+
+static int fw_parse_variable_hdr_cal(struct tasdevice_priv *tas_priv,
+ struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset)
+{
+ struct tasdevice_dspfw_hdr *fw_hdr = &(tas_fmw->fw_hdr);
+
+ offset = fw_parse_variable_hdr(tas_priv, fw_hdr, fmw, offset);
+ if (offset < 0)
+ goto out;
+ if (fw_hdr->ndev != 1) {
+ dev_err(tas_priv->dev,
+ "%s: calbin must be 1, but currently ndev(%u)\n",
+ __func__, fw_hdr->ndev);
+ offset = -EINVAL;
+ }
+
+out:
+ return offset;
+}
+
+/* When calibrated data parsing error occurs, DSP can still work with default
+ * calibrated data, memory resource related to calibrated data will be
+ * released in the tasdevice_codec_remove.
+ */
+static int fw_parse_calibration_data(struct tasdevice_priv *tas_priv,
+ struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset)
+{
+ struct tasdevice_calibration *calibration;
+ unsigned char *data = (unsigned char *)fmw->data;
+ unsigned int i, n;
+
+ if (offset + 2 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: Calibrations error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ tas_fmw->nr_calibrations = be16_to_cpup((__be16 *)&data[offset]);
+ offset += 2;
+
+ if (tas_fmw->nr_calibrations != 1) {
+ dev_err(tas_priv->dev,
+ "%s: only supports one calibration (%d)!\n",
+ __func__, tas_fmw->nr_calibrations);
+ goto out;
+ }
+
+ tas_fmw->calibrations = kcalloc(tas_fmw->nr_calibrations,
+ sizeof(struct tasdevice_calibration), GFP_KERNEL);
+ if (!tas_fmw->calibrations) {
+ offset = -ENOMEM;
+ goto out;
+ }
+ for (i = 0; i < tas_fmw->nr_calibrations; i++) {
+ if (offset + 64 > fmw->size) {
+ dev_err(tas_priv->dev, "Calibrations error\n");
+ offset = -EINVAL;
+ goto out;
+ }
+ calibration = &(tas_fmw->calibrations[i]);
+ offset += 64;
+
+ n = strlen((char *)&data[offset]);
+ /* skip '\0' and 2 unused bytes */
+ n += 3;
+ if (offset + n > fmw->size) {
+ dev_err(tas_priv->dev, "Description err\n");
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += n;
+
+ offset = fw_parse_data(tas_fmw, &(calibration->dev_data), fmw,
+ offset);
+ if (offset < 0)
+ goto out;
+ }
+
+out:
+ return offset;
+}
+
+int tas2781_load_calibration(void *context, char *file_name,
+ unsigned short i)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context;
+ struct tasdevice *tasdev = &(tas_priv->tasdevice[i]);
+ const struct firmware *fw_entry;
+ struct tasdevice_fw *tas_fmw;
+ struct firmware fmw;
+ int offset = 0;
+ int ret;
+
+ ret = request_firmware(&fw_entry, file_name, tas_priv->dev);
+ if (ret) {
+ dev_err(tas_priv->dev, "%s: Request firmware %s failed\n",
+ __func__, file_name);
+ goto out;
+ }
+
+ if (!fw_entry->size) {
+ dev_err(tas_priv->dev, "%s: file read error: size = %lu\n",
+ __func__, (unsigned long)fw_entry->size);
+ ret = -EINVAL;
+ goto out;
+ }
+ fmw.size = fw_entry->size;
+ fmw.data = fw_entry->data;
+
+ tas_fmw = tasdev->cali_data_fmw = kzalloc(sizeof(struct tasdevice_fw),
+ GFP_KERNEL);
+ if (!tasdev->cali_data_fmw) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ tas_fmw->dev = tas_priv->dev;
+ offset = fw_parse_header(tas_priv, tas_fmw, &fmw, offset);
+ if (offset == -EINVAL) {
+ dev_err(tas_priv->dev, "fw_parse_header EXIT!\n");
+ ret = offset;
+ goto out;
+ }
+ offset = fw_parse_variable_hdr_cal(tas_priv, tas_fmw, &fmw, offset);
+ if (offset == -EINVAL) {
+ dev_err(tas_priv->dev,
+ "%s: fw_parse_variable_header_cal EXIT!\n", __func__);
+ ret = offset;
+ goto out;
+ }
+ offset = fw_parse_program_data(tas_priv, tas_fmw, &fmw, offset);
+ if (offset < 0) {
+ dev_err(tas_priv->dev, "fw_parse_program_data EXIT!\n");
+ ret = offset;
+ goto out;
+ }
+ offset = fw_parse_configuration_data(tas_priv, tas_fmw, &fmw, offset);
+ if (offset < 0) {
+ dev_err(tas_priv->dev, "fw_parse_configuration_data EXIT!\n");
+ ret = offset;
+ goto out;
+ }
+ offset = fw_parse_calibration_data(tas_priv, tas_fmw, &fmw, offset);
+ if (offset < 0) {
+ dev_err(tas_priv->dev, "fw_parse_calibration_data EXIT!\n");
+ ret = offset;
+ goto out;
+ }
+
+out:
+ if (fw_entry)
+ release_firmware(fw_entry);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tas2781_load_calibration, SND_SOC_TAS2781_FMWLIB);
+
+static int tasdevice_dspfw_ready(const struct firmware *fmw,
+ void *context)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice_fw_fixed_hdr *fw_fixed_hdr;
+ struct tasdevice_fw *tas_fmw;
+ int offset = 0;
+ int ret = 0;
+
+ if (!fmw || !fmw->data) {
+ dev_err(tas_priv->dev, "%s: Failed to read firmware %s\n",
+ __func__, tas_priv->coef_binaryname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ tas_priv->fmw = kzalloc(sizeof(struct tasdevice_fw), GFP_KERNEL);
+ if (!tas_priv->fmw) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ tas_fmw = tas_priv->fmw;
+ tas_fmw->dev = tas_priv->dev;
+ offset = fw_parse_header(tas_priv, tas_fmw, fmw, offset);
+
+ if (offset == -EINVAL) {
+ ret = -EINVAL;
+ goto out;
+ }
+ fw_fixed_hdr = &(tas_fmw->fw_hdr.fixed_hdr);
+ /* Support different versions of firmware */
+ switch (fw_fixed_hdr->drv_ver) {
+ case 0x301:
+ case 0x302:
+ case 0x502:
+ tas_priv->fw_parse_variable_header =
+ fw_parse_variable_header_kernel;
+ tas_priv->fw_parse_program_data =
+ fw_parse_program_data_kernel;
+ tas_priv->fw_parse_configuration_data =
+ fw_parse_configuration_data_kernel;
+ tas_priv->tasdevice_load_block =
+ tasdevice_load_block_kernel;
+ break;
+ case 0x202:
+ case 0x400:
+ tas_priv->fw_parse_variable_header =
+ fw_parse_variable_header_git;
+ tas_priv->fw_parse_program_data =
+ fw_parse_program_data;
+ tas_priv->fw_parse_configuration_data =
+ fw_parse_configuration_data;
+ tas_priv->tasdevice_load_block =
+ tasdevice_load_block;
+ break;
+ default:
+ ret = dspfw_default_callback(tas_priv,
+ fw_fixed_hdr->drv_ver, fw_fixed_hdr->ppcver);
+ if (ret)
+ goto out;
+ break;
+ }
+
+ offset = tas_priv->fw_parse_variable_header(tas_priv, fmw, offset);
+ if (offset < 0) {
+ ret = offset;
+ goto out;
+ }
+ offset = tas_priv->fw_parse_program_data(tas_priv, tas_fmw, fmw,
+ offset);
+ if (offset < 0) {
+ ret = offset;
+ goto out;
+ }
+ offset = tas_priv->fw_parse_configuration_data(tas_priv,
+ tas_fmw, fmw, offset);
+ if (offset < 0)
+ ret = offset;
+
+out:
+ return ret;
+}
+
+int tasdevice_dsp_parser(void *context)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context;
+ const struct firmware *fw_entry;
+ int ret;
+
+ ret = request_firmware(&fw_entry, tas_priv->coef_binaryname,
+ tas_priv->dev);
+ if (ret) {
+ dev_err(tas_priv->dev, "%s: load %s error\n", __func__,
+ tas_priv->coef_binaryname);
+ goto out;
+ }
+
+ ret = tasdevice_dspfw_ready(fw_entry, tas_priv);
+ release_firmware(fw_entry);
+ fw_entry = NULL;
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_dsp_parser, SND_SOC_TAS2781_FMWLIB);
+
+static void tas2781_clear_calfirmware(struct tasdevice_fw *tas_fmw)
+{
+ struct tasdevice_calibration *calibration;
+ struct tasdev_blk *block;
+ struct tasdevice_data *im;
+ unsigned int blks;
+ int i;
+
+ if (!tas_fmw->calibrations)
+ goto out;
+
+ for (i = 0; i < tas_fmw->nr_calibrations; i++) {
+ calibration = &(tas_fmw->calibrations[i]);
+ if (!calibration)
+ continue;
+
+ im = &(calibration->dev_data);
+
+ if (!im->dev_blks)
+ continue;
+
+ for (blks = 0; blks < im->nr_blk; blks++) {
+ block = &(im->dev_blks[blks]);
+ if (!block)
+ continue;
+ kfree(block->data);
+ }
+ kfree(im->dev_blks);
+ }
+ kfree(tas_fmw->calibrations);
+out:
+ kfree(tas_fmw);
+}
+
+void tasdevice_calbin_remove(void *context)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice *tasdev;
+ int i;
+
+ if (!tas_priv)
+ return;
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ tasdev = &(tas_priv->tasdevice[i]);
+ if (!tasdev->cali_data_fmw)
+ continue;
+ tas2781_clear_calfirmware(tasdev->cali_data_fmw);
+ tasdev->cali_data_fmw = NULL;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_calbin_remove, SND_SOC_TAS2781_FMWLIB);
+
+void tasdevice_config_info_remove(void *context)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice_rca *rca = &(tas_priv->rcabin);
+ struct tasdevice_config_info **ci = rca->cfg_info;
+ int i, j;
+
+ if (!ci)
+ return;
+ for (i = 0; i < rca->ncfgs; i++) {
+ if (!ci[i])
+ continue;
+ if (ci[i]->blk_data) {
+ for (j = 0; j < (int)ci[i]->real_nblocks; j++) {
+ if (!ci[i]->blk_data[j])
+ continue;
+ kfree(ci[i]->blk_data[j]->regdata);
+ kfree(ci[i]->blk_data[j]);
+ }
+ kfree(ci[i]->blk_data);
+ }
+ kfree(ci[i]);
+ }
+ kfree(ci);
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_config_info_remove, SND_SOC_TAS2781_FMWLIB);
+
+static int tasdevice_load_data(struct tasdevice_priv *tas_priv,
+ struct tasdevice_data *dev_data)
+{
+ struct tasdev_blk *block;
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < dev_data->nr_blk; i++) {
+ block = &(dev_data->dev_blks[i]);
+ ret = tas_priv->tasdevice_load_block(tas_priv, block);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+int tasdevice_select_tuningprm_cfg(void *context, int prm_no,
+ int cfg_no, int rca_conf_no)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice_rca *rca = &(tas_priv->rcabin);
+ struct tasdevice_config_info **cfg_info = rca->cfg_info;
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct tasdevice_prog *program;
+ struct tasdevice_config *conf;
+ int prog_status = 0;
+ int status, i;
+
+ if (!tas_fmw) {
+ dev_err(tas_priv->dev, "%s: Firmware is NULL\n", __func__);
+ goto out;
+ }
+
+ if (cfg_no >= tas_fmw->nr_configurations) {
+ dev_err(tas_priv->dev,
+ "%s: cfg(%d) is not in range of conf %u\n",
+ __func__, cfg_no, tas_fmw->nr_configurations);
+ goto out;
+ }
+
+ if (prm_no >= tas_fmw->nr_programs) {
+ dev_err(tas_priv->dev,
+ "%s: prm(%d) is not in range of Programs %u\n",
+ __func__, prm_no, tas_fmw->nr_programs);
+ goto out;
+ }
+
+ if (rca_conf_no >= rca->ncfgs || rca_conf_no < 0 ||
+ !cfg_info) {
+ dev_err(tas_priv->dev,
+ "conf_no:%d should be in range from 0 to %u\n",
+ rca_conf_no, rca->ncfgs-1);
+ goto out;
+ }
+
+ conf = &(tas_fmw->configs[cfg_no]);
+ for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) {
+ if (cfg_info[rca_conf_no]->active_dev & (1 << i)) {
+ if (tas_priv->tasdevice[i].cur_prog != prm_no
+ || tas_priv->force_fwload_status) {
+ tas_priv->tasdevice[i].cur_conf = -1;
+ tas_priv->tasdevice[i].is_loading = true;
+ prog_status++;
+ }
+ } else
+ tas_priv->tasdevice[i].is_loading = false;
+ tas_priv->tasdevice[i].is_loaderr = false;
+ }
+
+ if (prog_status) {
+ program = &(tas_fmw->programs[prm_no]);
+ tasdevice_load_data(tas_priv, &(program->dev_data));
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (tas_priv->tasdevice[i].is_loaderr == true)
+ continue;
+ else if (tas_priv->tasdevice[i].is_loaderr == false
+ && tas_priv->tasdevice[i].is_loading == true) {
+ struct tasdevice_fw *cal_fmw =
+ tas_priv->tasdevice[i].cali_data_fmw;
+
+ if (cal_fmw) {
+ struct tasdevice_calibration
+ *cal = cal_fmw->calibrations;
+
+ if (cal)
+ load_calib_data(tas_priv,
+ &(cal->dev_data));
+ }
+ tas_priv->tasdevice[i].cur_prog = prm_no;
+ }
+ }
+ }
+
+ for (i = 0, status = 0; i < tas_priv->ndev; i++) {
+ if (tas_priv->tasdevice[i].cur_conf != cfg_no
+ && (cfg_info[rca_conf_no]->active_dev & (1 << i))
+ && (tas_priv->tasdevice[i].is_loaderr == false)) {
+ status++;
+ tas_priv->tasdevice[i].is_loading = true;
+ } else
+ tas_priv->tasdevice[i].is_loading = false;
+ }
+
+ if (status) {
+ status = 0;
+ tasdevice_load_data(tas_priv, &(conf->dev_data));
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (tas_priv->tasdevice[i].is_loaderr == true) {
+ status |= 1 << (i + 4);
+ continue;
+ } else if (tas_priv->tasdevice[i].is_loaderr == false
+ && tas_priv->tasdevice[i].is_loading == true)
+ tas_priv->tasdevice[i].cur_conf = cfg_no;
+ }
+ } else
+ dev_dbg(tas_priv->dev, "%s: Unneeded loading dsp conf %d\n",
+ __func__, cfg_no);
+
+ status |= cfg_info[rca_conf_no]->active_dev;
+
+out:
+ return prog_status;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_select_tuningprm_cfg,
+ SND_SOC_TAS2781_FMWLIB);
+
+int tasdevice_prmg_load(void *context, int prm_no)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct tasdevice_prog *program;
+ int prog_status = 0;
+ int i;
+
+ if (!tas_fmw) {
+ dev_err(tas_priv->dev, "%s: Firmware is NULL\n", __func__);
+ goto out;
+ }
+
+ if (prm_no >= tas_fmw->nr_programs) {
+ dev_err(tas_priv->dev,
+ "%s: prm(%d) is not in range of Programs %u\n",
+ __func__, prm_no, tas_fmw->nr_programs);
+ goto out;
+ }
+
+ for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) {
+ if (tas_priv->tasdevice[i].cur_prog != prm_no) {
+ tas_priv->tasdevice[i].cur_conf = -1;
+ tas_priv->tasdevice[i].is_loading = true;
+ prog_status++;
+ }
+ }
+
+ if (prog_status) {
+ program = &(tas_fmw->programs[prm_no]);
+ tasdevice_load_data(tas_priv, &(program->dev_data));
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (tas_priv->tasdevice[i].is_loaderr == true)
+ continue;
+ else if (tas_priv->tasdevice[i].is_loaderr == false
+ && tas_priv->tasdevice[i].is_loading == true)
+ tas_priv->tasdevice[i].cur_prog = prm_no;
+ }
+ }
+
+out:
+ return prog_status;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_load, SND_SOC_TAS2781_FMWLIB);
+
+int tasdevice_prmg_calibdata_load(void *context, int prm_no)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct tasdevice_prog *program;
+ int prog_status = 0;
+ int i;
+
+ if (!tas_fmw) {
+ dev_err(tas_priv->dev, "%s: Firmware is NULL\n", __func__);
+ goto out;
+ }
+
+ if (prm_no >= tas_fmw->nr_programs) {
+ dev_err(tas_priv->dev,
+ "%s: prm(%d) is not in range of Programs %u\n",
+ __func__, prm_no, tas_fmw->nr_programs);
+ goto out;
+ }
+
+ for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) {
+ if (tas_priv->tasdevice[i].cur_prog != prm_no) {
+ tas_priv->tasdevice[i].cur_conf = -1;
+ tas_priv->tasdevice[i].is_loading = true;
+ prog_status++;
+ }
+ tas_priv->tasdevice[i].is_loaderr = false;
+ }
+
+ if (prog_status) {
+ program = &(tas_fmw->programs[prm_no]);
+ tasdevice_load_data(tas_priv, &(program->dev_data));
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (tas_priv->tasdevice[i].is_loaderr == true)
+ continue;
+ else if (tas_priv->tasdevice[i].is_loaderr == false
+ && tas_priv->tasdevice[i].is_loading == true) {
+ struct tasdevice_fw *cal_fmw =
+ tas_priv->tasdevice[i].cali_data_fmw;
+
+ if (cal_fmw) {
+ struct tasdevice_calibration *cal =
+ cal_fmw->calibrations;
+
+ if (cal)
+ load_calib_data(tas_priv,
+ &(cal->dev_data));
+ }
+ tas_priv->tasdevice[i].cur_prog = prm_no;
+ }
+ }
+ }
+
+out:
+ return prog_status;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_calibdata_load,
+ SND_SOC_TAS2781_FMWLIB);
+
+void tasdevice_tuning_switch(void *context, int state)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ int profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
+
+ if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) {
+ dev_err(tas_priv->dev, "DSP bin file not loaded\n");
+ return;
+ }
+
+ if (state == 0) {
+ if (tas_priv->cur_prog < tas_fmw->nr_programs) {
+ /*dsp mode or tuning mode*/
+ profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
+ tasdevice_select_tuningprm_cfg(tas_priv,
+ tas_priv->cur_prog, tas_priv->cur_conf,
+ profile_cfg_id);
+ }
+
+ tasdevice_select_cfg_blk(tas_priv, profile_cfg_id,
+ TASDEVICE_BIN_BLK_PRE_POWER_UP);
+ } else
+ tasdevice_select_cfg_blk(tas_priv, profile_cfg_id,
+ TASDEVICE_BIN_BLK_PRE_SHUTDOWN);
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_tuning_switch,
+ SND_SOC_TAS2781_FMWLIB);
+
+MODULE_DESCRIPTION("Texas Firmware Support");
+MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
new file mode 100644
index 000000000000..4c59429a42b7
--- /dev/null
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -0,0 +1,763 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier
+//
+// Copyright (C) 2022 - 2023 Texas Instruments Incorporated
+// https://www.ti.com
+//
+// The TAS2781 driver implements a flexible and configurable
+// algo coefficient setting for one, two, or even multiple
+// TAS2781 chips.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+// Author: Kevin Lu <kevin-lu@ti.com>
+//
+
+#include <linux/crc8.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tas2781.h>
+#include <sound/tlv.h>
+#include <sound/tas2781-tlv.h>
+
+static const struct i2c_device_id tasdevice_id[] = {
+ { "tas2781", TAS2781 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tasdevice_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tasdevice_of_match[] = {
+ { .compatible = "ti,tas2781" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tasdevice_of_match);
+#endif
+
+/**
+ * tas2781_digital_getvol - get the volum control
+ * @kcontrol: control pointer
+ * @ucontrol: User data
+ * Customer Kcontrol for tas2781 is primarily for regmap booking, paging
+ * depends on internal regmap mechanism.
+ * tas2781 contains book and page two-level register map, especially
+ * book switching will set the register BXXP00R7F, after switching to the
+ * correct book, then leverage the mechanism for paging to access the
+ * register.
+ */
+static int tas2781_digital_getvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ return tasdevice_digital_getvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ return tasdevice_digital_putvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ return tasdevice_amp_getvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv =
+ snd_soc_component_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ return tasdevice_amp_putvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv =
+ snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status;
+ dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
+ tas_priv->force_fwload_status ? "ON" : "OFF");
+
+ return 0;
+}
+
+static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv =
+ snd_soc_component_get_drvdata(component);
+ bool change, val = (bool)ucontrol->value.integer.value[0];
+
+ if (tas_priv->force_fwload_status == val)
+ change = false;
+ else {
+ change = true;
+ tas_priv->force_fwload_status = val;
+ }
+ dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
+ tas_priv->force_fwload_status ? "ON" : "OFF");
+
+ return change;
+}
+
+static const struct snd_kcontrol_new tas2781_snd_controls[] = {
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL,
+ 1, 0, 20, 0, tas2781_amp_getvol,
+ tas2781_amp_putvol, amp_vol_tlv),
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain", TAS2781_DVC_LVL,
+ 0, 0, 200, 1, tas2781_digital_getvol,
+ tas2781_digital_putvol, dvc_tlv),
+ SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
+ tas2781_force_fwload_get, tas2781_force_fwload_put),
+};
+
+static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ int ret = 0;
+
+ if (tas_priv->rcabin.profile_cfg_id !=
+ ucontrol->value.integer.value[0]) {
+ tas_priv->rcabin.profile_cfg_id =
+ ucontrol->value.integer.value[0];
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ struct tasdevice_fw *tas_fw = tas_priv->fmw;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = (int)tas_fw->nr_programs;
+
+ return 0;
+}
+
+static int tasdevice_info_configurations(
+ struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec =
+ snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ struct tasdevice_fw *tas_fw = tas_priv->fmw;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = (int)tas_fw->nr_configurations - 1;
+
+ return 0;
+}
+
+static int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;
+
+ return 0;
+}
+
+static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
+
+ return 0;
+}
+
+static int tasdevice_create_control(struct tasdevice_priv *tas_priv)
+{
+ struct snd_kcontrol_new *prof_ctrls;
+ int nr_controls = 1;
+ int mix_index = 0;
+ int ret;
+ char *name;
+
+ prof_ctrls = devm_kcalloc(tas_priv->dev, nr_controls,
+ sizeof(prof_ctrls[0]), GFP_KERNEL);
+ if (!prof_ctrls) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Create a mixer item for selecting the active profile */
+ name = devm_kzalloc(tas_priv->dev, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ GFP_KERNEL);
+ if (!name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "Speaker Profile Id");
+ prof_ctrls[mix_index].name = name;
+ prof_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ prof_ctrls[mix_index].info = tasdevice_info_profile;
+ prof_ctrls[mix_index].get = tasdevice_get_profile_id;
+ prof_ctrls[mix_index].put = tasdevice_set_profile_id;
+ mix_index++;
+
+ ret = snd_soc_add_component_controls(tas_priv->codec,
+ prof_ctrls, nr_controls < mix_index ? nr_controls : mix_index);
+
+out:
+ return ret;
+}
+
+static int tasdevice_program_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = tas_priv->cur_prog;
+
+ return 0;
+}
+
+static int tasdevice_program_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ unsigned int nr_program = ucontrol->value.integer.value[0];
+ int ret = 0;
+
+ if (tas_priv->cur_prog != nr_program) {
+ tas_priv->cur_prog = nr_program;
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int tasdevice_configuration_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = tas_priv->cur_conf;
+
+ return 0;
+}
+
+static int tasdevice_configuration_put(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ unsigned int nr_configuration = ucontrol->value.integer.value[0];
+ int ret = 0;
+
+ if (tas_priv->cur_conf != nr_configuration) {
+ tas_priv->cur_conf = nr_configuration;
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int tasdevice_dsp_create_ctrls(
+ struct tasdevice_priv *tas_priv)
+{
+ struct snd_kcontrol_new *dsp_ctrls;
+ char *prog_name, *conf_name;
+ int nr_controls = 2;
+ int mix_index = 0;
+ int ret;
+
+ /* Alloc kcontrol via devm_kzalloc, which don't manually
+ * free the kcontrol
+ */
+ dsp_ctrls = devm_kcalloc(tas_priv->dev, nr_controls,
+ sizeof(dsp_ctrls[0]), GFP_KERNEL);
+ if (!dsp_ctrls) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Create a mixer item for selecting the active profile */
+ prog_name = devm_kzalloc(tas_priv->dev,
+ SNDRV_CTL_ELEM_ID_NAME_MAXLEN, GFP_KERNEL);
+ conf_name = devm_kzalloc(tas_priv->dev, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ GFP_KERNEL);
+ if (!prog_name || !conf_name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ scnprintf(prog_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ "Speaker Program Id");
+ dsp_ctrls[mix_index].name = prog_name;
+ dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ dsp_ctrls[mix_index].info = tasdevice_info_programs;
+ dsp_ctrls[mix_index].get = tasdevice_program_get;
+ dsp_ctrls[mix_index].put = tasdevice_program_put;
+ mix_index++;
+
+ scnprintf(conf_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ "Speaker Config Id");
+ dsp_ctrls[mix_index].name = conf_name;
+ dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ dsp_ctrls[mix_index].info = tasdevice_info_configurations;
+ dsp_ctrls[mix_index].get = tasdevice_configuration_get;
+ dsp_ctrls[mix_index].put = tasdevice_configuration_put;
+ mix_index++;
+
+ ret = snd_soc_add_component_controls(tas_priv->codec, dsp_ctrls,
+ nr_controls < mix_index ? nr_controls : mix_index);
+
+out:
+ return ret;
+}
+
+static void tasdevice_fw_ready(const struct firmware *fmw,
+ void *context)
+{
+ struct tasdevice_priv *tas_priv = context;
+ int ret = 0;
+ int i;
+
+ mutex_lock(&tas_priv->codec_lock);
+
+ ret = tasdevice_rca_parser(tas_priv, fmw);
+ if (ret)
+ goto out;
+ tasdevice_create_control(tas_priv);
+
+ tasdevice_dsp_remove(tas_priv);
+ tasdevice_calbin_remove(tas_priv);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
+ scnprintf(tas_priv->coef_binaryname, 64, "%s_coef.bin",
+ tas_priv->dev_name);
+ ret = tasdevice_dsp_parser(tas_priv);
+ if (ret) {
+ dev_err(tas_priv->dev, "dspfw load %s error\n",
+ tas_priv->coef_binaryname);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ goto out;
+ }
+ tasdevice_dsp_create_ctrls(tas_priv);
+
+ tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
+
+ /* If calibrated data occurs error, dsp will still works with default
+ * calibrated data inside algo.
+ */
+ for (i = 0; i < tas_priv->ndev; i++) {
+ scnprintf(tas_priv->cal_binaryname[i], 64, "%s_cal_0x%02x.bin",
+ tas_priv->dev_name, tas_priv->tasdevice[i].dev_addr);
+ ret = tas2781_load_calibration(tas_priv,
+ tas_priv->cal_binaryname[i], i);
+ if (ret != 0)
+ dev_err(tas_priv->dev,
+ "%s: load %s error, default will effect\n",
+ __func__, tas_priv->cal_binaryname[i]);
+ }
+
+ tasdevice_prmg_calibdata_load(tas_priv, 0);
+ tas_priv->cur_prog = 0;
+out:
+ if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) {
+ /*If DSP FW fail, kcontrol won't be created */
+ tasdevice_config_info_remove(tas_priv);
+ tasdevice_dsp_remove(tas_priv);
+ }
+ mutex_unlock(&tas_priv->codec_lock);
+ if (fmw)
+ release_firmware(fmw);
+}
+
+static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ int state = 0;
+
+ /* Codec Lock Hold */
+ mutex_lock(&tas_priv->codec_lock);
+ if (event == SND_SOC_DAPM_PRE_PMD)
+ state = 1;
+ tasdevice_tuning_switch(tas_priv, state);
+ /* Codec Lock Release*/
+ mutex_unlock(&tas_priv->codec_lock);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget tasdevice_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("ASI", "ASI Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT_E("ASI OUT", "ASI Capture", 0, SND_SOC_NOPM,
+ 0, 0, tasdevice_dapm_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SPK("SPK", tasdevice_dapm_event),
+ SND_SOC_DAPM_OUTPUT("OUT"),
+ SND_SOC_DAPM_INPUT("DMIC")
+};
+
+static const struct snd_soc_dapm_route tasdevice_audio_map[] = {
+ {"SPK", NULL, "ASI"},
+ {"OUT", NULL, "SPK"},
+ {"ASI OUT", NULL, "DMIC"}
+};
+
+static int tasdevice_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *codec = dai->component;
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ int ret = 0;
+
+ if (tas_priv->fw_state != TASDEVICE_DSP_FW_ALL_OK) {
+ dev_err(tas_priv->dev, "DSP bin file not loaded\n");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int tasdevice_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct tasdevice_priv *tas_priv = snd_soc_dai_get_drvdata(dai);
+ unsigned int slot_width;
+ unsigned int fsrate;
+ int bclk_rate;
+ int rc = 0;
+
+ fsrate = params_rate(params);
+ switch (fsrate) {
+ case 48000:
+ case 44100:
+ break;
+ default:
+ dev_err(tas_priv->dev, "%s: incorrect sample rate = %u\n",
+ __func__, fsrate);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ slot_width = params_width(params);
+ switch (slot_width) {
+ case 16:
+ case 20:
+ case 24:
+ case 32:
+ break;
+ default:
+ dev_err(tas_priv->dev, "%s: incorrect slot width = %u\n",
+ __func__, slot_width);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ bclk_rate = snd_soc_params_to_bclk(params);
+ if (bclk_rate < 0) {
+ dev_err(tas_priv->dev, "%s: incorrect bclk rate = %d\n",
+ __func__, bclk_rate);
+ rc = bclk_rate;
+ goto out;
+ }
+
+out:
+ return rc;
+}
+
+static int tasdevice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct tasdevice_priv *tas_priv = snd_soc_dai_get_drvdata(codec_dai);
+
+ tas_priv->sysclk = freq;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops tasdevice_dai_ops = {
+ .startup = tasdevice_startup,
+ .hw_params = tasdevice_hw_params,
+ .set_sysclk = tasdevice_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver tasdevice_dai_driver[] = {
+ {
+ .name = "tas2781_codec",
+ .id = 0,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = TASDEVICE_RATES,
+ .formats = TASDEVICE_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = TASDEVICE_RATES,
+ .formats = TASDEVICE_FORMATS,
+ },
+ .ops = &tasdevice_dai_ops,
+ .symmetric_rate = 1,
+ },
+};
+
+static int tasdevice_codec_probe(struct snd_soc_component *codec)
+{
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ return tascodec_init(tas_priv, codec, tasdevice_fw_ready);
+}
+
+static void tasdevice_deinit(void *context)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+
+ tasdevice_config_info_remove(tas_priv);
+ tasdevice_dsp_remove(tas_priv);
+ tasdevice_calbin_remove(tas_priv);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
+}
+
+static void tasdevice_codec_remove(
+ struct snd_soc_component *codec)
+{
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ tasdevice_deinit(tas_priv);
+}
+
+static const struct snd_soc_component_driver
+ soc_codec_driver_tasdevice = {
+ .probe = tasdevice_codec_probe,
+ .remove = tasdevice_codec_remove,
+ .controls = tas2781_snd_controls,
+ .num_controls = ARRAY_SIZE(tas2781_snd_controls),
+ .dapm_widgets = tasdevice_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tasdevice_dapm_widgets),
+ .dapm_routes = tasdevice_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(tasdevice_audio_map),
+ .idle_bias_on = 1,
+ .endianness = 1,
+};
+
+static void tasdevice_parse_dt(struct tasdevice_priv *tas_priv)
+{
+ struct i2c_client *client = (struct i2c_client *)tas_priv->client;
+ unsigned int dev_addrs[TASDEVICE_MAX_CHANNELS];
+ int rc, i, ndev = 0;
+
+ if (tas_priv->isacpi) {
+ ndev = device_property_read_u32_array(&client->dev,
+ "ti,audio-slots", NULL, 0);
+ if (ndev <= 0) {
+ ndev = 1;
+ dev_addrs[0] = client->addr;
+ } else {
+ ndev = (ndev < ARRAY_SIZE(dev_addrs))
+ ? ndev : ARRAY_SIZE(dev_addrs);
+ ndev = device_property_read_u32_array(&client->dev,
+ "ti,audio-slots", dev_addrs, ndev);
+ }
+
+ tas_priv->irq_info.irq_gpio =
+ acpi_dev_gpio_irq_get(ACPI_COMPANION(&client->dev), 0);
+ } else {
+ struct device_node *np = tas_priv->dev->of_node;
+#ifdef CONFIG_OF
+ const __be32 *reg, *reg_end;
+ int len, sw, aw;
+
+ aw = of_n_addr_cells(np);
+ sw = of_n_size_cells(np);
+ if (sw == 0) {
+ reg = (const __be32 *)of_get_property(np,
+ "reg", &len);
+ reg_end = reg + len/sizeof(*reg);
+ ndev = 0;
+ do {
+ dev_addrs[ndev] = of_read_number(reg, aw);
+ reg += aw;
+ ndev++;
+ } while (reg < reg_end);
+ } else {
+ ndev = 1;
+ dev_addrs[0] = client->addr;
+ }
+#else
+ ndev = 1;
+ dev_addrs[0] = client->addr;
+#endif
+ tas_priv->irq_info.irq_gpio = of_irq_get(np, 0);
+ }
+ tas_priv->ndev = ndev;
+ for (i = 0; i < ndev; i++)
+ tas_priv->tasdevice[i].dev_addr = dev_addrs[i];
+
+ tas_priv->reset = devm_gpiod_get_optional(&client->dev,
+ "reset-gpios", GPIOD_OUT_HIGH);
+ if (IS_ERR(tas_priv->reset))
+ dev_err(tas_priv->dev, "%s Can't get reset GPIO\n",
+ __func__);
+
+ strcpy(tas_priv->dev_name, tasdevice_id[tas_priv->chip_id].name);
+
+ if (gpio_is_valid(tas_priv->irq_info.irq_gpio)) {
+ rc = gpio_request(tas_priv->irq_info.irq_gpio,
+ "AUDEV-IRQ");
+ if (!rc) {
+ gpio_direction_input(
+ tas_priv->irq_info.irq_gpio);
+
+ tas_priv->irq_info.irq =
+ gpio_to_irq(tas_priv->irq_info.irq_gpio);
+ } else
+ dev_err(tas_priv->dev, "%s: GPIO %d request error\n",
+ __func__, tas_priv->irq_info.irq_gpio);
+ } else
+ dev_err(tas_priv->dev,
+ "Looking up irq-gpio property failed %d\n",
+ tas_priv->irq_info.irq_gpio);
+}
+
+static int tasdevice_i2c_probe(struct i2c_client *i2c)
+{
+ const struct i2c_device_id *id = i2c_match_id(tasdevice_id, i2c);
+ const struct acpi_device_id *acpi_id;
+ struct tasdevice_priv *tas_priv;
+ int ret;
+
+ tas_priv = tasdevice_kzalloc(i2c);
+ if (!tas_priv)
+ return -ENOMEM;
+
+ if (ACPI_HANDLE(&i2c->dev)) {
+ acpi_id = acpi_match_device(i2c->dev.driver->acpi_match_table,
+ &i2c->dev);
+ if (!acpi_id) {
+ dev_err(&i2c->dev, "No driver data\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ tas_priv->chip_id = acpi_id->driver_data;
+ tas_priv->isacpi = true;
+ } else {
+ tas_priv->chip_id = id ? id->driver_data : 0;
+ tas_priv->isacpi = false;
+ }
+
+ tasdevice_parse_dt(tas_priv);
+
+ ret = tasdevice_init(tas_priv);
+ if (ret)
+ goto err;
+
+ ret = devm_snd_soc_register_component(tas_priv->dev,
+ &soc_codec_driver_tasdevice,
+ tasdevice_dai_driver, ARRAY_SIZE(tasdevice_dai_driver));
+ if (ret) {
+ dev_err(tas_priv->dev, "%s: codec register error:0x%08x\n",
+ __func__, ret);
+ goto err;
+ }
+err:
+ if (ret < 0)
+ tasdevice_remove(tas_priv);
+ return ret;
+}
+
+static void tasdevice_i2c_remove(struct i2c_client *client)
+{
+ struct tasdevice_priv *tas_priv = i2c_get_clientdata(client);
+
+ tasdevice_remove(tas_priv);
+}
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id tasdevice_acpi_match[] = {
+ { "TAS2781", TAS2781 },
+ {},
+};
+
+MODULE_DEVICE_TABLE(acpi, tasdevice_acpi_match);
+#endif
+
+static struct i2c_driver tasdevice_i2c_driver = {
+ .driver = {
+ .name = "tas2781-codec",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(tasdevice_of_match),
+#ifdef CONFIG_ACPI
+ .acpi_match_table = ACPI_PTR(tasdevice_acpi_match),
+#endif
+ },
+ .probe = tasdevice_i2c_probe,
+ .remove = tasdevice_i2c_remove,
+ .id_table = tasdevice_id,
+};
+
+module_i2c_driver(tasdevice_i2c_driver);
+
+MODULE_AUTHOR("Shenghao Ding <shenghao-ding@ti.com>");
+MODULE_AUTHOR("Kevin Lu <kevin-lu@ti.com>");
+MODULE_DESCRIPTION("ASoC TAS2781 Driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(SND_SOC_TAS2781_FMWLIB);
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
index f9e7122894bd..60e59e993ba6 100644
--- a/sound/soc/codecs/tas5086.c
+++ b/sound/soc/codecs/tas5086.c
@@ -990,7 +990,7 @@ static struct i2c_driver tas5086_i2c_driver = {
.of_match_table = of_match_ptr(tas5086_dt_ids),
},
.id_table = tas5086_i2c_id,
- .probe_new = tas5086_i2c_probe,
+ .probe = tas5086_i2c_probe,
.remove = tas5086_i2c_remove,
};
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c
index f39c3273b2fd..1756edb35961 100644
--- a/sound/soc/codecs/tas571x.c
+++ b/sound/soc/codecs/tas571x.c
@@ -975,7 +975,7 @@ static struct i2c_driver tas571x_i2c_driver = {
.name = "tas571x",
.of_match_table = of_match_ptr(tas571x_of_match),
},
- .probe_new = tas571x_i2c_probe,
+ .probe = tas571x_i2c_probe,
.remove = tas571x_i2c_remove,
.id_table = tas571x_i2c_id,
};
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c
index 4d27b60bd804..6dd6c0896eff 100644
--- a/sound/soc/codecs/tas5720.c
+++ b/sound/soc/codecs/tas5720.c
@@ -11,7 +11,6 @@
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/i2c.h>
-#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
@@ -821,7 +820,7 @@ static struct i2c_driver tas5720_i2c_driver = {
.name = "tas5720",
.of_match_table = of_match_ptr(tas5720_of_match),
},
- .probe_new = tas5720_probe,
+ .probe = tas5720_probe,
.id_table = tas5720_id,
};
diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c
index 4e38eb7acea1..aca3756ffab6 100644
--- a/sound/soc/codecs/tas5805m.c
+++ b/sound/soc/codecs/tas5805m.c
@@ -597,7 +597,7 @@ MODULE_DEVICE_TABLE(of, tas5805m_of_match);
#endif
static struct i2c_driver tas5805m_i2c_driver = {
- .probe_new = tas5805m_i2c_probe,
+ .probe = tas5805m_i2c_probe,
.remove = tas5805m_i2c_remove,
.id_table = tas5805m_i2c_id,
.driver = {
diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c
index f8ff69fa2549..da89e8c681dd 100644
--- a/sound/soc/codecs/tas6424.c
+++ b/sound/soc/codecs/tas6424.c
@@ -11,7 +11,6 @@
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/i2c.h>
-#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
@@ -803,7 +802,7 @@ static struct i2c_driver tas6424_i2c_driver = {
.name = "tas6424",
.of_match_table = of_match_ptr(tas6424_of_ids),
},
- .probe_new = tas6424_i2c_probe,
+ .probe = tas6424_i2c_probe,
.remove = tas6424_i2c_remove,
.id_table = tas6424_i2c_ids,
};
diff --git a/sound/soc/codecs/tda7419.c b/sound/soc/codecs/tda7419.c
index d964e5207569..e187d74a1737 100644
--- a/sound/soc/codecs/tda7419.c
+++ b/sound/soc/codecs/tda7419.c
@@ -629,7 +629,7 @@ static struct i2c_driver tda7419_driver = {
.name = "tda7419",
.of_match_table = tda7419_of_match,
},
- .probe_new = tda7419_probe,
+ .probe = tda7419_probe,
.id_table = tda7419_i2c_id,
};
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
index 9f7902ec40db..8cca2ceadd9e 100644
--- a/sound/soc/codecs/tfa9879.c
+++ b/sound/soc/codecs/tfa9879.c
@@ -312,7 +312,7 @@ static struct i2c_driver tfa9879_i2c_driver = {
.name = "tfa9879",
.of_match_table = tfa9879_of_match,
},
- .probe_new = tfa9879_i2c_probe,
+ .probe = tfa9879_i2c_probe,
.id_table = tfa9879_i2c_id,
};
diff --git a/sound/soc/codecs/tfa989x.c b/sound/soc/codecs/tfa989x.c
index b853507e65a8..79847a90ac46 100644
--- a/sound/soc/codecs/tfa989x.c
+++ b/sound/soc/codecs/tfa989x.c
@@ -416,7 +416,7 @@ static struct i2c_driver tfa989x_i2c_driver = {
.name = "tfa989x",
.of_match_table = tfa989x_of_match,
},
- .probe_new = tfa989x_i2c_probe,
+ .probe = tfa989x_i2c_probe,
};
module_i2c_driver(tfa989x_i2c_driver);
diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c
index 52bb55724724..b976c1946286 100644
--- a/sound/soc/codecs/tlv320adc3xxx.c
+++ b/sound/soc/codecs/tlv320adc3xxx.c
@@ -1451,7 +1451,7 @@ static struct i2c_driver adc3xxx_i2c_driver = {
.name = "tlv320adc3xxx-codec",
.of_match_table = tlv320adc3xxx_of_match,
},
- .probe_new = adc3xxx_i2c_probe,
+ .probe = adc3xxx_i2c_probe,
.remove = __exit_p(adc3xxx_i2c_remove),
.id_table = adc3xxx_i2c_id,
};
diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c
index 530f321d08e9..41342b340680 100644
--- a/sound/soc/codecs/tlv320adcx140.c
+++ b/sound/soc/codecs/tlv320adcx140.c
@@ -1208,7 +1208,7 @@ static struct i2c_driver adcx140_i2c_driver = {
.name = "tlv320adcx140-codec",
.of_match_table = of_match_ptr(tlv320adcx140_of_match),
},
- .probe_new = adcx140_i2c_probe,
+ .probe = adcx140_i2c_probe,
.id_table = adcx140_i2c_id,
};
module_i2c_driver(adcx140_i2c_driver);
diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c
index 1f97673a1cc0..9692ae007c91 100644
--- a/sound/soc/codecs/tlv320aic23-i2c.c
+++ b/sound/soc/codecs/tlv320aic23-i2c.c
@@ -47,7 +47,7 @@ static struct i2c_driver tlv320aic23_i2c_driver = {
.name = "tlv320aic23-codec",
.of_match_table = of_match_ptr(tlv320aic23_of_match),
},
- .probe_new = tlv320aic23_i2c_probe,
+ .probe = tlv320aic23_i2c_probe,
.id_table = tlv320aic23_id,
};
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 0847302121f6..9611aa8acb0d 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1746,7 +1746,7 @@ static struct i2c_driver aic31xx_i2c_driver = {
.of_match_table = of_match_ptr(tlv320aic31xx_of_match),
.acpi_match_table = ACPI_PTR(aic31xx_acpi_match),
},
- .probe_new = aic31xx_i2c_probe,
+ .probe = aic31xx_i2c_probe,
.id_table = aic31xx_i2c_id,
};
module_i2c_driver(aic31xx_i2c_driver);
diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c
index d1e543ca3521..49b33a256cd7 100644
--- a/sound/soc/codecs/tlv320aic32x4-i2c.c
+++ b/sound/soc/codecs/tlv320aic32x4-i2c.c
@@ -71,7 +71,7 @@ static struct i2c_driver aic32x4_i2c_driver = {
.name = "tlv320aic32x4",
.of_match_table = aic32x4_of_id,
},
- .probe_new = aic32x4_i2c_probe,
+ .probe = aic32x4_i2c_probe,
.remove = aic32x4_i2c_remove,
.id_table = aic32x4_i2c_id,
};
diff --git a/sound/soc/codecs/tlv320aic3x-i2c.c b/sound/soc/codecs/tlv320aic3x-i2c.c
index d7e94d564dbf..bb33fd3dfb4f 100644
--- a/sound/soc/codecs/tlv320aic3x-i2c.c
+++ b/sound/soc/codecs/tlv320aic3x-i2c.c
@@ -61,7 +61,7 @@ static struct i2c_driver aic3x_i2c_driver = {
.name = "tlv320aic3x",
.of_match_table = aic3x_of_id,
},
- .probe_new = aic3x_i2c_probe,
+ .probe = aic3x_i2c_probe,
.remove = aic3x_i2c_remove,
.id_table = aic3x_i2c_id,
};
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 16ce3ef1134b..fa46f51d4341 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -1560,7 +1560,7 @@ static struct i2c_driver tlv320dac33_i2c_driver = {
.driver = {
.name = "tlv320dac33-codec",
},
- .probe_new = dac33_i2c_probe,
+ .probe = dac33_i2c_probe,
.remove = dac33_i2c_remove,
.id_table = tlv320dac33_i2c_id,
};
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 8c00db32996b..5bc486283fde 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -319,7 +319,7 @@ static struct i2c_driver tpa6130a2_i2c_driver = {
.name = "tpa6130a2",
.of_match_table = of_match_ptr(tpa6130a2_of_match),
},
- .probe_new = tpa6130a2_probe,
+ .probe = tpa6130a2_probe,
.id_table = tpa6130a2_id,
};
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
index 5282112c7d8d..6d9166d9116a 100644
--- a/sound/soc/codecs/ts3a227e.c
+++ b/sound/soc/codecs/ts3a227e.c
@@ -455,7 +455,7 @@ static struct i2c_driver ts3a227e_driver = {
.of_match_table = of_match_ptr(ts3a227e_of_match),
.acpi_match_table = ACPI_PTR(ts3a227e_acpi_match),
},
- .probe_new = ts3a227e_i2c_probe,
+ .probe = ts3a227e_i2c_probe,
.id_table = ts3a227e_i2c_ids,
};
module_i2c_driver(ts3a227e_driver);
diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c
index fa0c525189c2..1eefc1fe6ea8 100644
--- a/sound/soc/codecs/tscs42xx.c
+++ b/sound/soc/codecs/tscs42xx.c
@@ -1503,7 +1503,7 @@ static struct i2c_driver tscs42xx_i2c_driver = {
.name = "tscs42xx",
.of_match_table = tscs42xx_of_match,
},
- .probe_new = tscs42xx_i2c_probe,
+ .probe = tscs42xx_i2c_probe,
.id_table = tscs42xx_i2c_id,
};
diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c
index 38622bc247fc..744aef32a21f 100644
--- a/sound/soc/codecs/tscs454.c
+++ b/sound/soc/codecs/tscs454.c
@@ -3473,7 +3473,7 @@ static struct i2c_driver tscs454_i2c_driver = {
.name = "tscs454",
.of_match_table = tscs454_of_match,
},
- .probe_new = tscs454_i2c_probe,
+ .probe = tscs454_i2c_probe,
.id_table = tscs454_i2c_id,
};
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index fdaaee845176..5c5751dc14e5 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -798,7 +798,7 @@ static struct i2c_driver uda1380_i2c_driver = {
.name = "uda1380-codec",
.of_match_table = uda1380_of_match,
},
- .probe_new = uda1380_i2c_probe,
+ .probe = uda1380_i2c_probe,
.id_table = uda1380_i2c_id,
};
diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c
index 9c10200ff34b..bd0e9fbc12eb 100644
--- a/sound/soc/codecs/wcd938x-sdw.c
+++ b/sound/soc/codecs/wcd938x-sdw.c
@@ -1270,7 +1270,7 @@ static int wcd9380_probe(struct sdw_slave *pdev,
/* Start in cache-only until device is enumerated */
regcache_cache_only(wcd->regmap, true);
- };
+ }
pm_runtime_set_autosuspend_delay(dev, 3000);
pm_runtime_use_autosuspend(dev);
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index 034a4e858c7e..1d4259433f47 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -994,3 +994,6 @@ module_spi_driver(wm0010_spi_driver);
MODULE_DESCRIPTION("ASoC WM0010 driver");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");
+
+MODULE_FIRMWARE("wm0010.dfw");
+MODULE_FIRMWARE("wm0010_stage2.bin");
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c
index 0064a607ec68..d7eeb41ba60f 100644
--- a/sound/soc/codecs/wm1250-ev1.c
+++ b/sound/soc/codecs/wm1250-ev1.c
@@ -243,7 +243,7 @@ static struct i2c_driver wm1250_ev1_i2c_driver = {
.driver = {
.name = "wm1250-ev1",
},
- .probe_new = wm1250_ev1_probe,
+ .probe = wm1250_ev1_probe,
.remove = wm1250_ev1_remove,
.id_table = wm1250_ev1_i2c_id,
};
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 14b4fd97488c..9571ea53cb3f 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -938,7 +938,7 @@ static struct i2c_driver wm2000_i2c_driver = {
.driver = {
.name = "wm2000",
},
- .probe_new = wm2000_i2c_probe,
+ .probe = wm2000_i2c_probe,
.id_table = wm2000_i2c_id,
};
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 0a65afa44a59..277b8c468c78 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -2485,7 +2485,7 @@ static struct i2c_driver wm2200_i2c_driver = {
.name = "wm2200",
.pm = &wm2200_pm,
},
- .probe_new = wm2200_i2c_probe,
+ .probe = wm2200_i2c_probe,
.remove = wm2200_i2c_remove,
.id_table = wm2200_i2c_id,
};
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 3b09d4a1684f..a86eacb2a9bb 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -2709,7 +2709,7 @@ static struct i2c_driver wm5100_i2c_driver = {
.name = "wm5100",
.pm = &wm5100_pm,
},
- .probe_new = wm5100_i2c_probe,
+ .probe = wm5100_i2c_probe,
.remove = wm5100_i2c_remove,
.id_table = wm5100_i2c_id,
};
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index e13f9780a111..c0ed76d5b65f 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -678,7 +678,7 @@ static struct i2c_driver wm8510_i2c_driver = {
.name = "wm8510",
.of_match_table = wm8510_of_match,
},
- .probe_new = wm8510_i2c_probe,
+ .probe = wm8510_i2c_probe,
.id_table = wm8510_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 66f6371d8acf..55c72c5ac845 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -527,7 +527,7 @@ static struct i2c_driver wm8523_i2c_driver = {
.name = "wm8523",
.of_match_table = wm8523_of_match,
},
- .probe_new = wm8523_i2c_probe,
+ .probe = wm8523_i2c_probe,
.id_table = wm8523_i2c_id,
};
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index ca796aa0aeb7..34ae7fe05398 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -1049,7 +1049,7 @@ static struct i2c_driver wm8580_i2c_driver = {
.name = "wm8580",
.of_match_table = wm8580_of_match,
},
- .probe_new = wm8580_i2c_probe,
+ .probe = wm8580_i2c_probe,
.id_table = wm8580_i2c_id,
};
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index 383c6796e8a3..903a0147d584 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -464,7 +464,7 @@ static struct i2c_driver wm8711_i2c_driver = {
.name = "wm8711",
.of_match_table = wm8711_of_match,
},
- .probe_new = wm8711_i2c_probe,
+ .probe = wm8711_i2c_probe,
.id_table = wm8711_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index a3dbdbf40723..5ea6d8fd10f6 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -305,7 +305,7 @@ static struct i2c_driver wm8728_i2c_driver = {
.name = "wm8728",
.of_match_table = wm8728_of_match,
},
- .probe_new = wm8728_i2c_probe,
+ .probe = wm8728_i2c_probe,
.id_table = wm8728_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8731-i2c.c b/sound/soc/codecs/wm8731-i2c.c
index fdf03bf91606..c39e637d813d 100644
--- a/sound/soc/codecs/wm8731-i2c.c
+++ b/sound/soc/codecs/wm8731-i2c.c
@@ -57,7 +57,7 @@ static struct i2c_driver wm8731_i2c_driver = {
.name = "wm8731",
.of_match_table = wm8731_of_match,
},
- .probe_new = wm8731_i2c_probe,
+ .probe = wm8731_i2c_probe,
.id_table = wm8731_i2c_id,
};
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index 90b54343370c..9f4e372e90ea 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -649,7 +649,7 @@ static struct i2c_driver wm8737_i2c_driver = {
.name = "wm8737",
.of_match_table = wm8737_of_match,
},
- .probe_new = wm8737_i2c_probe,
+ .probe = wm8737_i2c_probe,
.id_table = wm8737_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index c7afa4f2795d..787156b980a1 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -616,7 +616,7 @@ static struct i2c_driver wm8741_i2c_driver = {
.name = "wm8741",
.of_match_table = wm8741_of_match,
},
- .probe_new = wm8741_i2c_probe,
+ .probe = wm8741_i2c_probe,
.id_table = wm8741_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 2f6ee8d6639f..20dc9ff9fea9 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -813,7 +813,7 @@ static struct i2c_driver wm8750_i2c_driver = {
.name = "wm8750",
.of_match_table = wm8750_of_match,
},
- .probe_new = wm8750_i2c_probe,
+ .probe = wm8750_i2c_probe,
.id_table = wm8750_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index bb18f58dc670..5e8a8eb41b2b 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -1590,7 +1590,7 @@ static struct i2c_driver wm8753_i2c_driver = {
.name = "wm8753",
.of_match_table = wm8753_of_match,
},
- .probe_new = wm8753_i2c_probe,
+ .probe = wm8753_i2c_probe,
.id_table = wm8753_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index 936ea24621b0..212224a68006 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -523,7 +523,7 @@ static struct i2c_driver wm8776_i2c_driver = {
.name = "wm8776",
.of_match_table = wm8776_of_match,
},
- .probe_new = wm8776_i2c_probe,
+ .probe = wm8776_i2c_probe,
.id_table = wm8776_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c
index 3ce1a39d76eb..7062a8b2f8b5 100644
--- a/sound/soc/codecs/wm8804-i2c.c
+++ b/sound/soc/codecs/wm8804-i2c.c
@@ -60,7 +60,7 @@ static struct i2c_driver wm8804_i2c_driver = {
.of_match_table = of_match_ptr(wm8804_of_match),
.acpi_match_table = ACPI_PTR(wm8804_acpi_match),
},
- .probe_new = wm8804_i2c_probe,
+ .probe = wm8804_i2c_probe,
.remove = wm8804_i2c_remove,
.id_table = wm8804_i2c_id
};
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 03bbd85ebdf4..320ccd92f318 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -1295,7 +1295,7 @@ static struct i2c_driver wm8900_i2c_driver = {
.driver = {
.name = "wm8900",
},
- .probe_new = wm8900_i2c_probe,
+ .probe = wm8900_i2c_probe,
.remove = wm8900_i2c_remove,
.id_table = wm8900_i2c_id,
};
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 1dc8e20bdace..901b65ef8de5 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -2209,7 +2209,7 @@ static struct i2c_driver wm8903_i2c_driver = {
.name = "wm8903",
.of_match_table = wm8903_of_match,
},
- .probe_new = wm8903_i2c_probe,
+ .probe = wm8903_i2c_probe,
.remove = wm8903_i2c_remove,
.id_table = wm8903_i2c_id,
};
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 791d8738d1c0..068e610b1b4c 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -2337,7 +2337,7 @@ static struct i2c_driver wm8904_i2c_driver = {
.name = "wm8904",
.of_match_table = of_match_ptr(wm8904_of_match),
},
- .probe_new = wm8904_i2c_probe,
+ .probe = wm8904_i2c_probe,
.id_table = wm8904_i2c_id,
};
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index 8eb4782c9232..53c27986d216 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -860,7 +860,7 @@ static struct i2c_driver wm8940_i2c_driver = {
.name = "wm8940",
.of_match_table = wm8940_of_match,
},
- .probe_new = wm8940_i2c_probe,
+ .probe = wm8940_i2c_probe,
.id_table = wm8940_i2c_id,
};
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index 05ef45672ebc..78044f580a67 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -1003,7 +1003,7 @@ static struct i2c_driver wm8955_i2c_driver = {
.driver = {
.name = "wm8955",
},
- .probe_new = wm8955_i2c_probe,
+ .probe = wm8955_i2c_probe,
.id_table = wm8955_i2c_id,
};
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 0d167238a369..366f5d769d6d 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -1518,7 +1518,7 @@ static struct i2c_driver wm8960_i2c_driver = {
.of_match_table = of_match_ptr(wm8960_of_match),
.acpi_match_table = ACPI_PTR(wm8960_acpi_match),
},
- .probe_new = wm8960_i2c_probe,
+ .probe = wm8960_i2c_probe,
.remove = wm8960_i2c_remove,
.id_table = wm8960_i2c_id,
};
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index a4857024711d..c076f78d04ce 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -982,7 +982,7 @@ static struct i2c_driver wm8961_i2c_driver = {
.name = "wm8961",
.of_match_table = of_match_ptr(wm8961_of_match),
},
- .probe_new = wm8961_i2c_probe,
+ .probe = wm8961_i2c_probe,
.id_table = wm8961_i2c_id,
};
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index b901e4c65e8a..68ea15be7330 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -3946,7 +3946,7 @@ static struct i2c_driver wm8962_i2c_driver = {
.of_match_table = wm8962_of_match,
.pm = &wm8962_pm,
},
- .probe_new = wm8962_i2c_probe,
+ .probe = wm8962_i2c_probe,
.remove = wm8962_i2c_remove,
.id_table = wm8962_i2c_id,
};
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 4db9248de54b..b22d8f0b59be 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -700,7 +700,7 @@ static struct i2c_driver wm8971_i2c_driver = {
.driver = {
.name = "wm8971",
},
- .probe_new = wm8971_i2c_probe,
+ .probe = wm8971_i2c_probe,
.id_table = wm8971_i2c_id,
};
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 010a394c705c..044b6f604c09 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -723,7 +723,7 @@ static struct i2c_driver wm8974_i2c_driver = {
.name = "wm8974",
.of_match_table = wm8974_of_match,
},
- .probe_new = wm8974_i2c_probe,
+ .probe = wm8974_i2c_probe,
.id_table = wm8974_i2c_id,
};
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index aa2f55401a88..5c829301cf4c 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -1072,7 +1072,7 @@ static struct i2c_driver wm8978_i2c_driver = {
.name = "wm8978",
.of_match_table = wm8978_of_match,
},
- .probe_new = wm8978_i2c_probe,
+ .probe = wm8978_i2c_probe,
.id_table = wm8978_i2c_id,
};
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index 50e6ac6ccbe0..2bd26e2478d9 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -1068,7 +1068,7 @@ static struct i2c_driver wm8983_i2c_driver = {
.driver = {
.name = "wm8983",
},
- .probe_new = wm8983_i2c_probe,
+ .probe = wm8983_i2c_probe,
.id_table = wm8983_i2c_id
};
#endif
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index 751aa6730833..c0816bcfa294 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -1206,7 +1206,7 @@ static struct i2c_driver wm8985_i2c_driver = {
.driver = {
.name = "wm8985",
},
- .probe_new = wm8985_i2c_probe,
+ .probe = wm8985_i2c_probe,
.id_table = wm8985_i2c_id
};
#endif
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 5dbdf647cd97..b440719cca7d 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -905,7 +905,7 @@ static struct i2c_driver wm8988_i2c_driver = {
.driver = {
.name = "wm8988",
},
- .probe_new = wm8988_i2c_probe,
+ .probe = wm8988_i2c_probe,
.id_table = wm8988_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 589af286f133..5a8e765090af 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -1247,7 +1247,7 @@ static struct i2c_driver wm8990_i2c_driver = {
.driver = {
.name = "wm8990",
},
- .probe_new = wm8990_i2c_probe,
+ .probe = wm8990_i2c_probe,
.id_table = wm8990_i2c_id,
};
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index 30121993b7b4..8cb2ae829699 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -1323,7 +1323,7 @@ static struct i2c_driver wm8991_i2c_driver = {
.driver = {
.name = "wm8991",
},
- .probe_new = wm8991_i2c_probe,
+ .probe = wm8991_i2c_probe,
.id_table = wm8991_i2c_id,
};
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 22a47acbc6d1..feb997c698e2 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -1741,7 +1741,7 @@ static struct i2c_driver wm8993_i2c_driver = {
.driver = {
.name = "wm8993",
},
- .probe_new = wm8993_i2c_probe,
+ .probe = wm8993_i2c_probe,
.remove = wm8993_i2c_remove,
.id_table = wm8993_i2c_id,
};
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index eed48bf339f2..90588614edcc 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -2268,7 +2268,7 @@ static struct i2c_driver wm8995_i2c_driver = {
.driver = {
.name = "wm8995",
},
- .probe_new = wm8995_i2c_probe,
+ .probe = wm8995_i2c_probe,
.id_table = wm8995_i2c_id
};
#endif
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index b52ed89d631a..5d0eb0ae0475 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -3086,7 +3086,7 @@ static struct i2c_driver wm8996_i2c_driver = {
.driver = {
.name = "wm8996",
},
- .probe_new = wm8996_i2c_probe,
+ .probe = wm8996_i2c_probe,
.remove = wm8996_i2c_remove,
.id_table = wm8996_i2c_id,
};
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 513ec0ba81bb..34a07db7342a 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -1369,7 +1369,7 @@ static struct i2c_driver wm9081_i2c_driver = {
.driver = {
.name = "wm9081",
},
- .probe_new = wm9081_i2c_probe,
+ .probe = wm9081_i2c_probe,
.remove = wm9081_i2c_remove,
.id_table = wm9081_i2c_id,
};
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index ef3524c3f07f..432729c753dd 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -616,7 +616,7 @@ static struct i2c_driver wm9090_i2c_driver = {
.driver = {
.name = "wm9090",
},
- .probe_new = wm9090_i2c_probe,
+ .probe = wm9090_i2c_probe,
.id_table = wm9090_id,
};
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 216120b68b64..5a89abfe8784 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -15,7 +15,6 @@
#include <linux/firmware.h>
#include <linux/list.h>
#include <linux/pm.h>
-#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -686,8 +685,6 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
{
struct cs_dsp_coeff_ctl *cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg);
struct wm_coeff_ctl *ctl;
- struct snd_kcontrol *kcontrol;
- char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
int ret;
ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len);
@@ -699,23 +696,7 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
ctl = cs_ctl->priv;
- if (dsp->component->name_prefix)
- snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s",
- dsp->component->name_prefix, ctl->name);
- else
- snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s",
- ctl->name);
-
- kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl_name);
- if (!kcontrol) {
- adsp_err(dsp, "Can't find kcontrol %s\n", ctl_name);
- return -EINVAL;
- }
-
- snd_ctl_notify(dsp->component->card->snd_card,
- SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id);
-
- return 0;
+ return snd_soc_component_notify_control(dsp->component, ctl->name);
}
EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
index e80b53143569..e40d583a1ce6 100644
--- a/sound/soc/codecs/wsa883x.c
+++ b/sound/soc/codecs/wsa883x.c
@@ -1333,7 +1333,8 @@ static int wsa883x_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
WSA883X_DRE_GAIN_EN_MASK,
WSA883X_DRE_GAIN_FROM_CSR);
snd_soc_component_write_field(component, WSA883X_PA_FSM_CTL,
- WSA883X_GLOBAL_PA_EN_MASK, 1);
+ WSA883X_GLOBAL_PA_EN_MASK,
+ WSA883X_GLOBAL_PA_ENABLE);
}
diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c
new file mode 100644
index 000000000000..993d76b18b53
--- /dev/null
+++ b/sound/soc/codecs/wsa884x.c
@@ -0,0 +1,1936 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Linaro Ltd.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#define WSA884X_BASE 0x3000
+#define WSA884X_ANA_BG_TSADC_BASE (WSA884X_BASE + 0x0001)
+#define WSA884X_BG_CTRL (WSA884X_ANA_BG_TSADC_BASE + 0x00)
+#define WSA884X_ADC_CTRL (WSA884X_ANA_BG_TSADC_BASE + 0x01)
+#define WSA884X_BOP1_PROG (WSA884X_ANA_BG_TSADC_BASE + 0x02)
+#define WSA884X_BOP2_PROG (WSA884X_ANA_BG_TSADC_BASE + 0x03)
+#define WSA884X_BOP2_PROG_BOP2_VTH_MASK 0xf0
+#define WSA884X_BOP2_PROG_BOP2_VTH_SHIFT 4
+#define WSA884X_BOP2_PROG_BOP2_HYST_MASK 0x0f
+#define WSA884X_BOP2_PROG_BOP2_HYST_SHIFT 0
+#define WSA884X_UVLO_PROG (WSA884X_ANA_BG_TSADC_BASE + 0x04)
+#define WSA884X_UVLO_PROG1 (WSA884X_ANA_BG_TSADC_BASE + 0x05)
+#define WSA884X_SPARE_CTRL_0 (WSA884X_ANA_BG_TSADC_BASE + 0x06)
+#define WSA884X_SPARE_CTRL_1 (WSA884X_ANA_BG_TSADC_BASE + 0x07)
+#define WSA884X_SPARE_CTRL_2 (WSA884X_ANA_BG_TSADC_BASE + 0x08)
+#define WSA884X_SPARE_CTRL_3 (WSA884X_ANA_BG_TSADC_BASE + 0x09)
+#define WSA884X_REF_CTRL (WSA884X_ANA_BG_TSADC_BASE + 0x0a)
+#define WSA884X_REF_CTRL_BG_RDY_SEL_MASK 0x03
+#define WSA884X_REF_CTRL_BG_RDY_SEL_SHIFT 0
+#define WSA884X_BG_TEST_CTL (WSA884X_ANA_BG_TSADC_BASE + 0x0b)
+#define WSA884X_BG_BIAS (WSA884X_ANA_BG_TSADC_BASE + 0x0c)
+#define WSA884X_ADC_PROG (WSA884X_ANA_BG_TSADC_BASE + 0x0d)
+#define WSA884X_ADC_IREF_CTL (WSA884X_ANA_BG_TSADC_BASE + 0x0e)
+#define WSA884X_ADC_ISENS_CTL (WSA884X_ANA_BG_TSADC_BASE + 0x0f)
+#define WSA884X_ADC_CLK_CTL (WSA884X_ANA_BG_TSADC_BASE + 0x10)
+#define WSA884X_ADC_TEST_CTL (WSA884X_ANA_BG_TSADC_BASE + 0x11)
+#define WSA884X_ADC_BIAS (WSA884X_ANA_BG_TSADC_BASE + 0x12)
+#define WSA884X_VBAT_SNS (WSA884X_ANA_BG_TSADC_BASE + 0x13)
+#define WSA884X_DOUT_MSB (WSA884X_ANA_BG_TSADC_BASE + 0x14)
+#define WSA884X_DOUT_LSB (WSA884X_ANA_BG_TSADC_BASE + 0x15)
+#define WSA884X_BOP_ATEST_SEL (WSA884X_ANA_BG_TSADC_BASE + 0x16)
+#define WSA884X_MISC0 (WSA884X_ANA_BG_TSADC_BASE + 0x17)
+#define WSA884X_MISC1 (WSA884X_ANA_BG_TSADC_BASE + 0x18)
+#define WSA884X_MISC2 (WSA884X_ANA_BG_TSADC_BASE + 0x19)
+#define WSA884X_MISC3 (WSA884X_ANA_BG_TSADC_BASE + 0x1a)
+#define WSA884X_SPARE_TSBG_0 (WSA884X_ANA_BG_TSADC_BASE + 0x1b)
+#define WSA884X_SPARE_TUNE_0 (WSA884X_ANA_BG_TSADC_BASE + 0x1c)
+#define WSA884X_SPARE_TUNE_1 (WSA884X_ANA_BG_TSADC_BASE + 0x1d)
+
+#define WSA884X_ANA_IVSENSE_BASE (WSA884X_BASE + 0x0020)
+#define WSA884X_VSENSE1 (WSA884X_ANA_IVSENSE_BASE + 0x00)
+#define WSA884X_VSENSE1_GAIN_VSENSE_FE_MASK 0xe0
+#define WSA884X_VSENSE1_GAIN_VSENSE_FE_SHIFT 5
+#define WSA884X_ISENSE2 (WSA884X_ANA_IVSENSE_BASE + 0x01)
+#define WSA884X_ISENSE2_ISENSE_GAIN_CTL_MASK 0xe0
+#define WSA884X_ISENSE2_ISENSE_GAIN_CTL_SHIFT 5
+
+#define WSA884X_SPARE_CTL_1 (WSA884X_ANA_IVSENSE_BASE + 0x02)
+#define WSA884X_SPARE_CTL_2 (WSA884X_ANA_IVSENSE_BASE + 0x03)
+#define WSA884X_SPARE_CTL_3 (WSA884X_ANA_IVSENSE_BASE + 0x04)
+#define WSA884X_SPARE_CTL_4 (WSA884X_ANA_IVSENSE_BASE + 0x05)
+#define WSA884X_EN (WSA884X_ANA_IVSENSE_BASE + 0x06)
+#define WSA884X_OVERRIDE1 (WSA884X_ANA_IVSENSE_BASE + 0x07)
+#define WSA884X_OVERRIDE2 (WSA884X_ANA_IVSENSE_BASE + 0x08)
+#define WSA884X_ISENSE1 (WSA884X_ANA_IVSENSE_BASE + 0x09)
+#define WSA884X_ISENSE_CAL (WSA884X_ANA_IVSENSE_BASE + 0x0a)
+#define WSA884X_MISC (WSA884X_ANA_IVSENSE_BASE + 0x0b)
+#define WSA884X_ADC_0 (WSA884X_ANA_IVSENSE_BASE + 0x0c)
+#define WSA884X_ADC_1 (WSA884X_ANA_IVSENSE_BASE + 0x0d)
+#define WSA884X_ADC_2 (WSA884X_ANA_IVSENSE_BASE + 0x0e)
+#define WSA884X_ADC_3 (WSA884X_ANA_IVSENSE_BASE + 0x0f)
+#define WSA884X_ADC_4 (WSA884X_ANA_IVSENSE_BASE + 0x10)
+#define WSA884X_ADC_5 (WSA884X_ANA_IVSENSE_BASE + 0x11)
+#define WSA884X_ADC_6 (WSA884X_ANA_IVSENSE_BASE + 0x12)
+#define WSA884X_ADC_7 (WSA884X_ANA_IVSENSE_BASE + 0x13)
+#define WSA884X_STATUS (WSA884X_ANA_IVSENSE_BASE + 0x14)
+#define WSA884X_IVSENSE_SPARE_TUNE_1 (WSA884X_ANA_IVSENSE_BASE + 0x15)
+#define WSA884X_SPARE_TUNE_2 (WSA884X_ANA_IVSENSE_BASE + 0x16)
+#define WSA884X_SPARE_TUNE_3 (WSA884X_ANA_IVSENSE_BASE + 0x17)
+#define WSA884X_SPARE_TUNE_4 (WSA884X_ANA_IVSENSE_BASE + 0x18)
+
+#define WSA884X_ANA_SPK_TOP_BASE (WSA884X_BASE + 0x0040)
+#define WSA884X_TOP_CTRL1 (WSA884X_ANA_SPK_TOP_BASE + 0x00)
+#define WSA884X_TOP_CTRL1_OCP_LOWVBAT_ITH_EN_MASK 0x01
+#define WSA884X_CLIP_DET_CTRL1 (WSA884X_ANA_SPK_TOP_BASE + 0x01)
+#define WSA884X_CLIP_DET_CTRL2 (WSA884X_ANA_SPK_TOP_BASE + 0x02)
+#define WSA884X_DAC_CTRL1 (WSA884X_ANA_SPK_TOP_BASE + 0x03)
+#define WSA884X_DAC_VCM_CTRL_REG1 (WSA884X_ANA_SPK_TOP_BASE + 0x04)
+#define WSA884X_DAC_VCM_CTRL_REG2 (WSA884X_ANA_SPK_TOP_BASE + 0x05)
+#define WSA884X_DAC_VCM_CTRL_REG3 (WSA884X_ANA_SPK_TOP_BASE + 0x06)
+#define WSA884X_DAC_VCM_CTRL_REG4 (WSA884X_ANA_SPK_TOP_BASE + 0x07)
+#define WSA884X_DAC_VCM_CTRL_REG5 (WSA884X_ANA_SPK_TOP_BASE + 0x08)
+#define WSA884X_DAC_VCM_CTRL_REG6 (WSA884X_ANA_SPK_TOP_BASE + 0x09)
+#define WSA884X_PWM_CLK_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x0a)
+#define WSA884X_PWM_CLK_CTL_VCMO_INT1_IDLE_MODE_OVRT_MASK 0x80
+#define WSA884X_PWM_CLK_CTL_VCMO_INT1_IDLE_MODE_OVRT_SHIFT 7
+#define WSA884X_PWM_CLK_CTL_REG_MCLK_DIV_RATIO_MASK 0x40
+#define WSA884X_PWM_CLK_CTL_REG_MCLK_DIV_RATIO_SHIFT 6
+#define WSA884X_PWM_CLK_CTL_PWM_DEGLITCH_CLK_DELAY_CTRL_MASK 0x30
+#define WSA884X_PWM_CLK_CTL_PWM_DEGLITCH_CLK_DELAY_CTRL_SHIFT 4
+#define WSA884X_PWM_CLK_CTL_PWM_CLK_FREQ_SEL_MASK 0x08
+#define WSA884X_PWM_CLK_CTL_PWM_CLK_FREQ_SEL_SHIFT 3
+#define WSA884X_PWM_CLK_CTL_PWM_CLK_DIV_RATIO_MASK 0x06
+#define WSA884X_PWM_CLK_CTL_PWM_CLK_DIV_RATIO_SHIFT 1
+#define WSA884X_PWM_CLK_CTL_PWM_CLK_DIV_BYPASS_MASK 0x01
+#define WSA884X_PWM_CLK_CTL_PWM_CLK_DIV_BYPASS_SHIFT 0
+#define WSA884X_DRV_LF_LDO_SEL (WSA884X_ANA_SPK_TOP_BASE + 0x0b)
+#define WSA884X_OCP_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x0c)
+#define WSA884X_PDRV_HS_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x0d)
+#define WSA884X_PDRV_LS_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x0e)
+#define WSA884X_SPK_TOP_SPARE_CTL_1 (WSA884X_ANA_SPK_TOP_BASE + 0x0f)
+#define WSA884X_SPK_TOP_SPARE_CTL_2 (WSA884X_ANA_SPK_TOP_BASE + 0x10)
+#define WSA884X_SPK_TOP_SPARE_CTL_3 (WSA884X_ANA_SPK_TOP_BASE + 0x11)
+#define WSA884X_SPK_TOP_SPARE_CTL_4 (WSA884X_ANA_SPK_TOP_BASE + 0x12)
+#define WSA884X_SPARE_CTL_5 (WSA884X_ANA_SPK_TOP_BASE + 0x13)
+#define WSA884X_DAC_EN_DEBUG_REG (WSA884X_ANA_SPK_TOP_BASE + 0x14)
+#define WSA884X_DAC_OPAMP_BIAS1_REG (WSA884X_ANA_SPK_TOP_BASE + 0x15)
+#define WSA884X_DAC_OPAMP_BIAS2_REG (WSA884X_ANA_SPK_TOP_BASE + 0x16)
+#define WSA884X_DAC_TUNE1 (WSA884X_ANA_SPK_TOP_BASE + 0x17)
+#define WSA884X_DAC_VOLTAGE_CTRL_REG (WSA884X_ANA_SPK_TOP_BASE + 0x18)
+#define WSA884X_ATEST1_REG (WSA884X_ANA_SPK_TOP_BASE + 0x19)
+#define WSA884X_ATEST2_REG (WSA884X_ANA_SPK_TOP_BASE + 0x1a)
+#define WSA884X_TOP_BIAS_REG1 (WSA884X_ANA_SPK_TOP_BASE + 0x1b)
+#define WSA884X_TOP_BIAS_REG2 (WSA884X_ANA_SPK_TOP_BASE + 0x1c)
+#define WSA884X_TOP_BIAS_REG3 (WSA884X_ANA_SPK_TOP_BASE + 0x1d)
+#define WSA884X_TOP_BIAS_REG4 (WSA884X_ANA_SPK_TOP_BASE + 0x1e)
+#define WSA884X_PWRSTG_DBG2 (WSA884X_ANA_SPK_TOP_BASE + 0x1f)
+#define WSA884X_DRV_LF_BLK_EN (WSA884X_ANA_SPK_TOP_BASE + 0x20)
+#define WSA884X_DRV_LF_EN (WSA884X_ANA_SPK_TOP_BASE + 0x21)
+#define WSA884X_DRV_LF_MASK_DCC_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x22)
+#define WSA884X_DRV_LF_MISC_CTL1 (WSA884X_ANA_SPK_TOP_BASE + 0x23)
+#define WSA884X_DRV_LF_REG_GAIN (WSA884X_ANA_SPK_TOP_BASE + 0x24)
+#define WSA884X_DRV_OS_CAL_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x25)
+#define WSA884X_DRV_OS_CAL_CTL1 (WSA884X_ANA_SPK_TOP_BASE + 0x26)
+#define WSA884X_PWRSTG_DBG (WSA884X_ANA_SPK_TOP_BASE + 0x27)
+#define WSA884X_BBM_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x28)
+#define WSA884X_TOP_MISC1 (WSA884X_ANA_SPK_TOP_BASE + 0x29)
+#define WSA884X_DAC_VCM_CTRL_REG7 (WSA884X_ANA_SPK_TOP_BASE + 0x2a)
+#define WSA884X_TOP_BIAS_REG5 (WSA884X_ANA_SPK_TOP_BASE + 0x2b)
+#define WSA884X_DRV_LF_MISC_CTL2 (WSA884X_ANA_SPK_TOP_BASE + 0x2c)
+#define WSA884X_SPK_TOP_SPARE_TUNE_2 (WSA884X_ANA_SPK_TOP_BASE + 0x2d)
+#define WSA884X_SPK_TOP_SPARE_TUNE_3 (WSA884X_ANA_SPK_TOP_BASE + 0x2e)
+#define WSA884X_SPK_TOP_SPARE_TUNE_4 (WSA884X_ANA_SPK_TOP_BASE + 0x2f)
+#define WSA884X_SPARE_TUNE_5 (WSA884X_ANA_SPK_TOP_BASE + 0x30)
+#define WSA884X_SPARE_TUNE_6 (WSA884X_ANA_SPK_TOP_BASE + 0x31)
+#define WSA884X_SPARE_TUNE_7 (WSA884X_ANA_SPK_TOP_BASE + 0x32)
+#define WSA884X_SPARE_TUNE_8 (WSA884X_ANA_SPK_TOP_BASE + 0x33)
+#define WSA884X_SPARE_TUNE_9 (WSA884X_ANA_SPK_TOP_BASE + 0x34)
+#define WSA884X_SPARE_TUNE_10 (WSA884X_ANA_SPK_TOP_BASE + 0x35)
+#define WSA884X_PA_STATUS0 (WSA884X_ANA_SPK_TOP_BASE + 0x36)
+#define WSA884X_PA_STATUS1 (WSA884X_ANA_SPK_TOP_BASE + 0x37)
+#define WSA884X_PA_STATUS2 (WSA884X_ANA_SPK_TOP_BASE + 0x38)
+#define WSA884X_PA_STATUS3 (WSA884X_ANA_SPK_TOP_BASE + 0x39)
+#define WSA884X_PA_STATUS4 (WSA884X_ANA_SPK_TOP_BASE + 0x3a)
+#define WSA884X_PA_STATUS5 (WSA884X_ANA_SPK_TOP_BASE + 0x3b)
+#define WSA884X_SPARE_RO_1 (WSA884X_ANA_SPK_TOP_BASE + 0x3c)
+#define WSA884X_SPARE_RO_2 (WSA884X_ANA_SPK_TOP_BASE + 0x3d)
+#define WSA884X_SPARE_RO_3 (WSA884X_ANA_SPK_TOP_BASE + 0x3e)
+
+#define WSA884X_ANA_BOOST_BASE (WSA884X_BASE + 0x0090)
+#define WSA884X_STB_CTRL1 (WSA884X_ANA_BOOST_BASE + 0x00)
+#define WSA884X_STB_CTRL1_SLOPE_COMP_CURRENT_MASK 0xf8
+#define WSA884X_STB_CTRL1_SLOPE_COMP_CURRENT_SHIFT 3
+#define WSA884X_STB_CTRL1_VOUT_FS_MASK 0x07
+#define WSA884X_STB_CTRL1_VOUT_FS_SHIFT 0
+#define WSA884X_CURRENT_LIMIT (WSA884X_ANA_BOOST_BASE + 0x01)
+#define WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_OVRD_EN_MASK 0x80
+#define WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_OVRD_EN_SHIFT 7
+#define WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_MASK 0x7c
+#define WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_SHIFT 2
+#define WSA884X_CURRENT_LIMIT_CLK_PHASE_SHIFT 0
+#define WSA884X_BYP_CTRL1 (WSA884X_ANA_BOOST_BASE + 0x02)
+#define WSA884X_SPARE_CTL_0 (WSA884X_ANA_BOOST_BASE + 0x03)
+#define WSA884X_BOOST_SPARE_CTL_1 (WSA884X_ANA_BOOST_BASE + 0x04)
+#define WSA884X_SPARE_RO_0 (WSA884X_ANA_BOOST_BASE + 0x05)
+#define WSA884X_BOOST_SPARE_RO_1 (WSA884X_ANA_BOOST_BASE + 0x06)
+#define WSA884X_IBIAS1 (WSA884X_ANA_BOOST_BASE + 0x07)
+#define WSA884X_IBIAS2 (WSA884X_ANA_BOOST_BASE + 0x08)
+#define WSA884X_IBIAS3 (WSA884X_ANA_BOOST_BASE + 0x09)
+#define WSA884X_EN_CTRL (WSA884X_ANA_BOOST_BASE + 0x0a)
+#define WSA884X_STB_CTRL2 (WSA884X_ANA_BOOST_BASE + 0x0b)
+#define WSA884X_STB_CTRL3 (WSA884X_ANA_BOOST_BASE + 0x0c)
+#define WSA884X_STB_CTRL4 (WSA884X_ANA_BOOST_BASE + 0x0d)
+#define WSA884X_BYP_CTRL2 (WSA884X_ANA_BOOST_BASE + 0x0e)
+#define WSA884X_BYP_CTRL3 (WSA884X_ANA_BOOST_BASE + 0x0f)
+#define WSA884X_ZX_CTRL1 (WSA884X_ANA_BOOST_BASE + 0x10)
+#define WSA884X_ZX_CTRL1_ZX_DET_EN_MASK 0x80
+#define WSA884X_ZX_CTRL1_ZX_DET_EN_SHIFT 7
+#define WSA884X_ZX_CTRL1_ZX_DET_SW_EN_MASK 0x40
+#define WSA884X_ZX_CTRL1_ZX_DET_SW_EN_SHIFT 6
+#define WSA884X_ZX_CTRL1_ZX_DET_STAGE_DEFAULT_MASK 0x20
+#define WSA884X_ZX_CTRL1_ZX_DET_STAGE_DEFAULT_SHIFT 5
+#define WSA884X_ZX_CTRL1_ZX_DET_SW_SEL_MASK 0x18
+#define WSA884X_ZX_CTRL1_ZX_DET_SW_SEL_SHIFT 3
+#define WSA884X_ZX_CTRL1_ZX_BYP_MASK_IGNORE_MASK 0x04
+#define WSA884X_ZX_CTRL1_ZX_BYP_MASK_IGNORE_SHIFT 2
+#define WSA884X_ZX_CTRL1_ZX_BYP_MASK_DEL_MASK 0x02
+#define WSA884X_ZX_CTRL1_ZX_BYP_MASK_DEL_SHIFT 1
+#define WSA884X_ZX_CTRL1_BOOTCAP_REFRESH_DIS_MASK 0x01
+#define WSA884X_ZX_CTRL1_BOOTCAP_REFRESH_DIS_SHIFT 0
+#define WSA884X_ZX_CTRL2 (WSA884X_ANA_BOOST_BASE + 0x11)
+#define WSA884X_BLEEDER_CTRL (WSA884X_ANA_BOOST_BASE + 0x12)
+#define WSA884X_BOOST_MISC (WSA884X_ANA_BOOST_BASE + 0x13)
+#define WSA884X_PWRSTAGE_CTRL1 (WSA884X_ANA_BOOST_BASE + 0x14)
+#define WSA884X_PWRSTAGE_CTRL2 (WSA884X_ANA_BOOST_BASE + 0x15)
+#define WSA884X_PWRSTAGE_CTRL3 (WSA884X_ANA_BOOST_BASE + 0x16)
+#define WSA884X_PWRSTAGE_CTRL4 (WSA884X_ANA_BOOST_BASE + 0x17)
+#define WSA884X_MAXD_REG1 (WSA884X_ANA_BOOST_BASE + 0x18)
+#define WSA884X_MAXD_REG2 (WSA884X_ANA_BOOST_BASE + 0x19)
+#define WSA884X_ILIM_CTRL1 (WSA884X_ANA_BOOST_BASE + 0x1a)
+#define WSA884X_ILIM_CTRL1_EN_AUTO_MAXD_SEL_MASK 0x80
+#define WSA884X_ILIM_CTRL1_EN_AUTO_MAXD_SEL_SHIFT 0x07
+#define WSA884X_ILIM_CTRL1_EN_ILIM_SW_CLH_MASK 0x40
+#define WSA884X_ILIM_CTRL1_EN_ILIM_SW_CLH_SHIFT 0x06
+#define WSA884X_ILIM_CTRL1_ILIM_OFFSET_CLH_MASK 0x38
+#define WSA884X_ILIM_CTRL1_ILIM_OFFSET_CLH_SHIFT 0x03
+#define WSA884X_ILIM_CTRL1_ILIM_OFFSET_PB_MASK 0x07
+#define WSA884X_ILIM_CTRL1_ILIM_OFFSET_PB_SHIFT 0x00
+#define WSA884X_ILIM_CTRL2 (WSA884X_ANA_BOOST_BASE + 0x1b)
+#define WSA884X_TEST_CTRL1 (WSA884X_ANA_BOOST_BASE + 0x1c)
+#define WSA884X_TEST_CTRL2 (WSA884X_ANA_BOOST_BASE + 0x1d)
+#define WSA884X_SPARE1 (WSA884X_ANA_BOOST_BASE + 0x1e)
+#define WSA884X_BOOT_CAP_CHECK (WSA884X_ANA_BOOST_BASE + 0x1f)
+
+#define WSA884X_ANA_PON_LDOL_BASE (WSA884X_BASE + 0x00b0)
+#define WSA884X_PON_CTL_0 (WSA884X_ANA_PON_LDOL_BASE + 0x00)
+#define WSA884X_PWRSAV_CTL (WSA884X_ANA_PON_LDOL_BASE + 0x01)
+#define WSA884X_PON_LDOL_SPARE_CTL_0 (WSA884X_ANA_PON_LDOL_BASE + 0x02)
+#define WSA884X_PON_LDOL_SPARE_CTL_1 (WSA884X_ANA_PON_LDOL_BASE + 0x03)
+#define WSA884X_PON_LDOL_SPARE_CTL_2 (WSA884X_ANA_PON_LDOL_BASE + 0x04)
+#define WSA884X_PON_LDOL_SPARE_CTL_3 (WSA884X_ANA_PON_LDOL_BASE + 0x05)
+#define WSA884X_PON_CLT_1 (WSA884X_ANA_PON_LDOL_BASE + 0x06)
+#define WSA884X_PON_CTL_2 (WSA884X_ANA_PON_LDOL_BASE + 0x07)
+#define WSA884X_PON_CTL_3 (WSA884X_ANA_PON_LDOL_BASE + 0x08)
+#define WSA884X_CKWD_CTL_0 (WSA884X_ANA_PON_LDOL_BASE + 0x09)
+#define WSA884X_CKWD_CTL_1 (WSA884X_ANA_PON_LDOL_BASE + 0x0a)
+#define WSA884X_CKWD_CTL_1_VPP_SW_CTL_MASK 0x20
+#define WSA884X_CKWD_CTL_1_VPP_SW_CTL_SHIFT 5
+#define WSA884X_CKWD_CTL_1_CKWD_VCOMP_VREF_SEL_MASK 0x1f
+#define WSA884X_CKWD_CTL_1_CKWD_VCOMP_VREF_SEL_SHIFT 0
+#define WSA884X_CKWD_CTL_2 (WSA884X_ANA_PON_LDOL_BASE + 0x0b)
+#define WSA884X_CKSK_CTL_0 (WSA884X_ANA_PON_LDOL_BASE + 0x0c)
+#define WSA884X_PADSW_CTL_0 (WSA884X_ANA_PON_LDOL_BASE + 0x0d)
+#define WSA884X_TEST_0 (WSA884X_ANA_PON_LDOL_BASE + 0x0e)
+#define WSA884X_TEST_1 (WSA884X_ANA_PON_LDOL_BASE + 0x0f)
+#define WSA884X_STATUS_0 (WSA884X_ANA_PON_LDOL_BASE + 0x10)
+#define WSA884X_STATUS_1 (WSA884X_ANA_PON_LDOL_BASE + 0x11)
+#define WSA884X_PON_LDOL_SPARE_TUNE_0 (WSA884X_ANA_PON_LDOL_BASE + 0x12)
+#define WSA884X_PON_LDOL_SPARE_TUNE_1 (WSA884X_ANA_PON_LDOL_BASE + 0x13)
+#define WSA884X_PON_LDOL_SPARE_TUNE_2 (WSA884X_ANA_PON_LDOL_BASE + 0x14)
+#define WSA884X_PON_LDOL_SPARE_TUNE_3 (WSA884X_ANA_PON_LDOL_BASE + 0x15)
+#define WSA884X_PON_LDOL_SPARE_TUNE_4 (WSA884X_ANA_PON_LDOL_BASE + 0x16)
+
+#define WSA884X_DIG_CTRL0_BASE (WSA884X_BASE + 0x0400)
+#define WSA884X_DIG_CTRL0_PAGE (WSA884X_DIG_CTRL0_BASE + 0x00)
+#define WSA884X_CHIP_ID0 (WSA884X_DIG_CTRL0_BASE + 0x01)
+#define WSA884X_CHIP_ID1 (WSA884X_DIG_CTRL0_BASE + 0x02)
+#define WSA884X_CHIP_ID2 (WSA884X_DIG_CTRL0_BASE + 0x03)
+#define WSA884X_CHIP_ID3 (WSA884X_DIG_CTRL0_BASE + 0x04)
+#define WSA884X_BUS_ID (WSA884X_DIG_CTRL0_BASE + 0x05)
+#define WSA884X_CDC_RST_CTL (WSA884X_DIG_CTRL0_BASE + 0x10)
+#define WSA884X_SWR_RESET_EN (WSA884X_DIG_CTRL0_BASE + 0x14)
+#define WSA884X_TOP_CLK_CFG (WSA884X_DIG_CTRL0_BASE + 0x18)
+#define WSA884X_SWR_CLK_RATE (WSA884X_DIG_CTRL0_BASE + 0x19)
+#define WSA884X_CDC_PATH_MODE (WSA884X_DIG_CTRL0_BASE + 0x1a)
+#define WSA884X_CDC_PATH_MODE_RXD_MODE_MASK 0x02
+#define WSA884X_CDC_PATH_MODE_RXD_MODE_SHIFT 0
+#define WSA884X_CDC_PATH_MODE_TXD_MODE_MASK 0x01
+#define WSA884X_CDC_PATH_MODE_TXD_MODE_SHIFT 0
+#define WSA884X_CDC_CLK_CTL (WSA884X_DIG_CTRL0_BASE + 0x1c)
+#define WSA884X_PA_FSM_EN (WSA884X_DIG_CTRL0_BASE + 0x30)
+#define WSA884X_PA_FSM_EN_GLOBAL_PA_EN_MASK 0x01
+#define WSA884X_PA_FSM_EN_GLOBAL_PA_EN_SHIFT 0
+#define WSA884X_PA_FSM_CTL0 (WSA884X_DIG_CTRL0_BASE + 0x31)
+#define WSA884X_PA_FSM_CTL1 (WSA884X_DIG_CTRL0_BASE + 0x32)
+#define WSA884X_PA_FSM_CTL1_NOISE_GATE_BLOCK_MASK 0x38
+#define WSA884X_PA_FSM_TIMER0 (WSA884X_DIG_CTRL0_BASE + 0x33)
+#define WSA884X_PA_FSM_TIMER1 (WSA884X_DIG_CTRL0_BASE + 0x34)
+#define WSA884X_PA_FSM_STA0 (WSA884X_DIG_CTRL0_BASE + 0x35)
+#define WSA884X_PA_FSM_STA1 (WSA884X_DIG_CTRL0_BASE + 0x36)
+#define WSA884X_PA_FSM_ERR_CTL (WSA884X_DIG_CTRL0_BASE + 0x37)
+#define WSA884X_PA_FSM_ERR_COND0 (WSA884X_DIG_CTRL0_BASE + 0x38)
+#define WSA884X_PA_FSM_ERR_COND1 (WSA884X_DIG_CTRL0_BASE + 0x39)
+#define WSA884X_PA_FSM_MSK0 (WSA884X_DIG_CTRL0_BASE + 0x3a)
+#define WSA884X_PA_FSM_MSK1 (WSA884X_DIG_CTRL0_BASE + 0x3b)
+#define WSA884X_PA_FSM_BYP_CTL (WSA884X_DIG_CTRL0_BASE + 0x3c)
+#define WSA884X_PA_FSM_BYP0 (WSA884X_DIG_CTRL0_BASE + 0x3d)
+#define WSA884X_PA_FSM_BYP1 (WSA884X_DIG_CTRL0_BASE + 0x3e)
+#define WSA884X_TADC_VALUE_CTL (WSA884X_DIG_CTRL0_BASE + 0x50)
+#define WSA884X_TEMP_DETECT_CTL (WSA884X_DIG_CTRL0_BASE + 0x51)
+#define WSA884X_TEMP_DIN_MSB (WSA884X_DIG_CTRL0_BASE + 0x52)
+#define WSA884X_TEMP_DIN_LSB (WSA884X_DIG_CTRL0_BASE + 0x53)
+#define WSA884X_TEMP_DOUT_MSB (WSA884X_DIG_CTRL0_BASE + 0x54)
+#define WSA884X_TEMP_DOUT_LSB (WSA884X_DIG_CTRL0_BASE + 0x55)
+#define WSA884X_TEMP_CONFIG0 (WSA884X_DIG_CTRL0_BASE + 0x56)
+#define WSA884X_TEMP_CONFIG1 (WSA884X_DIG_CTRL0_BASE + 0x57)
+#define WSA884X_VBAT_THRM_FLT_CTL (WSA884X_DIG_CTRL0_BASE + 0x58)
+#define WSA884X_VBAT_THRM_FLT_CTL_THRM_COEF_SEL_MASK 0xe0
+#define WSA884X_VBAT_THRM_FLT_CTL_THRM_COEF_SEL_SHIFT 5
+#define WSA884X_VBAT_THRM_FLT_CTL_THRM_FLT_EN_SHIFT 4
+#define WSA884X_VBAT_THRM_FLT_CTL_VBAT_COEF_SEL_MASK 0x0e
+#define WSA884X_VBAT_THRM_FLT_CTL_VBAT_COEF_SEL_SHIFT 1
+#define WSA884X_VBAT_THRM_FLT_CTL_VBAT_FLT_EN_SHIFT 0
+#define WSA884X_VBAT_CAL_CTL (WSA884X_DIG_CTRL0_BASE + 0x59)
+#define WSA884X_VBAT_CAL_CTL_RESERVE_MASK 0x0e
+#define WSA884X_VBAT_CAL_CTL_VBAT_CAL_EN_MASK 0x01
+#define WSA884X_VBAT_DIN_MSB (WSA884X_DIG_CTRL0_BASE + 0x5a)
+#define WSA884X_VBAT_DIN_LSB (WSA884X_DIG_CTRL0_BASE + 0x5b)
+#define WSA884X_VBAT_DOUT_MSB (WSA884X_DIG_CTRL0_BASE + 0x5c)
+#define WSA884X_VBAT_DOUT_LSB (WSA884X_DIG_CTRL0_BASE + 0x5d)
+#define WSA884X_VBAT_CAL_MSB (WSA884X_DIG_CTRL0_BASE + 0x5e)
+#define WSA884X_VBAT_CAL_LSB (WSA884X_DIG_CTRL0_BASE + 0x5f)
+#define WSA884X_UVLO_DEGLITCH_CTL (WSA884X_DIG_CTRL0_BASE + 0x60)
+#define WSA884X_BOP_DEGLITCH_CTL (WSA884X_DIG_CTRL0_BASE + 0x61)
+#define WSA884X_BOP_DEGLITCH_CTL_BOP_DEGLITCH_SETTING_MASK 0x1e
+#define WSA884X_BOP_DEGLITCH_CTL_BOP_DEGLITCH_SETTING_SHIFT 1
+#define WSA884X_BOP_DEGLITCH_CTL_BOP_DEGLITCH_EN_MASK 0x1
+#define WSA884X_BOP_DEGLITCH_CTL_BOP_DEGLITCH_EN_SHIFT 0
+#define WSA884X_VBAT_ZONE_DETC_CTL (WSA884X_DIG_CTRL0_BASE + 0x64)
+#define WSA884X_CPS_CTL (WSA884X_DIG_CTRL0_BASE + 0x68)
+#define WSA884X_CDC_RX_CTL (WSA884X_DIG_CTRL0_BASE + 0x70)
+#define WSA884X_CDC_SPK_DSM_A1_0 (WSA884X_DIG_CTRL0_BASE + 0x71)
+#define WSA884X_CDC_SPK_DSM_A1_1 (WSA884X_DIG_CTRL0_BASE + 0x72)
+#define WSA884X_CDC_SPK_DSM_A2_0 (WSA884X_DIG_CTRL0_BASE + 0x73)
+#define WSA884X_CDC_SPK_DSM_A2_1 (WSA884X_DIG_CTRL0_BASE + 0x74)
+#define WSA884X_CDC_SPK_DSM_A3_0 (WSA884X_DIG_CTRL0_BASE + 0x75)
+#define WSA884X_CDC_SPK_DSM_A3_1 (WSA884X_DIG_CTRL0_BASE + 0x76)
+#define WSA884X_CDC_SPK_DSM_A4_0 (WSA884X_DIG_CTRL0_BASE + 0x77)
+#define WSA884X_CDC_SPK_DSM_A4_1 (WSA884X_DIG_CTRL0_BASE + 0x78)
+#define WSA884X_CDC_SPK_DSM_A5_0 (WSA884X_DIG_CTRL0_BASE + 0x79)
+#define WSA884X_CDC_SPK_DSM_A5_1 (WSA884X_DIG_CTRL0_BASE + 0x7a)
+#define WSA884X_CDC_SPK_DSM_A6_0 (WSA884X_DIG_CTRL0_BASE + 0x7b)
+#define WSA884X_CDC_SPK_DSM_A7_0 (WSA884X_DIG_CTRL0_BASE + 0x7c)
+#define WSA884X_CDC_SPK_DSM_C_0 (WSA884X_DIG_CTRL0_BASE + 0x7d)
+#define WSA884X_CDC_SPK_DSM_C_0_COEF_C3_MASK 0xf0
+#define WSA884X_CDC_SPK_DSM_C_0_COEF_C3_SHIFT 4
+#define WSA884X_CDC_SPK_DSM_C_0_COEF_C2_MASK 0x0f
+#define WSA884X_CDC_SPK_DSM_C_0_COEF_C2_SHIFT 0
+#define WSA884X_CDC_SPK_DSM_C_1 (WSA884X_DIG_CTRL0_BASE + 0x7e)
+#define WSA884X_CDC_SPK_DSM_C_2 (WSA884X_DIG_CTRL0_BASE + 0x7f)
+#define WSA884X_CDC_SPK_DSM_C_2_COEF_C7_MASK 0xf0
+#define WSA884X_CDC_SPK_DSM_C_2_COEF_C7_SHIFT 4
+#define WSA884X_CDC_SPK_DSM_C_2_COEF_C6_MASK 0x0f
+#define WSA884X_CDC_SPK_DSM_C_2_COEF_C6_SHIFT 0
+#define WSA884X_CDC_SPK_DSM_C_3 (WSA884X_DIG_CTRL0_BASE + 0x80)
+#define WSA884X_CDC_SPK_DSM_C_3_COEF_C7_MASK 0x3f
+#define WSA884X_CDC_SPK_DSM_C_3_COEF_C7_SHIFT 0
+#define WSA884X_CDC_SPK_DSM_R1 (WSA884X_DIG_CTRL0_BASE + 0x81)
+#define WSA884X_CDC_SPK_DSM_R2 (WSA884X_DIG_CTRL0_BASE + 0x82)
+#define WSA884X_CDC_SPK_DSM_R3 (WSA884X_DIG_CTRL0_BASE + 0x83)
+#define WSA884X_CDC_SPK_DSM_R4 (WSA884X_DIG_CTRL0_BASE + 0x84)
+#define WSA884X_CDC_SPK_DSM_R5 (WSA884X_DIG_CTRL0_BASE + 0x85)
+#define WSA884X_CDC_SPK_DSM_R6 (WSA884X_DIG_CTRL0_BASE + 0x86)
+#define WSA884X_CDC_SPK_DSM_R7 (WSA884X_DIG_CTRL0_BASE + 0x87)
+#define WSA884X_CDC_SPK_GAIN_PDM_0 (WSA884X_DIG_CTRL0_BASE + 0x88)
+#define WSA884X_CDC_SPK_GAIN_PDM_1 (WSA884X_DIG_CTRL0_BASE + 0x89)
+#define WSA884X_CDC_SPK_GAIN_PDM_2 (WSA884X_DIG_CTRL0_BASE + 0x8a)
+#define WSA884X_PDM_WD_CTL (WSA884X_DIG_CTRL0_BASE + 0x8b)
+#define WSA884X_PDM_WD_CTL_HOLD_OFF_MASK 0x04
+#define WSA884X_PDM_WD_CTL_HOLD_OFF_SHIFT 2
+#define WSA884X_PDM_WD_CTL_TIME_OUT_SEL_MASK 0x02
+#define WSA884X_PDM_WD_CTL_TIME_OUT_SEL_SHIFT 1
+#define WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK 0x01
+#define WSA884X_PDM_WD_CTL_PDM_WD_EN_SHIFT 0
+#define WSA884X_DEM_BYPASS_DATA0 (WSA884X_DIG_CTRL0_BASE + 0x90)
+#define WSA884X_DEM_BYPASS_DATA1 (WSA884X_DIG_CTRL0_BASE + 0x91)
+#define WSA884X_DEM_BYPASS_DATA2 (WSA884X_DIG_CTRL0_BASE + 0x92)
+#define WSA884X_DEM_BYPASS_DATA3 (WSA884X_DIG_CTRL0_BASE + 0x93)
+#define WSA884X_DRE_CTL_0 (WSA884X_DIG_CTRL0_BASE + 0xb0)
+#define WSA884X_DRE_CTL_0_PROG_DELAY_MASK 0xf0
+#define WSA884X_DRE_CTL_0_PROG_DELAY_SHIFT 4
+#define WSA884X_DRE_CTL_0_OFFSET_MASK 0x07
+#define WSA884X_DRE_CTL_0_OFFSET_SHIFT 0
+#define WSA884X_DRE_CTL_1 (WSA884X_DIG_CTRL0_BASE + 0xb1)
+#define WSA884X_DRE_CTL_1_CSR_GAIN_MASK 0x3e
+#define WSA884X_DRE_CTL_1_CSR_GAIN_SHIFT 1
+#define WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK 0x01
+#define WSA884X_DRE_CTL_1_CSR_GAIN_EN_SHIFT 0
+#define WSA884X_DRE_IDLE_DET_CTL (WSA884X_DIG_CTRL0_BASE + 0xb2)
+#define WSA884X_GAIN_RAMPING_CTL (WSA884X_DIG_CTRL0_BASE + 0xb8)
+#define WSA884X_GAIN_RAMPING_MIN (WSA884X_DIG_CTRL0_BASE + 0xb9)
+#define WSA884X_GAIN_RAMPING_MIN_MIN_GAIN_MASK 0x1f
+#define WSA884X_GAIN_RAMPING_MIN_MIN_GAIN_SHIFT 0
+#define WSA884X_TAGC_CTL (WSA884X_DIG_CTRL0_BASE + 0xc0)
+#define WSA884X_TAGC_TIME (WSA884X_DIG_CTRL0_BASE + 0xc1)
+#define WSA884X_TAGC_FORCE_VAL (WSA884X_DIG_CTRL0_BASE + 0xc2)
+#define WSA884X_VAGC_CTL (WSA884X_DIG_CTRL0_BASE + 0xc8)
+#define WSA884X_VAGC_TIME (WSA884X_DIG_CTRL0_BASE + 0xc9)
+#define WSA884X_VAGC_ATTN_LVL_1 (WSA884X_DIG_CTRL0_BASE + 0xca)
+#define WSA884X_VAGC_ATTN_LVL_2 (WSA884X_DIG_CTRL0_BASE + 0xcb)
+#define WSA884X_VAGC_ATTN_LVL_3 (WSA884X_DIG_CTRL0_BASE + 0xcc)
+#define WSA884X_CLSH_CTL_0 (WSA884X_DIG_CTRL0_BASE + 0xd0)
+#define WSA884X_CLSH_CTL_0_CSR_GAIN_EN_SHIFT 7
+#define WSA884X_CLSH_CTL_0_DLY_CODE_MASK 0x70
+#define WSA884X_CLSH_CTL_0_DLY_CODE_SHIFT 4
+#define WSA884X_CLSH_CTL_0_DLY_RST_SHIFT 3
+#define WSA884X_CLSH_CTL_0_DLY_EN_SHIFT 2
+#define WSA884X_CLSH_CTL_0_INPUT_EN_SHIFT 1
+#define WSA884X_CLSH_CTL_0_CLSH_EN_SHIFT 0
+#define WSA884X_CLSH_CTL_1 (WSA884X_DIG_CTRL0_BASE + 0xd1)
+#define WSA884X_CLSH_V_HD_PA (WSA884X_DIG_CTRL0_BASE + 0xd2)
+#define WSA884X_CLSH_V_PA_MIN (WSA884X_DIG_CTRL0_BASE + 0xd3)
+#define WSA884X_CLSH_OVRD_VAL (WSA884X_DIG_CTRL0_BASE + 0xd4)
+#define WSA884X_CLSH_HARD_MAX (WSA884X_DIG_CTRL0_BASE + 0xd5)
+#define WSA884X_CLSH_SOFT_MAX (WSA884X_DIG_CTRL0_BASE + 0xd6)
+#define WSA884X_CLSH_SIG_DP (WSA884X_DIG_CTRL0_BASE + 0xd7)
+#define WSA884X_PBR_DELAY_CTL (WSA884X_DIG_CTRL0_BASE + 0xd8)
+#define WSA884X_CLSH_SRL_MAX_PBR (WSA884X_DIG_CTRL0_BASE + 0xe0)
+#define WSA884X_PBR_MAX_VOLTAGE 20
+#define WSA884X_PBR_MAX_CODE 255
+#define WSA884X_VTH_TO_REG(vth) \
+ ((vth) != 0 ? (((vth) - 150) * WSA884X_PBR_MAX_CODE / (WSA884X_PBR_MAX_VOLTAGE * 100) + 1) : 0)
+#define WSA884X_CLSH_VTH1 (WSA884X_DIG_CTRL0_BASE + 0xe1)
+#define WSA884X_CLSH_VTH2 (WSA884X_DIG_CTRL0_BASE + 0xe2)
+#define WSA884X_CLSH_VTH3 (WSA884X_DIG_CTRL0_BASE + 0xe3)
+#define WSA884X_CLSH_VTH4 (WSA884X_DIG_CTRL0_BASE + 0xe4)
+#define WSA884X_CLSH_VTH5 (WSA884X_DIG_CTRL0_BASE + 0xe5)
+#define WSA884X_CLSH_VTH6 (WSA884X_DIG_CTRL0_BASE + 0xe6)
+#define WSA884X_CLSH_VTH7 (WSA884X_DIG_CTRL0_BASE + 0xe7)
+#define WSA884X_CLSH_VTH8 (WSA884X_DIG_CTRL0_BASE + 0xe8)
+#define WSA884X_CLSH_VTH9 (WSA884X_DIG_CTRL0_BASE + 0xe9)
+#define WSA884X_CLSH_VTH10 (WSA884X_DIG_CTRL0_BASE + 0xea)
+#define WSA884X_CLSH_VTH11 (WSA884X_DIG_CTRL0_BASE + 0xeb)
+#define WSA884X_CLSH_VTH12 (WSA884X_DIG_CTRL0_BASE + 0xec)
+#define WSA884X_CLSH_VTH13 (WSA884X_DIG_CTRL0_BASE + 0xed)
+#define WSA884X_CLSH_VTH14 (WSA884X_DIG_CTRL0_BASE + 0xee)
+#define WSA884X_CLSH_VTH15 (WSA884X_DIG_CTRL0_BASE + 0xef)
+
+#define WSA884X_DIG_CTRL1_BASE (WSA884X_BASE + 0x0500)
+#define WSA884X_DIG_CTRL1_PAGE (WSA884X_DIG_CTRL1_BASE + 0x00)
+#define WSA884X_VPHX_SYS_EN_STATUS (WSA884X_DIG_CTRL1_BASE + 0x01)
+#define WSA884X_ANA_WO_CTL_0 (WSA884X_DIG_CTRL1_BASE + 0x04)
+#define WSA884X_ANA_WO_CTL_0_MODE_SHIFT 0
+#define WSA884X_ANA_WO_CTL_0_VPHX_SYS_EN_MASK 0xc0
+#define WSA884X_ANA_WO_CTL_0_PA_AUX_DISABLE 0x0
+#define WSA884X_ANA_WO_CTL_0_PA_AUX_18_DB 0xa
+#define WSA884X_ANA_WO_CTL_0_PA_AUX_0_DB 0x7
+#define WSA884X_ANA_WO_CTL_0_PA_AUX_GAIN_MASK 0x3c
+#define WSA884X_ANA_WO_CTL_0_PA_MIN_GAIN_BYP_MASK 0x02
+#define WSA884X_ANA_WO_CTL_0_DAC_CM_CLAMP_EN_MODE_SPEAKER 0x1
+#define WSA884X_ANA_WO_CTL_0_DAC_CM_CLAMP_EN_MASK 0x01
+#define WSA884X_ANA_WO_CTL_1 (WSA884X_DIG_CTRL1_BASE + 0x05)
+#define WSA884X_PIN_CTL (WSA884X_DIG_CTRL1_BASE + 0x10)
+#define WSA884X_PIN_CTL_OE (WSA884X_DIG_CTRL1_BASE + 0x11)
+#define WSA884X_PIN_WDATA_IOPAD (WSA884X_DIG_CTRL1_BASE + 0x12)
+#define WSA884X_PIN_STATUS (WSA884X_DIG_CTRL1_BASE + 0x13)
+#define WSA884X_I2C_SLAVE_CTL (WSA884X_DIG_CTRL1_BASE + 0x14)
+#define WSA884X_SPMI_PAD_CTL0 (WSA884X_DIG_CTRL1_BASE + 0x15)
+#define WSA884X_SPMI_PAD_CTL1 (WSA884X_DIG_CTRL1_BASE + 0x16)
+#define WSA884X_SPMI_PAD_CTL2 (WSA884X_DIG_CTRL1_BASE + 0x17)
+#define WSA884X_MEM_CTL (WSA884X_DIG_CTRL1_BASE + 0x18)
+#define WSA884X_SWR_HM_TEST0 (WSA884X_DIG_CTRL1_BASE + 0x19)
+#define WSA884X_SWR_HM_TEST1 (WSA884X_DIG_CTRL1_BASE + 0x1a)
+#define WSA884X_OTP_CTRL0 (WSA884X_DIG_CTRL1_BASE + 0x30)
+#define WSA884X_OTP_CTRL1 (WSA884X_DIG_CTRL1_BASE + 0x31)
+#define WSA884X_OTP_CTRL2 (WSA884X_DIG_CTRL1_BASE + 0x32)
+#define WSA884X_OTP_STAT (WSA884X_DIG_CTRL1_BASE + 0x33)
+#define WSA884X_OTP_PRG_TCSP0 (WSA884X_DIG_CTRL1_BASE + 0x34)
+#define WSA884X_OTP_PRG_TCSP1 (WSA884X_DIG_CTRL1_BASE + 0x35)
+#define WSA884X_OTP_PRG_TPPS (WSA884X_DIG_CTRL1_BASE + 0x36)
+#define WSA884X_OTP_PRG_TVPS (WSA884X_DIG_CTRL1_BASE + 0x37)
+#define WSA884X_OTP_PRG_TVPH (WSA884X_DIG_CTRL1_BASE + 0x38)
+#define WSA884X_OTP_PRG_TPPR0 (WSA884X_DIG_CTRL1_BASE + 0x39)
+#define WSA884X_OTP_PRG_TPPR1 (WSA884X_DIG_CTRL1_BASE + 0x3a)
+#define WSA884X_OTP_PRG_TPPH (WSA884X_DIG_CTRL1_BASE + 0x3b)
+#define WSA884X_OTP_PRG_END (WSA884X_DIG_CTRL1_BASE + 0x3c)
+#define WSA884X_WAVG_PLAY (WSA884X_DIG_CTRL1_BASE + 0x40)
+#define WSA884X_WAVG_CTL (WSA884X_DIG_CTRL1_BASE + 0x41)
+#define WSA884X_WAVG_LRA_PER_0 (WSA884X_DIG_CTRL1_BASE + 0x43)
+#define WSA884X_WAVG_LRA_PER_1 (WSA884X_DIG_CTRL1_BASE + 0x44)
+#define WSA884X_WAVG_DELTA_THETA_0 (WSA884X_DIG_CTRL1_BASE + 0x45)
+#define WSA884X_WAVG_DELTA_THETA_1 (WSA884X_DIG_CTRL1_BASE + 0x46)
+#define WSA884X_WAVG_DIRECT_AMP_0 (WSA884X_DIG_CTRL1_BASE + 0x47)
+#define WSA884X_WAVG_DIRECT_AMP_1 (WSA884X_DIG_CTRL1_BASE + 0x48)
+#define WSA884X_WAVG_PTRN_AMP0_0 (WSA884X_DIG_CTRL1_BASE + 0x49)
+#define WSA884X_WAVG_PTRN_AMP0_1 (WSA884X_DIG_CTRL1_BASE + 0x4a)
+#define WSA884X_WAVG_PTRN_AMP1_0 (WSA884X_DIG_CTRL1_BASE + 0x4b)
+#define WSA884X_WAVG_PTRN_AMP1_1 (WSA884X_DIG_CTRL1_BASE + 0x4c)
+#define WSA884X_WAVG_PTRN_AMP2_0 (WSA884X_DIG_CTRL1_BASE + 0x4d)
+#define WSA884X_WAVG_PTRN_AMP2_1 (WSA884X_DIG_CTRL1_BASE + 0x4e)
+#define WSA884X_WAVG_PTRN_AMP3_0 (WSA884X_DIG_CTRL1_BASE + 0x4f)
+#define WSA884X_WAVG_PTRN_AMP3_1 (WSA884X_DIG_CTRL1_BASE + 0x50)
+#define WSA884X_WAVG_PTRN_AMP4_0 (WSA884X_DIG_CTRL1_BASE + 0x51)
+#define WSA884X_WAVG_PTRN_AMP4_1 (WSA884X_DIG_CTRL1_BASE + 0x52)
+#define WSA884X_WAVG_PTRN_AMP5_0 (WSA884X_DIG_CTRL1_BASE + 0x53)
+#define WSA884X_WAVG_PTRN_AMP5_1 (WSA884X_DIG_CTRL1_BASE + 0x54)
+#define WSA884X_WAVG_PTRN_AMP6_0 (WSA884X_DIG_CTRL1_BASE + 0x55)
+#define WSA884X_WAVG_PTRN_AMP6_1 (WSA884X_DIG_CTRL1_BASE + 0x56)
+#define WSA884X_WAVG_PTRN_AMP7_0 (WSA884X_DIG_CTRL1_BASE + 0x57)
+#define WSA884X_WAVG_PTRN_AMP7_1 (WSA884X_DIG_CTRL1_BASE + 0x58)
+#define WSA884X_WAVG_PER_0_1 (WSA884X_DIG_CTRL1_BASE + 0x59)
+#define WSA884X_WAVG_PER_2_3 (WSA884X_DIG_CTRL1_BASE + 0x5a)
+#define WSA884X_WAVG_PER_4_5 (WSA884X_DIG_CTRL1_BASE + 0x5b)
+#define WSA884X_WAVG_PER_6_7 (WSA884X_DIG_CTRL1_BASE + 0x5c)
+#define WSA884X_WAVG_STA (WSA884X_DIG_CTRL1_BASE + 0x5d)
+#define WSA884X_INTR_MODE (WSA884X_DIG_CTRL1_BASE + 0x80)
+#define WSA884X_INTR_MASK0 (WSA884X_DIG_CTRL1_BASE + 0x81)
+#define WSA884X_INTR_MASK1 (WSA884X_DIG_CTRL1_BASE + 0x82)
+#define WSA884X_INTR_STATUS0 (WSA884X_DIG_CTRL1_BASE + 0x83)
+#define WSA884X_INTR_STATUS1 (WSA884X_DIG_CTRL1_BASE + 0x84)
+#define WSA884X_INTR_CLEAR0 (WSA884X_DIG_CTRL1_BASE + 0x85)
+#define WSA884X_INTR_CLEAR1 (WSA884X_DIG_CTRL1_BASE + 0x86)
+#define WSA884X_INTR_LEVEL0 (WSA884X_DIG_CTRL1_BASE + 0x87)
+#define WSA884X_INTR_LEVEL1 (WSA884X_DIG_CTRL1_BASE + 0x88)
+#define WSA884X_INTR_SET0 (WSA884X_DIG_CTRL1_BASE + 0x89)
+#define WSA884X_INTR_SET1 (WSA884X_DIG_CTRL1_BASE + 0x8a)
+#define WSA884X_INTR_TEST0 (WSA884X_DIG_CTRL1_BASE + 0x8b)
+#define WSA884X_INTR_TEST1 (WSA884X_DIG_CTRL1_BASE + 0x8c)
+#define WSA884X_PDM_TEST_MODE (WSA884X_DIG_CTRL1_BASE + 0xc0)
+#define WSA884X_ATE_TEST_MODE (WSA884X_DIG_CTRL1_BASE + 0xc1)
+#define WSA884X_PA_FSM_DBG (WSA884X_DIG_CTRL1_BASE + 0xc2)
+#define WSA884X_DIG_DEBUG_MODE (WSA884X_DIG_CTRL1_BASE + 0xc3)
+#define WSA884X_DIG_DEBUG_SEL (WSA884X_DIG_CTRL1_BASE + 0xc4)
+#define WSA884X_DIG_DEBUG_EN (WSA884X_DIG_CTRL1_BASE + 0xc5)
+#define WSA884X_TADC_DETECT_DBG_CTL (WSA884X_DIG_CTRL1_BASE + 0xc9)
+#define WSA884X_TADC_DEBUG_MSB (WSA884X_DIG_CTRL1_BASE + 0xca)
+#define WSA884X_TADC_DEBUG_LSB (WSA884X_DIG_CTRL1_BASE + 0xcb)
+#define WSA884X_SAMPLE_EDGE_SEL (WSA884X_DIG_CTRL1_BASE + 0xcc)
+#define WSA884X_SWR_EDGE_SEL (WSA884X_DIG_CTRL1_BASE + 0xcd)
+#define WSA884X_TEST_MODE_CTL (WSA884X_DIG_CTRL1_BASE + 0xce)
+#define WSA884X_IOPAD_CTL (WSA884X_DIG_CTRL1_BASE + 0xcf)
+#define WSA884X_ANA_CSR_DBG_ADD (WSA884X_DIG_CTRL1_BASE + 0xd0)
+#define WSA884X_ANA_CSR_DBG_CTL (WSA884X_DIG_CTRL1_BASE + 0xd1)
+#define WSA884X_CLK_DBG_CTL (WSA884X_DIG_CTRL1_BASE + 0xd2)
+#define WSA884X_SPARE_R (WSA884X_DIG_CTRL1_BASE + 0xf0)
+#define WSA884X_SPARE_0 (WSA884X_DIG_CTRL1_BASE + 0xf1)
+#define WSA884X_SPARE_1 (WSA884X_DIG_CTRL1_BASE + 0xf2)
+#define WSA884X_SPARE_2 (WSA884X_DIG_CTRL1_BASE + 0xf3)
+#define WSA884X_SCODE (WSA884X_DIG_CTRL1_BASE + 0xff)
+
+#define WSA884X_DIG_TRIM_BASE (WSA884X_BASE + 0x0800)
+#define WSA884X_DIG_TRIM_PAGE (WSA884X_DIG_TRIM_BASE + 0x00)
+#define WSA884X_OTP_REG_0 (WSA884X_DIG_TRIM_BASE + 0x80)
+#define WSA884X_OTP_ID_WSA8840 0x0
+#define WSA884X_OTP_ID_WSA8845 0x5
+#define WSA884X_OTP_ID_WSA8845H 0xc
+#define WSA884X_OTP_REG_0_ID_MASK 0x0f
+#define WSA884X_OTP_REG_1 (WSA884X_DIG_TRIM_BASE + 0x81)
+#define WSA884X_OTP_REG_2 (WSA884X_DIG_TRIM_BASE + 0x82)
+#define WSA884X_OTP_REG_3 (WSA884X_DIG_TRIM_BASE + 0x83)
+#define WSA884X_OTP_REG_4 (WSA884X_DIG_TRIM_BASE + 0x84)
+#define WSA884X_OTP_REG_5 (WSA884X_DIG_TRIM_BASE + 0x85)
+#define WSA884X_OTP_REG_6 (WSA884X_DIG_TRIM_BASE + 0x86)
+#define WSA884X_OTP_REG_7 (WSA884X_DIG_TRIM_BASE + 0x87)
+#define WSA884X_OTP_REG_8 (WSA884X_DIG_TRIM_BASE + 0x88)
+#define WSA884X_OTP_REG_9 (WSA884X_DIG_TRIM_BASE + 0x89)
+#define WSA884X_OTP_REG_10 (WSA884X_DIG_TRIM_BASE + 0x8a)
+#define WSA884X_OTP_REG_11 (WSA884X_DIG_TRIM_BASE + 0x8b)
+#define WSA884X_OTP_REG_12 (WSA884X_DIG_TRIM_BASE + 0x8c)
+#define WSA884X_OTP_REG_13 (WSA884X_DIG_TRIM_BASE + 0x8d)
+#define WSA884X_OTP_REG_14 (WSA884X_DIG_TRIM_BASE + 0x8e)
+#define WSA884X_OTP_REG_15 (WSA884X_DIG_TRIM_BASE + 0x8f)
+#define WSA884X_OTP_REG_16 (WSA884X_DIG_TRIM_BASE + 0x90)
+#define WSA884X_OTP_REG_17 (WSA884X_DIG_TRIM_BASE + 0x91)
+#define WSA884X_OTP_REG_18 (WSA884X_DIG_TRIM_BASE + 0x92)
+#define WSA884X_OTP_REG_19 (WSA884X_DIG_TRIM_BASE + 0x93)
+#define WSA884X_OTP_REG_20 (WSA884X_DIG_TRIM_BASE + 0x94)
+#define WSA884X_OTP_REG_21 (WSA884X_DIG_TRIM_BASE + 0x95)
+#define WSA884X_OTP_REG_22 (WSA884X_DIG_TRIM_BASE + 0x96)
+#define WSA884X_OTP_REG_23 (WSA884X_DIG_TRIM_BASE + 0x97)
+#define WSA884X_OTP_REG_24 (WSA884X_DIG_TRIM_BASE + 0x98)
+#define WSA884X_OTP_REG_25 (WSA884X_DIG_TRIM_BASE + 0x99)
+#define WSA884X_OTP_REG_26 (WSA884X_DIG_TRIM_BASE + 0x9a)
+#define WSA884X_OTP_REG_27 (WSA884X_DIG_TRIM_BASE + 0x9b)
+#define WSA884X_OTP_REG_28 (WSA884X_DIG_TRIM_BASE + 0x9c)
+#define WSA884X_OTP_REG_29 (WSA884X_DIG_TRIM_BASE + 0x9d)
+#define WSA884X_OTP_REG_30 (WSA884X_DIG_TRIM_BASE + 0x9e)
+#define WSA884X_OTP_REG_31 (WSA884X_DIG_TRIM_BASE + 0x9f)
+#define WSA884X_OTP_REG_32 (WSA884X_DIG_TRIM_BASE + 0xa0)
+#define WSA884X_OTP_REG_33 (WSA884X_DIG_TRIM_BASE + 0xa1)
+#define WSA884X_OTP_REG_34 (WSA884X_DIG_TRIM_BASE + 0xa2)
+#define WSA884X_OTP_REG_35 (WSA884X_DIG_TRIM_BASE + 0xa3)
+#define WSA884X_OTP_REG_36 (WSA884X_DIG_TRIM_BASE + 0xa4)
+#define WSA884X_OTP_REG_37 (WSA884X_DIG_TRIM_BASE + 0xa5)
+#define WSA884X_OTP_REG_38 (WSA884X_DIG_TRIM_BASE + 0xa6)
+#define WSA884X_OTP_REG_38_RESERVER_MASK 0xf0
+#define WSA884X_OTP_REG_38_RESERVER_SHIFT 4
+#define WSA884X_OTP_REG_38_BST_CFG_SEL_MASK 0x08
+#define WSA884X_OTP_REG_38_BST_CFG_SEL_SHIFT 3
+#define WSA884X_OTP_REG_38_BOOST_ILIM_TUNE_MASK 0x07
+#define WSA884X_OTP_REG_38_BOOST_ILIM_TUNE_SHIFT 0
+#define WSA884X_OTP_REG_39 (WSA884X_DIG_TRIM_BASE + 0xa7)
+#define WSA884X_OTP_REG_40 (WSA884X_DIG_TRIM_BASE + 0xa8)
+#define WSA884X_OTP_REG_40_SPARE_TYPE2_MASK 0xc0
+#define WSA884X_OTP_REG_40_SPARE_TYPE2_SHIFT 6
+#define WSA884X_OTP_REG_40_ISENSE_RESCAL_MASK 0x3c
+#define WSA884X_OTP_REG_40_ISENSE_RESCAL_SHIFT 2
+#define WSA884X_OTP_REG_40_ATE_BOOST_RDSON_TEST_MASK 0x2
+#define WSA884X_OTP_REG_40_ATE_BOOST_RDSON_TEST_SHIFT 1
+#define WSA884X_OTP_REG_40_ATE_CLASSD_RDSON_TEST_MASK 0x1
+#define WSA884X_OTP_REG_40_ATE_CLASSD_RDSON_TEST_SHIFT 0
+#define WSA884X_OTP_REG_41 (WSA884X_DIG_TRIM_BASE + 0xa9)
+#define WSA884X_OTP_REG_63 (WSA884X_DIG_TRIM_BASE + 0xbf)
+
+#define WSA884X_DIG_EMEM_BASE (WSA884X_BASE + 0x08C0)
+#define WSA884X_EMEM_0 (WSA884X_DIG_EMEM_BASE + 0x00)
+#define WSA884X_EMEM_1 (WSA884X_DIG_EMEM_BASE + 0x01)
+#define WSA884X_EMEM_2 (WSA884X_DIG_EMEM_BASE + 0x02)
+#define WSA884X_EMEM_3 (WSA884X_DIG_EMEM_BASE + 0x03)
+#define WSA884X_EMEM_4 (WSA884X_DIG_EMEM_BASE + 0x04)
+#define WSA884X_EMEM_5 (WSA884X_DIG_EMEM_BASE + 0x05)
+#define WSA884X_EMEM_6 (WSA884X_DIG_EMEM_BASE + 0x06)
+#define WSA884X_EMEM_7 (WSA884X_DIG_EMEM_BASE + 0x07)
+#define WSA884X_EMEM_8 (WSA884X_DIG_EMEM_BASE + 0x08)
+#define WSA884X_EMEM_9 (WSA884X_DIG_EMEM_BASE + 0x09)
+#define WSA884X_EMEM_10 (WSA884X_DIG_EMEM_BASE + 0x0a)
+#define WSA884X_EMEM_11 (WSA884X_DIG_EMEM_BASE + 0x0b)
+#define WSA884X_EMEM_12 (WSA884X_DIG_EMEM_BASE + 0x0c)
+#define WSA884X_EMEM_13 (WSA884X_DIG_EMEM_BASE + 0x0d)
+#define WSA884X_EMEM_14 (WSA884X_DIG_EMEM_BASE + 0x0e)
+#define WSA884X_EMEM_15 (WSA884X_DIG_EMEM_BASE + 0x0f)
+#define WSA884X_EMEM_16 (WSA884X_DIG_EMEM_BASE + 0x10)
+#define WSA884X_EMEM_17 (WSA884X_DIG_EMEM_BASE + 0x11)
+#define WSA884X_EMEM_18 (WSA884X_DIG_EMEM_BASE + 0x12)
+#define WSA884X_EMEM_19 (WSA884X_DIG_EMEM_BASE + 0x13)
+#define WSA884X_EMEM_20 (WSA884X_DIG_EMEM_BASE + 0x14)
+#define WSA884X_EMEM_21 (WSA884X_DIG_EMEM_BASE + 0x15)
+#define WSA884X_EMEM_22 (WSA884X_DIG_EMEM_BASE + 0x16)
+#define WSA884X_EMEM_23 (WSA884X_DIG_EMEM_BASE + 0x17)
+#define WSA884X_EMEM_24 (WSA884X_DIG_EMEM_BASE + 0x18)
+#define WSA884X_EMEM_25 (WSA884X_DIG_EMEM_BASE + 0x19)
+#define WSA884X_EMEM_26 (WSA884X_DIG_EMEM_BASE + 0x1a)
+#define WSA884X_EMEM_27 (WSA884X_DIG_EMEM_BASE + 0x1b)
+#define WSA884X_EMEM_28 (WSA884X_DIG_EMEM_BASE + 0x1c)
+#define WSA884X_EMEM_29 (WSA884X_DIG_EMEM_BASE + 0x1d)
+#define WSA884X_EMEM_30 (WSA884X_DIG_EMEM_BASE + 0x1e)
+#define WSA884X_EMEM_31 (WSA884X_DIG_EMEM_BASE + 0x1f)
+#define WSA884X_EMEM_32 (WSA884X_DIG_EMEM_BASE + 0x20)
+#define WSA884X_EMEM_33 (WSA884X_DIG_EMEM_BASE + 0x21)
+#define WSA884X_EMEM_34 (WSA884X_DIG_EMEM_BASE + 0x22)
+#define WSA884X_EMEM_35 (WSA884X_DIG_EMEM_BASE + 0x23)
+#define WSA884X_EMEM_36 (WSA884X_DIG_EMEM_BASE + 0x24)
+#define WSA884X_EMEM_37 (WSA884X_DIG_EMEM_BASE + 0x25)
+#define WSA884X_EMEM_38 (WSA884X_DIG_EMEM_BASE + 0x26)
+#define WSA884X_EMEM_39 (WSA884X_DIG_EMEM_BASE + 0x27)
+#define WSA884X_EMEM_40 (WSA884X_DIG_EMEM_BASE + 0x28)
+#define WSA884X_EMEM_41 (WSA884X_DIG_EMEM_BASE + 0x29)
+#define WSA884X_EMEM_42 (WSA884X_DIG_EMEM_BASE + 0x2a)
+#define WSA884X_EMEM_43 (WSA884X_DIG_EMEM_BASE + 0x2b)
+#define WSA884X_EMEM_44 (WSA884X_DIG_EMEM_BASE + 0x2c)
+#define WSA884X_EMEM_45 (WSA884X_DIG_EMEM_BASE + 0x2d)
+#define WSA884X_EMEM_46 (WSA884X_DIG_EMEM_BASE + 0x2e)
+#define WSA884X_EMEM_47 (WSA884X_DIG_EMEM_BASE + 0x2f)
+#define WSA884X_EMEM_48 (WSA884X_DIG_EMEM_BASE + 0x30)
+#define WSA884X_EMEM_49 (WSA884X_DIG_EMEM_BASE + 0x31)
+#define WSA884X_EMEM_50 (WSA884X_DIG_EMEM_BASE + 0x32)
+#define WSA884X_EMEM_51 (WSA884X_DIG_EMEM_BASE + 0x33)
+#define WSA884X_EMEM_52 (WSA884X_DIG_EMEM_BASE + 0x34)
+#define WSA884X_EMEM_53 (WSA884X_DIG_EMEM_BASE + 0x35)
+#define WSA884X_EMEM_54 (WSA884X_DIG_EMEM_BASE + 0x36)
+#define WSA884X_EMEM_55 (WSA884X_DIG_EMEM_BASE + 0x37)
+#define WSA884X_EMEM_56 (WSA884X_DIG_EMEM_BASE + 0x38)
+#define WSA884X_EMEM_57 (WSA884X_DIG_EMEM_BASE + 0x39)
+#define WSA884X_EMEM_58 (WSA884X_DIG_EMEM_BASE + 0x3a)
+#define WSA884X_EMEM_59 (WSA884X_DIG_EMEM_BASE + 0x3b)
+#define WSA884X_EMEM_60 (WSA884X_DIG_EMEM_BASE + 0x3c)
+#define WSA884X_EMEM_61 (WSA884X_DIG_EMEM_BASE + 0x3d)
+#define WSA884X_EMEM_62 (WSA884X_DIG_EMEM_BASE + 0x3e)
+#define WSA884X_EMEM_63 (WSA884X_DIG_EMEM_BASE + 0x3f)
+
+#define WSA884X_NUM_REGISTERS (WSA884X_EMEM_63 + 1)
+#define WSA884X_MAX_REGISTER (WSA884X_NUM_REGISTERS - 1)
+
+#define WSA884X_SUPPLIES_NUM 2
+#define WSA884X_MAX_SWR_PORTS 6
+#define WSA884X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
+ SNDRV_PCM_RATE_384000)
+/* Fractional Rates */
+#define WSA884X_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800)
+
+#define WSA884X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct wsa884x_priv {
+ struct regmap *regmap;
+ struct device *dev;
+ struct regulator_bulk_data supplies[WSA884X_SUPPLIES_NUM];
+ struct sdw_slave *slave;
+ struct sdw_stream_config sconfig;
+ struct sdw_stream_runtime *sruntime;
+ struct sdw_port_config port_config[WSA884X_MAX_SWR_PORTS];
+ struct gpio_desc *sd_n;
+ bool port_prepared[WSA884X_MAX_SWR_PORTS];
+ bool port_enable[WSA884X_MAX_SWR_PORTS];
+ unsigned int variant;
+ int active_ports;
+ int dev_mode;
+ bool hw_init;
+};
+
+enum {
+ COMP_OFFSET0,
+ COMP_OFFSET1,
+ COMP_OFFSET2,
+ COMP_OFFSET3,
+ COMP_OFFSET4,
+};
+
+enum wsa884x_gain {
+ G_21_DB = 0,
+ G_19P5_DB,
+ G_18_DB,
+ G_16P5_DB,
+ G_15_DB,
+ G_13P5_DB,
+ G_12_DB,
+ G_10P5_DB,
+ G_9_DB,
+ G_7P5_DB,
+ G_6_DB,
+ G_4P5_DB,
+ G_3_DB,
+ G_1P5_DB,
+ G_0_DB,
+ G_M1P5_DB,
+ G_M3_DB,
+ G_M4P5_DB,
+ G_M6_DB,
+ G_MAX_DB,
+};
+
+enum wsa884x_isense {
+ ISENSE_6_DB = 0,
+ ISENSE_12_DB,
+ ISENSE_15_DB,
+ ISENSE_18_DB,
+};
+
+enum wsa884x_vsense {
+ VSENSE_M12_DB = 0,
+ VSENSE_M15_DB,
+ VSENSE_M18_DB,
+ VSENSE_M21_DB,
+ VSENSE_M24_DB,
+};
+
+enum wsa884x_port_ids {
+ WSA884X_PORT_DAC,
+ WSA884X_PORT_COMP,
+ WSA884X_PORT_BOOST,
+ WSA884X_PORT_PBR,
+ WSA884X_PORT_VISENSE,
+ WSA884X_PORT_CPS,
+};
+
+static const char * const wsa884x_supply_name[] = {
+ "vdd-io",
+ "vdd-1p8",
+};
+
+static const char * const wsa884x_dev_mode_text[] = {
+ "Speaker", "Receiver"
+};
+
+enum wsa884x_mode {
+ WSA884X_SPEAKER,
+ WSA884X_RECEIVER,
+};
+
+static const struct soc_enum wsa884x_dev_mode_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa884x_dev_mode_text), wsa884x_dev_mode_text);
+
+static struct sdw_dpn_prop wsa884x_sink_dpn_prop[WSA884X_MAX_SWR_PORTS] = {
+ {
+ .num = WSA884X_PORT_DAC + 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ .read_only_wordlength = true,
+ }, {
+ .num = WSA884X_PORT_COMP + 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ .read_only_wordlength = true,
+ }, {
+ .num = WSA884X_PORT_BOOST + 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ .read_only_wordlength = true,
+ }, {
+ .num = WSA884X_PORT_PBR + 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ .read_only_wordlength = true,
+ }, {
+ .num = WSA884X_PORT_VISENSE + 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ .read_only_wordlength = true,
+ }, {
+ .num = WSA884X_PORT_CPS + 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ .read_only_wordlength = true,
+ }
+};
+
+static const struct sdw_port_config wsa884x_pconfig[WSA884X_MAX_SWR_PORTS] = {
+ {
+ .num = WSA884X_PORT_DAC + 1,
+ .ch_mask = 0x1,
+ }, {
+ .num = WSA884X_PORT_COMP + 1,
+ .ch_mask = 0xf,
+ }, {
+ .num = WSA884X_PORT_BOOST + 1,
+ .ch_mask = 0x3,
+ }, {
+ .num = WSA884X_PORT_PBR + 1,
+ .ch_mask = 0x1,
+ }, {
+ .num = WSA884X_PORT_VISENSE + 1,
+ .ch_mask = 0x3,
+ }, {
+ .num = WSA884X_PORT_CPS + 1,
+ .ch_mask = 0x3,
+ },
+};
+
+static struct reg_default wsa884x_defaults[] = {
+ { WSA884X_BG_CTRL, 0xa5 },
+ { WSA884X_ADC_CTRL, 0x00 },
+ { WSA884X_BOP1_PROG, 0x22 },
+ { WSA884X_BOP2_PROG, 0x44 },
+ { WSA884X_UVLO_PROG, 0x99 },
+ { WSA884X_UVLO_PROG1, 0x70 },
+ { WSA884X_SPARE_CTRL_0, 0x00 },
+ { WSA884X_SPARE_CTRL_1, 0x00 },
+ { WSA884X_SPARE_CTRL_2, 0x00 },
+ { WSA884X_SPARE_CTRL_3, 0x00 },
+ { WSA884X_REF_CTRL, 0xd2 },
+ { WSA884X_BG_TEST_CTL, 0x06 },
+ { WSA884X_BG_BIAS, 0xd7 },
+ { WSA884X_ADC_PROG, 0x08 },
+ { WSA884X_ADC_IREF_CTL, 0x57 },
+ { WSA884X_ADC_ISENS_CTL, 0x47 },
+ { WSA884X_ADC_CLK_CTL, 0x87 },
+ { WSA884X_ADC_TEST_CTL, 0x00 },
+ { WSA884X_ADC_BIAS, 0x51 },
+ { WSA884X_VBAT_SNS, 0xa0 },
+ { WSA884X_BOP_ATEST_SEL, 0x00 },
+ { WSA884X_MISC0, 0x04 },
+ { WSA884X_MISC1, 0x75 },
+ { WSA884X_MISC2, 0x00 },
+ { WSA884X_MISC3, 0x10 },
+ { WSA884X_SPARE_TSBG_0, 0x00 },
+ { WSA884X_SPARE_TUNE_0, 0x00 },
+ { WSA884X_SPARE_TUNE_1, 0x00 },
+ { WSA884X_VSENSE1, 0xe7 },
+ { WSA884X_ISENSE2, 0x27 },
+ { WSA884X_SPARE_CTL_1, 0x00 },
+ { WSA884X_SPARE_CTL_2, 0x00 },
+ { WSA884X_SPARE_CTL_3, 0x00 },
+ { WSA884X_SPARE_CTL_4, 0x00 },
+ { WSA884X_EN, 0x10 },
+ { WSA884X_OVERRIDE1, 0x00 },
+ { WSA884X_OVERRIDE2, 0x08 },
+ { WSA884X_ISENSE1, 0xd4 },
+ { WSA884X_ISENSE_CAL, 0x00 },
+ { WSA884X_MISC, 0x00 },
+ { WSA884X_ADC_0, 0x00 },
+ { WSA884X_ADC_1, 0x00 },
+ { WSA884X_ADC_2, 0x40 },
+ { WSA884X_ADC_3, 0x80 },
+ { WSA884X_ADC_4, 0x25 },
+ { WSA884X_ADC_5, 0x24 },
+ { WSA884X_ADC_6, 0x0a },
+ { WSA884X_ADC_7, 0x81 },
+ { WSA884X_IVSENSE_SPARE_TUNE_1, 0x00 },
+ { WSA884X_SPARE_TUNE_2, 0x00 },
+ { WSA884X_SPARE_TUNE_3, 0x00 },
+ { WSA884X_SPARE_TUNE_4, 0x00 },
+ { WSA884X_TOP_CTRL1, 0xd3 },
+ { WSA884X_CLIP_DET_CTRL1, 0x7e },
+ { WSA884X_CLIP_DET_CTRL2, 0x4c },
+ { WSA884X_DAC_CTRL1, 0xa4 },
+ { WSA884X_DAC_VCM_CTRL_REG1, 0x02 },
+ { WSA884X_DAC_VCM_CTRL_REG2, 0x00 },
+ { WSA884X_DAC_VCM_CTRL_REG3, 0x00 },
+ { WSA884X_DAC_VCM_CTRL_REG4, 0x00 },
+ { WSA884X_DAC_VCM_CTRL_REG5, 0x00 },
+ { WSA884X_DAC_VCM_CTRL_REG6, 0x00 },
+ { WSA884X_PWM_CLK_CTL, 0x20 },
+ { WSA884X_DRV_LF_LDO_SEL, 0xaa },
+ { WSA884X_OCP_CTL, 0xc6 },
+ { WSA884X_PDRV_HS_CTL, 0x52 },
+ { WSA884X_PDRV_LS_CTL, 0x4a },
+ { WSA884X_SPK_TOP_SPARE_CTL_1, 0x00 },
+ { WSA884X_SPK_TOP_SPARE_CTL_2, 0x00 },
+ { WSA884X_SPK_TOP_SPARE_CTL_3, 0x00 },
+ { WSA884X_SPK_TOP_SPARE_CTL_4, 0x00 },
+ { WSA884X_SPARE_CTL_5, 0x00 },
+ { WSA884X_DAC_EN_DEBUG_REG, 0x00 },
+ { WSA884X_DAC_OPAMP_BIAS1_REG, 0x48 },
+ { WSA884X_DAC_OPAMP_BIAS2_REG, 0x48 },
+ { WSA884X_DAC_TUNE1, 0x02 },
+ { WSA884X_DAC_VOLTAGE_CTRL_REG, 0x05 },
+ { WSA884X_ATEST1_REG, 0x00 },
+ { WSA884X_ATEST2_REG, 0x00 },
+ { WSA884X_TOP_BIAS_REG1, 0x6a },
+ { WSA884X_TOP_BIAS_REG2, 0x65 },
+ { WSA884X_TOP_BIAS_REG3, 0x55 },
+ { WSA884X_TOP_BIAS_REG4, 0xa9 },
+ { WSA884X_PWRSTG_DBG2, 0x21 },
+ { WSA884X_DRV_LF_BLK_EN, 0x0f },
+ { WSA884X_DRV_LF_EN, 0x0a },
+ { WSA884X_DRV_LF_MASK_DCC_CTL, 0x08 },
+ { WSA884X_DRV_LF_MISC_CTL1, 0x30 },
+ { WSA884X_DRV_LF_REG_GAIN, 0x00 },
+ { WSA884X_DRV_OS_CAL_CTL, 0x00 },
+ { WSA884X_DRV_OS_CAL_CTL1, 0x90 },
+ { WSA884X_PWRSTG_DBG, 0x08 },
+ { WSA884X_BBM_CTL, 0x92 },
+ { WSA884X_TOP_MISC1, 0x00 },
+ { WSA884X_DAC_VCM_CTRL_REG7, 0x00 },
+ { WSA884X_TOP_BIAS_REG5, 0x15 },
+ { WSA884X_DRV_LF_MISC_CTL2, 0x00 },
+ { WSA884X_STB_CTRL1, 0x42 },
+ { WSA884X_CURRENT_LIMIT, 0x54 },
+ { WSA884X_BYP_CTRL1, 0x01 },
+ { WSA884X_SPARE_CTL_0, 0x00 },
+ { WSA884X_BOOST_SPARE_CTL_1, 0x00 },
+ { WSA884X_IBIAS1, 0x00 },
+ { WSA884X_IBIAS2, 0x00 },
+ { WSA884X_IBIAS3, 0x00 },
+ { WSA884X_EN_CTRL, 0x42 },
+ { WSA884X_STB_CTRL2, 0x03 },
+ { WSA884X_STB_CTRL3, 0x3c },
+ { WSA884X_STB_CTRL4, 0x30 },
+ { WSA884X_BYP_CTRL2, 0x97 },
+ { WSA884X_BYP_CTRL3, 0x11 },
+ { WSA884X_ZX_CTRL1, 0xf0 },
+ { WSA884X_ZX_CTRL2, 0x04 },
+ { WSA884X_BLEEDER_CTRL, 0x04 },
+ { WSA884X_BOOST_MISC, 0x62 },
+ { WSA884X_PWRSTAGE_CTRL1, 0x00 },
+ { WSA884X_PWRSTAGE_CTRL2, 0x31 },
+ { WSA884X_PWRSTAGE_CTRL3, 0x81 },
+ { WSA884X_PWRSTAGE_CTRL4, 0x5f },
+ { WSA884X_MAXD_REG1, 0x00 },
+ { WSA884X_MAXD_REG2, 0x5b },
+ { WSA884X_ILIM_CTRL1, 0xe2 },
+ { WSA884X_ILIM_CTRL2, 0x90 },
+ { WSA884X_TEST_CTRL1, 0x00 },
+ { WSA884X_TEST_CTRL2, 0x00 },
+ { WSA884X_SPARE1, 0x00 },
+ { WSA884X_BOOT_CAP_CHECK, 0x01 },
+ { WSA884X_PON_CTL_0, 0x12 },
+ { WSA884X_PWRSAV_CTL, 0xaa },
+ { WSA884X_PON_LDOL_SPARE_CTL_0, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_CTL_1, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_CTL_2, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_CTL_3, 0x00 },
+ { WSA884X_PON_CLT_1, 0xe1 },
+ { WSA884X_PON_CTL_2, 0x00 },
+ { WSA884X_PON_CTL_3, 0x70 },
+ { WSA884X_CKWD_CTL_0, 0x14 },
+ { WSA884X_CKWD_CTL_1, 0x3b },
+ { WSA884X_CKWD_CTL_2, 0x00 },
+ { WSA884X_CKSK_CTL_0, 0x00 },
+ { WSA884X_PADSW_CTL_0, 0x00 },
+ { WSA884X_TEST_0, 0x00 },
+ { WSA884X_TEST_1, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_TUNE_0, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_TUNE_1, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_TUNE_2, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_TUNE_3, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_TUNE_4, 0x00 },
+ { WSA884X_DIG_CTRL0_PAGE, 0x00 },
+ { WSA884X_CDC_RST_CTL, 0x01 },
+ { WSA884X_SWR_RESET_EN, 0x00 },
+ { WSA884X_TOP_CLK_CFG, 0x00 },
+ { WSA884X_SWR_CLK_RATE, 0x00 },
+ { WSA884X_CDC_PATH_MODE, 0x00 },
+ { WSA884X_CDC_CLK_CTL, 0x1f },
+ { WSA884X_PA_FSM_EN, 0x00 },
+ { WSA884X_PA_FSM_CTL0, 0x00 },
+ { WSA884X_PA_FSM_CTL1, 0xfe },
+ { WSA884X_PA_FSM_TIMER0, 0x80 },
+ { WSA884X_PA_FSM_TIMER1, 0x80 },
+ { WSA884X_PA_FSM_ERR_CTL, 0x00 },
+ { WSA884X_PA_FSM_MSK0, 0x00 },
+ { WSA884X_PA_FSM_MSK1, 0x00 },
+ { WSA884X_PA_FSM_BYP_CTL, 0x00 },
+ { WSA884X_PA_FSM_BYP0, 0x00 },
+ { WSA884X_PA_FSM_BYP1, 0x00 },
+ { WSA884X_TADC_VALUE_CTL, 0x03 },
+ { WSA884X_TEMP_DETECT_CTL, 0x01 },
+ { WSA884X_TEMP_CONFIG0, 0x00 },
+ { WSA884X_TEMP_CONFIG1, 0x00 },
+ { WSA884X_VBAT_THRM_FLT_CTL, 0x7f },
+ { WSA884X_VBAT_CAL_CTL, 0x01 },
+ { WSA884X_UVLO_DEGLITCH_CTL, 0x05 },
+ { WSA884X_BOP_DEGLITCH_CTL, 0x05 },
+ { WSA884X_VBAT_ZONE_DETC_CTL, 0x31 },
+ { WSA884X_CPS_CTL, 0x00 },
+ { WSA884X_CDC_RX_CTL, 0xfe },
+ { WSA884X_CDC_SPK_DSM_A1_0, 0x00 },
+ { WSA884X_CDC_SPK_DSM_A1_1, 0x01 },
+ { WSA884X_CDC_SPK_DSM_A2_0, 0x96 },
+ { WSA884X_CDC_SPK_DSM_A2_1, 0x09 },
+ { WSA884X_CDC_SPK_DSM_A3_0, 0xab },
+ { WSA884X_CDC_SPK_DSM_A3_1, 0x05 },
+ { WSA884X_CDC_SPK_DSM_A4_0, 0x1c },
+ { WSA884X_CDC_SPK_DSM_A4_1, 0x02 },
+ { WSA884X_CDC_SPK_DSM_A5_0, 0x17 },
+ { WSA884X_CDC_SPK_DSM_A5_1, 0x02 },
+ { WSA884X_CDC_SPK_DSM_A6_0, 0xaa },
+ { WSA884X_CDC_SPK_DSM_A7_0, 0xe3 },
+ { WSA884X_CDC_SPK_DSM_C_0, 0x69 },
+ { WSA884X_CDC_SPK_DSM_C_1, 0x54 },
+ { WSA884X_CDC_SPK_DSM_C_2, 0x02 },
+ { WSA884X_CDC_SPK_DSM_C_3, 0x15 },
+ { WSA884X_CDC_SPK_DSM_R1, 0xa4 },
+ { WSA884X_CDC_SPK_DSM_R2, 0xb5 },
+ { WSA884X_CDC_SPK_DSM_R3, 0x86 },
+ { WSA884X_CDC_SPK_DSM_R4, 0x85 },
+ { WSA884X_CDC_SPK_DSM_R5, 0xaa },
+ { WSA884X_CDC_SPK_DSM_R6, 0xe2 },
+ { WSA884X_CDC_SPK_DSM_R7, 0x62 },
+ { WSA884X_CDC_SPK_GAIN_PDM_0, 0x00 },
+ { WSA884X_CDC_SPK_GAIN_PDM_1, 0xfc },
+ { WSA884X_CDC_SPK_GAIN_PDM_2, 0x05 },
+ { WSA884X_PDM_WD_CTL, 0x00 },
+ { WSA884X_DEM_BYPASS_DATA0, 0x00 },
+ { WSA884X_DEM_BYPASS_DATA1, 0x00 },
+ { WSA884X_DEM_BYPASS_DATA2, 0x00 },
+ { WSA884X_DEM_BYPASS_DATA3, 0x00 },
+ { WSA884X_DRE_CTL_0, 0x70 },
+ { WSA884X_DRE_CTL_1, 0x04 },
+ { WSA884X_DRE_IDLE_DET_CTL, 0x2f },
+ { WSA884X_GAIN_RAMPING_CTL, 0x50 },
+ { WSA884X_GAIN_RAMPING_MIN, 0x12 },
+ { WSA884X_TAGC_CTL, 0x15 },
+ { WSA884X_TAGC_TIME, 0xbc },
+ { WSA884X_TAGC_FORCE_VAL, 0x00 },
+ { WSA884X_VAGC_CTL, 0x01 },
+ { WSA884X_VAGC_TIME, 0x0f },
+ { WSA884X_VAGC_ATTN_LVL_1, 0x03 },
+ { WSA884X_VAGC_ATTN_LVL_2, 0x06 },
+ { WSA884X_VAGC_ATTN_LVL_3, 0x09 },
+ { WSA884X_CLSH_CTL_0, 0x37 },
+ { WSA884X_CLSH_CTL_1, 0x81 },
+ { WSA884X_CLSH_V_HD_PA, 0x0c },
+ { WSA884X_CLSH_V_PA_MIN, 0x00 },
+ { WSA884X_CLSH_OVRD_VAL, 0x00 },
+ { WSA884X_CLSH_HARD_MAX, 0xff },
+ { WSA884X_CLSH_SOFT_MAX, 0xf5 },
+ { WSA884X_CLSH_SIG_DP, 0x00 },
+ { WSA884X_PBR_DELAY_CTL, 0x07 },
+ { WSA884X_CLSH_SRL_MAX_PBR, 0x02 },
+ { WSA884X_CLSH_VTH1, 0x00 },
+ { WSA884X_CLSH_VTH2, 0x00 },
+ { WSA884X_CLSH_VTH3, 0x00 },
+ { WSA884X_CLSH_VTH4, 0x00 },
+ { WSA884X_CLSH_VTH5, 0x00 },
+ { WSA884X_CLSH_VTH6, 0x00 },
+ { WSA884X_CLSH_VTH7, 0x00 },
+ { WSA884X_CLSH_VTH8, 0x00 },
+ { WSA884X_CLSH_VTH9, 0x00 },
+ { WSA884X_CLSH_VTH10, 0x00 },
+ { WSA884X_CLSH_VTH11, 0x00 },
+ { WSA884X_CLSH_VTH12, 0x00 },
+ { WSA884X_CLSH_VTH13, 0x00 },
+ { WSA884X_CLSH_VTH14, 0x00 },
+ { WSA884X_CLSH_VTH15, 0x00 },
+ { WSA884X_DIG_CTRL1_PAGE, 0x00 },
+ { WSA884X_PIN_CTL, 0x04 },
+ { WSA884X_PIN_CTL_OE, 0x00 },
+ { WSA884X_PIN_WDATA_IOPAD, 0x00 },
+ { WSA884X_I2C_SLAVE_CTL, 0x00 },
+ { WSA884X_SPMI_PAD_CTL0, 0x2f },
+ { WSA884X_SPMI_PAD_CTL1, 0x2f },
+ { WSA884X_SPMI_PAD_CTL2, 0x2f },
+ { WSA884X_MEM_CTL, 0x00 },
+ { WSA884X_SWR_HM_TEST0, 0x08 },
+ { WSA884X_OTP_CTRL0, 0x00 },
+ { WSA884X_OTP_CTRL2, 0x00 },
+ { WSA884X_OTP_PRG_TCSP0, 0x77 },
+ { WSA884X_OTP_PRG_TCSP1, 0x00 },
+ { WSA884X_OTP_PRG_TPPS, 0x47 },
+ { WSA884X_OTP_PRG_TVPS, 0x3b },
+ { WSA884X_OTP_PRG_TVPH, 0x47 },
+ { WSA884X_OTP_PRG_TPPR0, 0x47 },
+ { WSA884X_OTP_PRG_TPPR1, 0x00 },
+ { WSA884X_OTP_PRG_TPPH, 0x47 },
+ { WSA884X_OTP_PRG_END, 0x47 },
+ { WSA884X_WAVG_PLAY, 0x00 },
+ { WSA884X_WAVG_CTL, 0x06 },
+ { WSA884X_WAVG_LRA_PER_0, 0xd1 },
+ { WSA884X_WAVG_LRA_PER_1, 0x00 },
+ { WSA884X_WAVG_DELTA_THETA_0, 0xe6 },
+ { WSA884X_WAVG_DELTA_THETA_1, 0x04 },
+ { WSA884X_WAVG_DIRECT_AMP_0, 0x50 },
+ { WSA884X_WAVG_DIRECT_AMP_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP0_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP0_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP1_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP1_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP2_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP2_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP3_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP3_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP4_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP4_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP5_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP5_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP6_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP6_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP7_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP7_1, 0x00 },
+ { WSA884X_WAVG_PER_0_1, 0x88 },
+ { WSA884X_WAVG_PER_2_3, 0x88 },
+ { WSA884X_WAVG_PER_4_5, 0x88 },
+ { WSA884X_WAVG_PER_6_7, 0x88 },
+ { WSA884X_INTR_MODE, 0x00 },
+ { WSA884X_INTR_MASK0, 0x90 },
+ { WSA884X_INTR_MASK1, 0x00 },
+ { WSA884X_INTR_CLEAR0, 0x00 },
+ { WSA884X_INTR_CLEAR1, 0x00 },
+ { WSA884X_INTR_LEVEL0, 0x04 },
+ { WSA884X_INTR_LEVEL1, 0x00 },
+ { WSA884X_INTR_SET0, 0x00 },
+ { WSA884X_INTR_SET1, 0x00 },
+ { WSA884X_INTR_TEST0, 0x00 },
+ { WSA884X_INTR_TEST1, 0x00 },
+ { WSA884X_PDM_TEST_MODE, 0x00 },
+ { WSA884X_PA_FSM_DBG, 0x00 },
+ { WSA884X_DIG_DEBUG_MODE, 0x00 },
+ { WSA884X_DIG_DEBUG_SEL, 0x00 },
+ { WSA884X_DIG_DEBUG_EN, 0x00 },
+ { WSA884X_TADC_DETECT_DBG_CTL, 0x00 },
+ { WSA884X_TADC_DEBUG_MSB, 0x00 },
+ { WSA884X_TADC_DEBUG_LSB, 0x00 },
+ { WSA884X_SAMPLE_EDGE_SEL, 0x7f },
+ { WSA884X_SWR_EDGE_SEL, 0x00 },
+ { WSA884X_TEST_MODE_CTL, 0x05 },
+ { WSA884X_IOPAD_CTL, 0x00 },
+ { WSA884X_ANA_CSR_DBG_ADD, 0x00 },
+ { WSA884X_ANA_CSR_DBG_CTL, 0x12 },
+ { WSA884X_CLK_DBG_CTL, 0x00 },
+ { WSA884X_SPARE_0, 0x00 },
+ { WSA884X_SPARE_1, 0x00 },
+ { WSA884X_SPARE_2, 0x00 },
+ { WSA884X_SCODE, 0x00 },
+ { WSA884X_DIG_TRIM_PAGE, 0x00 },
+ { WSA884X_EMEM_0, 0x00 },
+ { WSA884X_EMEM_1, 0x00 },
+ { WSA884X_EMEM_2, 0x00 },
+ { WSA884X_EMEM_3, 0x00 },
+ { WSA884X_EMEM_4, 0x00 },
+ { WSA884X_EMEM_5, 0x00 },
+ { WSA884X_EMEM_6, 0x00 },
+ { WSA884X_EMEM_7, 0x00 },
+ { WSA884X_EMEM_8, 0x00 },
+ { WSA884X_EMEM_9, 0x00 },
+ { WSA884X_EMEM_10, 0x00 },
+ { WSA884X_EMEM_11, 0x00 },
+ { WSA884X_EMEM_12, 0x00 },
+ { WSA884X_EMEM_13, 0x00 },
+ { WSA884X_EMEM_14, 0x00 },
+ { WSA884X_EMEM_15, 0x00 },
+ { WSA884X_EMEM_16, 0x00 },
+ { WSA884X_EMEM_17, 0x00 },
+ { WSA884X_EMEM_18, 0x00 },
+ { WSA884X_EMEM_19, 0x00 },
+ { WSA884X_EMEM_20, 0x00 },
+ { WSA884X_EMEM_21, 0x00 },
+ { WSA884X_EMEM_22, 0x00 },
+ { WSA884X_EMEM_23, 0x00 },
+ { WSA884X_EMEM_24, 0x00 },
+ { WSA884X_EMEM_25, 0x00 },
+ { WSA884X_EMEM_26, 0x00 },
+ { WSA884X_EMEM_27, 0x00 },
+ { WSA884X_EMEM_28, 0x00 },
+ { WSA884X_EMEM_29, 0x00 },
+ { WSA884X_EMEM_30, 0x00 },
+ { WSA884X_EMEM_31, 0x00 },
+ { WSA884X_EMEM_32, 0x00 },
+ { WSA884X_EMEM_33, 0x00 },
+ { WSA884X_EMEM_34, 0x00 },
+ { WSA884X_EMEM_35, 0x00 },
+ { WSA884X_EMEM_36, 0x00 },
+ { WSA884X_EMEM_37, 0x00 },
+ { WSA884X_EMEM_38, 0x00 },
+ { WSA884X_EMEM_39, 0x00 },
+ { WSA884X_EMEM_40, 0x00 },
+ { WSA884X_EMEM_41, 0x00 },
+ { WSA884X_EMEM_42, 0x00 },
+ { WSA884X_EMEM_43, 0x00 },
+ { WSA884X_EMEM_44, 0x00 },
+ { WSA884X_EMEM_45, 0x00 },
+ { WSA884X_EMEM_46, 0x00 },
+ { WSA884X_EMEM_47, 0x00 },
+ { WSA884X_EMEM_48, 0x00 },
+ { WSA884X_EMEM_49, 0x00 },
+ { WSA884X_EMEM_50, 0x00 },
+ { WSA884X_EMEM_51, 0x00 },
+ { WSA884X_EMEM_52, 0x00 },
+ { WSA884X_EMEM_53, 0x00 },
+ { WSA884X_EMEM_54, 0x00 },
+ { WSA884X_EMEM_55, 0x00 },
+ { WSA884X_EMEM_56, 0x00 },
+ { WSA884X_EMEM_57, 0x00 },
+ { WSA884X_EMEM_58, 0x00 },
+ { WSA884X_EMEM_59, 0x00 },
+ { WSA884X_EMEM_60, 0x00 },
+ { WSA884X_EMEM_61, 0x00 },
+ { WSA884X_EMEM_62, 0x00 },
+ { WSA884X_EMEM_63, 0x00 },
+};
+
+static bool wsa884x_readonly_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WSA884X_DOUT_MSB:
+ case WSA884X_DOUT_LSB:
+ case WSA884X_STATUS:
+ case WSA884X_SPK_TOP_SPARE_TUNE_2:
+ case WSA884X_SPK_TOP_SPARE_TUNE_3:
+ case WSA884X_SPK_TOP_SPARE_TUNE_4:
+ case WSA884X_SPARE_TUNE_5:
+ case WSA884X_SPARE_TUNE_6:
+ case WSA884X_SPARE_TUNE_7:
+ case WSA884X_SPARE_TUNE_8:
+ case WSA884X_SPARE_TUNE_9:
+ case WSA884X_SPARE_TUNE_10:
+ case WSA884X_PA_STATUS0:
+ case WSA884X_PA_STATUS1:
+ case WSA884X_PA_STATUS2:
+ case WSA884X_PA_STATUS3:
+ case WSA884X_PA_STATUS4:
+ case WSA884X_PA_STATUS5:
+ case WSA884X_SPARE_RO_1:
+ case WSA884X_SPARE_RO_2:
+ case WSA884X_SPARE_RO_3:
+ case WSA884X_SPARE_RO_0:
+ case WSA884X_BOOST_SPARE_RO_1:
+ case WSA884X_STATUS_0:
+ case WSA884X_STATUS_1:
+ case WSA884X_CHIP_ID0:
+ case WSA884X_CHIP_ID1:
+ case WSA884X_CHIP_ID2:
+ case WSA884X_CHIP_ID3:
+ case WSA884X_BUS_ID:
+ case WSA884X_PA_FSM_STA0:
+ case WSA884X_PA_FSM_STA1:
+ case WSA884X_PA_FSM_ERR_COND0:
+ case WSA884X_PA_FSM_ERR_COND1:
+ case WSA884X_TEMP_DIN_MSB:
+ case WSA884X_TEMP_DIN_LSB:
+ case WSA884X_TEMP_DOUT_MSB:
+ case WSA884X_TEMP_DOUT_LSB:
+ case WSA884X_VBAT_DIN_MSB:
+ case WSA884X_VBAT_DIN_LSB:
+ case WSA884X_VBAT_DOUT_MSB:
+ case WSA884X_VBAT_DOUT_LSB:
+ case WSA884X_VBAT_CAL_MSB:
+ case WSA884X_VBAT_CAL_LSB:
+ case WSA884X_VPHX_SYS_EN_STATUS:
+ case WSA884X_PIN_STATUS:
+ case WSA884X_SWR_HM_TEST1:
+ case WSA884X_OTP_CTRL1:
+ case WSA884X_OTP_STAT:
+ case WSA884X_WAVG_STA:
+ case WSA884X_INTR_STATUS0:
+ case WSA884X_INTR_STATUS1:
+ case WSA884X_ATE_TEST_MODE:
+ case WSA884X_SPARE_R:
+ return true;
+ }
+ return false;
+}
+
+static bool wsa884x_writeable_register(struct device *dev, unsigned int reg)
+{
+ return !wsa884x_readonly_register(dev, reg);
+}
+
+static bool wsa884x_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WSA884X_ANA_WO_CTL_0:
+ case WSA884X_ANA_WO_CTL_1:
+ return true;
+ }
+ return wsa884x_readonly_register(dev, reg);
+}
+
+static struct regmap_config wsa884x_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .cache_type = REGCACHE_MAPLE,
+ .reg_defaults = wsa884x_defaults,
+ .max_register = WSA884X_MAX_REGISTER,
+ .num_reg_defaults = ARRAY_SIZE(wsa884x_defaults),
+ .volatile_reg = wsa884x_volatile_register,
+ .writeable_reg = wsa884x_writeable_register,
+ .reg_format_endian = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian = REGMAP_ENDIAN_NATIVE,
+ .use_single_read = true,
+};
+
+static const struct reg_sequence wsa884x_reg_init[] = {
+ { WSA884X_BOP2_PROG, FIELD_PREP_CONST(WSA884X_BOP2_PROG_BOP2_VTH_MASK, 0x6) |
+ FIELD_PREP_CONST(WSA884X_BOP2_PROG_BOP2_HYST_MASK, 0x6) },
+ { WSA884X_REF_CTRL, (0xd2 & ~WSA884X_REF_CTRL_BG_RDY_SEL_MASK) |
+ FIELD_PREP_CONST(WSA884X_REF_CTRL_BG_RDY_SEL_MASK, 0x1) },
+ /*
+ * Downstream suggests for batteries different than 1-Stacked (1S):
+ * { WSA884X_TOP_CTRL1, 0xd3 & ~WSA884X_TOP_CTRL1_OCP_LOWVBAT_ITH_EN_MASK },
+ */
+ { WSA884X_STB_CTRL1, (0x42 & ~WSA884X_STB_CTRL1_SLOPE_COMP_CURRENT_MASK) |
+ FIELD_PREP_CONST(WSA884X_STB_CTRL1_SLOPE_COMP_CURRENT_MASK, 0xd) },
+ { WSA884X_CURRENT_LIMIT, (0x54 & ~WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_MASK) |
+ FIELD_PREP_CONST(WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_MASK, 0x9) },
+ { WSA884X_ZX_CTRL1, (0xf0 & ~WSA884X_ZX_CTRL1_ZX_DET_SW_SEL_MASK) |
+ FIELD_PREP_CONST(WSA884X_ZX_CTRL1_ZX_DET_SW_SEL_MASK, 0x3) },
+ { WSA884X_ILIM_CTRL1, (0xe2 & ~WSA884X_ILIM_CTRL1_ILIM_OFFSET_PB_MASK) |
+ FIELD_PREP_CONST(WSA884X_ILIM_CTRL1_ILIM_OFFSET_PB_MASK, 0x3) },
+ { WSA884X_CKWD_CTL_1, FIELD_PREP_CONST(WSA884X_CKWD_CTL_1_VPP_SW_CTL_MASK, 0x0) |
+ FIELD_PREP_CONST(WSA884X_CKWD_CTL_1_CKWD_VCOMP_VREF_SEL_MASK, 0x13) },
+ { WSA884X_PA_FSM_CTL1, (0xfe & ~WSA884X_PA_FSM_CTL1_NOISE_GATE_BLOCK_MASK) |
+ FIELD_PREP_CONST(WSA884X_PA_FSM_CTL1_NOISE_GATE_BLOCK_MASK, 0x4) }, /* == 0xfe */
+ { WSA884X_VBAT_THRM_FLT_CTL, (0x7f & ~WSA884X_VBAT_THRM_FLT_CTL_VBAT_COEF_SEL_MASK) |
+ FIELD_PREP_CONST(WSA884X_VBAT_THRM_FLT_CTL_VBAT_COEF_SEL_MASK, 0x4) },
+ { WSA884X_VBAT_CAL_CTL, FIELD_PREP_CONST(WSA884X_VBAT_CAL_CTL_RESERVE_MASK, 0x2) |
+ FIELD_PREP_CONST(WSA884X_VBAT_CAL_CTL_VBAT_CAL_EN_MASK, 0x1) },
+ { WSA884X_BOP_DEGLITCH_CTL, FIELD_PREP_CONST(WSA884X_BOP_DEGLITCH_CTL_BOP_DEGLITCH_SETTING_MASK, 0x8) |
+ FIELD_PREP_CONST(WSA884X_BOP_DEGLITCH_CTL_BOP_DEGLITCH_EN_MASK, 0x1) },
+ { WSA884X_CDC_SPK_DSM_A2_0, 0x0a },
+ { WSA884X_CDC_SPK_DSM_A2_1, 0x08 },
+ { WSA884X_CDC_SPK_DSM_A3_0, 0xf3 },
+ { WSA884X_CDC_SPK_DSM_A3_1, 0x07 },
+ { WSA884X_CDC_SPK_DSM_A4_0, 0x79 },
+ { WSA884X_CDC_SPK_DSM_A5_0, 0x0b },
+ { WSA884X_CDC_SPK_DSM_A6_0, 0x8a },
+ { WSA884X_CDC_SPK_DSM_A7_0, 0x9b },
+ { WSA884X_CDC_SPK_DSM_C_0, FIELD_PREP_CONST(WSA884X_CDC_SPK_DSM_C_0_COEF_C3_MASK, 0x6) |
+ FIELD_PREP_CONST(WSA884X_CDC_SPK_DSM_C_0_COEF_C2_MASK, 0x8) },
+ { WSA884X_CDC_SPK_DSM_C_2, FIELD_PREP_CONST(WSA884X_CDC_SPK_DSM_C_2_COEF_C7_MASK, 0xf) },
+ { WSA884X_CDC_SPK_DSM_C_3, FIELD_PREP_CONST(WSA884X_CDC_SPK_DSM_C_3_COEF_C7_MASK, 0x20) },
+ { WSA884X_CDC_SPK_DSM_R1, 0x83 },
+ { WSA884X_CDC_SPK_DSM_R2, 0x7f },
+ { WSA884X_CDC_SPK_DSM_R3, 0x9d },
+ { WSA884X_CDC_SPK_DSM_R4, 0x82 },
+ { WSA884X_CDC_SPK_DSM_R5, 0x8b },
+ { WSA884X_CDC_SPK_DSM_R6, 0x9b },
+ { WSA884X_CDC_SPK_DSM_R7, 0x3f },
+ /* Speaker mode by default */
+ { WSA884X_DRE_CTL_0, FIELD_PREP_CONST(WSA884X_DRE_CTL_0_PROG_DELAY_MASK, 0x7) },
+ { WSA884X_CLSH_CTL_0, (0x37 & ~WSA884X_CLSH_CTL_0_DLY_CODE_MASK) |
+ FIELD_PREP_CONST(WSA884X_CLSH_CTL_0_DLY_CODE_MASK, 0x6) },
+ /*
+ * WSA884X_CLSH_VTH values for speaker mode with G_21_DB system gain,
+ * battery 1S and rload 8 Ohms.
+ */
+ { WSA884X_CLSH_VTH1, WSA884X_VTH_TO_REG(863), },
+ { WSA884X_CLSH_VTH2, WSA884X_VTH_TO_REG(918), },
+ { WSA884X_CLSH_VTH3, WSA884X_VTH_TO_REG(980), },
+ { WSA884X_CLSH_VTH4, WSA884X_VTH_TO_REG(1043), },
+ { WSA884X_CLSH_VTH5, WSA884X_VTH_TO_REG(1098), },
+ { WSA884X_CLSH_VTH6, WSA884X_VTH_TO_REG(1137), },
+ { WSA884X_CLSH_VTH7, WSA884X_VTH_TO_REG(1184), },
+ { WSA884X_CLSH_VTH8, WSA884X_VTH_TO_REG(1239), },
+ { WSA884X_CLSH_VTH9, WSA884X_VTH_TO_REG(1278), },
+ { WSA884X_CLSH_VTH10, WSA884X_VTH_TO_REG(1380), },
+ { WSA884X_CLSH_VTH11, WSA884X_VTH_TO_REG(1482), },
+ { WSA884X_CLSH_VTH12, WSA884X_VTH_TO_REG(1584), },
+ { WSA884X_CLSH_VTH13, WSA884X_VTH_TO_REG(1663), },
+ { WSA884X_CLSH_VTH14, WSA884X_VTH_TO_REG(1780), },
+ { WSA884X_CLSH_VTH15, WSA884X_VTH_TO_REG(2000), },
+ { WSA884X_ANA_WO_CTL_1, 0x00 },
+ { WSA884X_OTP_REG_38, 0x00 },
+ { WSA884X_OTP_REG_40, FIELD_PREP_CONST(WSA884X_OTP_REG_40_ISENSE_RESCAL_MASK, 0x8) },
+};
+
+static void wsa884x_set_gain_parameters(struct wsa884x_priv *wsa884x)
+{
+ struct regmap *regmap = wsa884x->regmap;
+ unsigned int min_gain, igain, vgain, comp_offset;
+
+ /*
+ * Downstream sets gain parameters customized per boards per use-case.
+ * Choose here some sane values matching knowon users, like QRD8550
+ * board:.
+ *
+ * Values match here downstream:
+ * For WSA884X_RECEIVER - G_7P5_DB system gain
+ * For WSA884X_SPEAKER - G_21_DB system gain
+ */
+ if (wsa884x->dev_mode == WSA884X_RECEIVER) {
+ comp_offset = COMP_OFFSET4;
+ min_gain = G_M6_DB;
+ igain = ISENSE_18_DB;
+ vgain = VSENSE_M12_DB;
+ } else {
+ /* WSA884X_SPEAKER */
+ comp_offset = COMP_OFFSET0;
+ min_gain = G_0_DB;
+ igain = ISENSE_12_DB;
+ vgain = VSENSE_M24_DB;
+ }
+
+ regmap_update_bits(regmap, WSA884X_ISENSE2,
+ WSA884X_ISENSE2_ISENSE_GAIN_CTL_MASK,
+ FIELD_PREP(WSA884X_ISENSE2_ISENSE_GAIN_CTL_MASK, igain));
+ regmap_update_bits(regmap, WSA884X_VSENSE1,
+ WSA884X_VSENSE1_GAIN_VSENSE_FE_MASK,
+ FIELD_PREP(WSA884X_VSENSE1_GAIN_VSENSE_FE_MASK, vgain));
+ regmap_update_bits(regmap, WSA884X_GAIN_RAMPING_MIN,
+ WSA884X_GAIN_RAMPING_MIN_MIN_GAIN_MASK,
+ FIELD_PREP(WSA884X_GAIN_RAMPING_MIN_MIN_GAIN_MASK, min_gain));
+
+ if (wsa884x->port_enable[WSA884X_PORT_COMP]) {
+ regmap_update_bits(regmap, WSA884X_DRE_CTL_0,
+ WSA884X_DRE_CTL_0_OFFSET_MASK,
+ FIELD_PREP(WSA884X_DRE_CTL_0_OFFSET_MASK, comp_offset));
+
+ regmap_update_bits(regmap, WSA884X_DRE_CTL_1,
+ WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK,
+ FIELD_PREP(WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK, 0x0));
+ } else {
+ regmap_update_bits(regmap, WSA884X_DRE_CTL_1,
+ WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK,
+ FIELD_PREP(WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK, 0x1));
+ }
+}
+
+static void wsa884x_init(struct wsa884x_priv *wsa884x)
+{
+ unsigned int wo_ctl_0;
+ unsigned int variant = 0;
+
+ if (!regmap_read(wsa884x->regmap, WSA884X_OTP_REG_0, &variant))
+ wsa884x->variant = variant & WSA884X_OTP_REG_0_ID_MASK;
+
+ regmap_multi_reg_write(wsa884x->regmap, wsa884x_reg_init,
+ ARRAY_SIZE(wsa884x_reg_init));
+
+ wo_ctl_0 = 0xc;
+ wo_ctl_0 |= FIELD_PREP(WSA884X_ANA_WO_CTL_0_DAC_CM_CLAMP_EN_MASK,
+ WSA884X_ANA_WO_CTL_0_DAC_CM_CLAMP_EN_MODE_SPEAKER);
+ /* Assume that compander is enabled by default unless it is haptics sku */
+ if (wsa884x->variant == WSA884X_OTP_ID_WSA8845H)
+ wo_ctl_0 |= FIELD_PREP(WSA884X_ANA_WO_CTL_0_PA_AUX_GAIN_MASK,
+ WSA884X_ANA_WO_CTL_0_PA_AUX_18_DB);
+ else
+ wo_ctl_0 |= FIELD_PREP(WSA884X_ANA_WO_CTL_0_PA_AUX_GAIN_MASK,
+ WSA884X_ANA_WO_CTL_0_PA_AUX_0_DB);
+ regmap_write(wsa884x->regmap, WSA884X_ANA_WO_CTL_0, wo_ctl_0);
+
+ wsa884x_set_gain_parameters(wsa884x);
+
+ wsa884x->hw_init = false;
+}
+
+static int wsa884x_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct wsa884x_priv *wsa884x = dev_get_drvdata(&slave->dev);
+ int ret;
+
+ if (status == SDW_SLAVE_UNATTACHED) {
+ wsa884x->hw_init = false;
+ regcache_cache_only(wsa884x->regmap, true);
+ regcache_mark_dirty(wsa884x->regmap);
+ return 0;
+ }
+
+ if (wsa884x->hw_init || status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ regcache_cache_only(wsa884x->regmap, false);
+ ret = regcache_sync(wsa884x->regmap);
+ if (ret < 0) {
+ dev_err(&slave->dev, "Cannot sync regmap cache\n");
+ return ret;
+ }
+
+ wsa884x_init(wsa884x);
+
+ return 0;
+}
+
+static int wsa884x_port_prep(struct sdw_slave *slave,
+ struct sdw_prepare_ch *prepare_ch,
+ enum sdw_port_prep_ops state)
+{
+ struct wsa884x_priv *wsa884x = dev_get_drvdata(&slave->dev);
+
+ if (state == SDW_OPS_PORT_POST_PREP)
+ wsa884x->port_prepared[prepare_ch->num - 1] = true;
+ else
+ wsa884x->port_prepared[prepare_ch->num - 1] = false;
+
+ return 0;
+}
+
+static const struct sdw_slave_ops wsa884x_slave_ops = {
+ .update_status = wsa884x_update_status,
+ .port_prep = wsa884x_port_prep,
+};
+
+static int wsa884x_dev_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct wsa884x_priv *wsa884x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.enumerated.item[0] = wsa884x->dev_mode;
+
+ return 0;
+}
+
+static int wsa884x_dev_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct wsa884x_priv *wsa884x = snd_soc_component_get_drvdata(component);
+
+ if (wsa884x->dev_mode == ucontrol->value.enumerated.item[0])
+ return 0;
+
+ wsa884x->dev_mode = ucontrol->value.enumerated.item[0];
+
+ return 1;
+}
+
+static int wsa884x_get_swr_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct wsa884x_priv *wsa884x = snd_soc_component_get_drvdata(comp);
+ struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+ int portidx = mixer->reg;
+
+ ucontrol->value.integer.value[0] = wsa884x->port_enable[portidx];
+
+ return 0;
+}
+
+static int wsa884x_set_swr_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct wsa884x_priv *wsa884x = snd_soc_component_get_drvdata(comp);
+ struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+ int portidx = mixer->reg;
+
+ if (ucontrol->value.integer.value[0]) {
+ if (wsa884x->port_enable[portidx])
+ return 0;
+
+ wsa884x->port_enable[portidx] = true;
+ } else {
+ if (!wsa884x->port_enable[portidx])
+ return 0;
+
+ wsa884x->port_enable[portidx] = false;
+ }
+
+ return 1;
+}
+
+static int wsa884x_codec_probe(struct snd_soc_component *comp)
+{
+ struct wsa884x_priv *wsa884x = snd_soc_component_get_drvdata(comp);
+
+ snd_soc_component_init_regmap(comp, wsa884x->regmap);
+
+ return 0;
+}
+
+static void wsa884x_spkr_post_pmu(struct snd_soc_component *component,
+ struct wsa884x_priv *wsa884x)
+{
+ unsigned int curr_limit, curr_ovrd_en;
+
+ wsa884x_set_gain_parameters(wsa884x);
+ if (wsa884x->dev_mode == WSA884X_RECEIVER) {
+ snd_soc_component_write_field(component, WSA884X_DRE_CTL_0,
+ WSA884X_DRE_CTL_0_PROG_DELAY_MASK, 0x3);
+ snd_soc_component_write_field(component, WSA884X_CDC_PATH_MODE,
+ WSA884X_CDC_PATH_MODE_RXD_MODE_MASK,
+ 0x1);
+ snd_soc_component_write_field(component, WSA884X_PWM_CLK_CTL,
+ WSA884X_PWM_CLK_CTL_PWM_CLK_FREQ_SEL_MASK,
+ 0x1);
+ } else {
+ /* WSA884X_SPEAKER */
+ snd_soc_component_write_field(component, WSA884X_DRE_CTL_0,
+ WSA884X_DRE_CTL_0_PROG_DELAY_MASK, 0xf);
+ }
+
+ if (wsa884x->port_enable[WSA884X_PORT_PBR]) {
+ curr_ovrd_en = 0x0;
+ curr_limit = 0x15;
+ } else {
+ curr_ovrd_en = 0x1;
+ if (wsa884x->dev_mode == WSA884X_RECEIVER)
+ curr_limit = 0x9;
+ else
+ curr_limit = 0x15;
+ }
+ snd_soc_component_write_field(component, WSA884X_CURRENT_LIMIT,
+ WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_OVRD_EN_MASK,
+ curr_ovrd_en);
+ snd_soc_component_write_field(component, WSA884X_CURRENT_LIMIT,
+ WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_MASK,
+ curr_limit);
+}
+
+static int wsa884x_spkr_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 wsa884x_priv *wsa884x = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ wsa884x_spkr_post_pmu(component, wsa884x);
+
+ snd_soc_component_write_field(component, WSA884X_PDM_WD_CTL,
+ WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK,
+ 0x1);
+ snd_soc_component_write_field(component, WSA884X_PA_FSM_EN,
+ WSA884X_PA_FSM_EN_GLOBAL_PA_EN_MASK,
+ 0x1);
+
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_component_write_field(component, WSA884X_PA_FSM_EN,
+ WSA884X_PA_FSM_EN_GLOBAL_PA_EN_MASK,
+ 0x0);
+ snd_soc_component_write_field(component, WSA884X_PDM_WD_CTL,
+ WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK,
+ 0x0);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget wsa884x_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("IN"),
+ SND_SOC_DAPM_SPK("SPKR", wsa884x_spkr_event),
+};
+
+static const DECLARE_TLV_DB_SCALE(pa_gain, -900, 150, -900);
+
+static const struct snd_kcontrol_new wsa884x_snd_controls[] = {
+ SOC_SINGLE_RANGE_TLV("PA Volume", WSA884X_DRE_CTL_1,
+ WSA884X_DRE_CTL_1_CSR_GAIN_SHIFT,
+ 0x0, 0x1f, 1, pa_gain),
+ SOC_ENUM_EXT("WSA MODE", wsa884x_dev_mode_enum,
+ wsa884x_dev_mode_get, wsa884x_dev_mode_put),
+ SOC_SINGLE_EXT("DAC Switch", WSA884X_PORT_DAC, 0, 1, 0,
+ wsa884x_get_swr_port, wsa884x_set_swr_port),
+ SOC_SINGLE_EXT("COMP Switch", WSA884X_PORT_COMP, 0, 1, 0,
+ wsa884x_get_swr_port, wsa884x_set_swr_port),
+ SOC_SINGLE_EXT("BOOST Switch", WSA884X_PORT_BOOST, 0, 1, 0,
+ wsa884x_get_swr_port, wsa884x_set_swr_port),
+ SOC_SINGLE_EXT("PBR Switch", WSA884X_PORT_PBR, 0, 1, 0,
+ wsa884x_get_swr_port, wsa884x_set_swr_port),
+ SOC_SINGLE_EXT("VISENSE Switch", WSA884X_PORT_VISENSE, 0, 1, 0,
+ wsa884x_get_swr_port, wsa884x_set_swr_port),
+ SOC_SINGLE_EXT("CPS Switch", WSA884X_PORT_CPS, 0, 1, 0,
+ wsa884x_get_swr_port, wsa884x_set_swr_port),
+};
+
+static const struct snd_soc_dapm_route wsa884x_audio_map[] = {
+ {"SPKR", NULL, "IN"},
+};
+
+static const struct snd_soc_component_driver wsa884x_component_drv = {
+ .name = "WSA884x",
+ .probe = wsa884x_codec_probe,
+ .controls = wsa884x_snd_controls,
+ .num_controls = ARRAY_SIZE(wsa884x_snd_controls),
+ .dapm_widgets = wsa884x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wsa884x_dapm_widgets),
+ .dapm_routes = wsa884x_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(wsa884x_audio_map),
+};
+
+static int wsa884x_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct wsa884x_priv *wsa884x = dev_get_drvdata(dai->dev);
+ int i;
+
+ wsa884x->active_ports = 0;
+ for (i = 0; i < WSA884X_MAX_SWR_PORTS; i++) {
+ if (!wsa884x->port_enable[i])
+ continue;
+
+ wsa884x->port_config[wsa884x->active_ports] = wsa884x_pconfig[i];
+ wsa884x->active_ports++;
+ }
+
+ wsa884x->sconfig.frame_rate = params_rate(params);
+
+ return sdw_stream_add_slave(wsa884x->slave, &wsa884x->sconfig,
+ wsa884x->port_config, wsa884x->active_ports,
+ wsa884x->sruntime);
+}
+
+static int wsa884x_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct wsa884x_priv *wsa884x = dev_get_drvdata(dai->dev);
+
+ sdw_stream_remove_slave(wsa884x->slave, wsa884x->sruntime);
+
+ return 0;
+}
+
+static int wsa884x_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_component *component = dai->component;
+
+ if (mute) {
+ snd_soc_component_write_field(component, WSA884X_DRE_CTL_1,
+ WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK,
+ 0x0);
+ snd_soc_component_write_field(component, WSA884X_PA_FSM_EN,
+ WSA884X_PA_FSM_EN_GLOBAL_PA_EN_MASK,
+ 0x0);
+
+ } else {
+ snd_soc_component_write_field(component, WSA884X_DRE_CTL_1,
+ WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK,
+ 0x1);
+ snd_soc_component_write_field(component, WSA884X_PA_FSM_EN,
+ WSA884X_PA_FSM_EN_GLOBAL_PA_EN_MASK,
+ 0x1);
+ }
+
+ return 0;
+}
+
+static int wsa884x_set_stream(struct snd_soc_dai *dai,
+ void *stream, int direction)
+{
+ struct wsa884x_priv *wsa884x = dev_get_drvdata(dai->dev);
+
+ wsa884x->sruntime = stream;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops wsa884x_dai_ops = {
+ .hw_params = wsa884x_hw_params,
+ .hw_free = wsa884x_hw_free,
+ .mute_stream = wsa884x_mute_stream,
+ .set_stream = wsa884x_set_stream,
+};
+
+static struct snd_soc_dai_driver wsa884x_dais[] = {
+ {
+ .name = "SPKR",
+ .playback = {
+ .stream_name = "SPKR Playback",
+ .rates = WSA884X_RATES | WSA884X_FRAC_RATES,
+ .formats = WSA884X_FORMATS,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ .channels_min = 1,
+ .channels_max = 1,
+ },
+ .ops = &wsa884x_dai_ops,
+ },
+};
+
+static void wsa884x_gpio_powerdown(void *data)
+{
+ gpiod_direction_output(data, 1);
+}
+
+static void wsa884x_regulator_disable(void *data)
+{
+ regulator_bulk_disable(WSA884X_SUPPLIES_NUM, data);
+}
+
+static int wsa884x_probe(struct sdw_slave *pdev,
+ const struct sdw_device_id *id)
+{
+ struct device *dev = &pdev->dev;
+ struct wsa884x_priv *wsa884x;
+ unsigned int i;
+ int ret;
+
+ wsa884x = devm_kzalloc(dev, sizeof(*wsa884x), GFP_KERNEL);
+ if (!wsa884x)
+ return -ENOMEM;
+
+ for (i = 0; i < WSA884X_SUPPLIES_NUM; i++)
+ wsa884x->supplies[i].supply = wsa884x_supply_name[i];
+
+ ret = devm_regulator_bulk_get(dev, WSA884X_SUPPLIES_NUM,
+ wsa884x->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get regulators\n");
+
+ ret = regulator_bulk_enable(WSA884X_SUPPLIES_NUM, wsa884x->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable regulators\n");
+
+ ret = devm_add_action_or_reset(dev, wsa884x_regulator_disable,
+ wsa884x->supplies);
+ if (ret)
+ return ret;
+
+ wsa884x->sd_n = devm_gpiod_get_optional(dev, "powerdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(wsa884x->sd_n))
+ return dev_err_probe(dev, PTR_ERR(wsa884x->sd_n),
+ "Shutdown Control GPIO not found\n");
+
+ dev_set_drvdata(dev, wsa884x);
+ wsa884x->slave = pdev;
+ wsa884x->dev = dev;
+ wsa884x->dev_mode = WSA884X_SPEAKER;
+ wsa884x->sconfig.ch_count = 1;
+ wsa884x->sconfig.bps = 1;
+ wsa884x->sconfig.direction = SDW_DATA_DIR_RX;
+ wsa884x->sconfig.type = SDW_STREAM_PDM;
+
+ pdev->prop.sink_ports = GENMASK(WSA884X_MAX_SWR_PORTS, 0);
+ pdev->prop.simple_clk_stop_capable = true;
+ pdev->prop.sink_dpn_prop = wsa884x_sink_dpn_prop;
+ pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+
+ /* Bring out of reset */
+ gpiod_direction_output(wsa884x->sd_n, 0);
+ ret = devm_add_action_or_reset(dev, wsa884x_gpio_powerdown, wsa884x->sd_n);
+ if (ret)
+ return ret;
+
+ wsa884x->regmap = devm_regmap_init_sdw(pdev, &wsa884x_regmap_config);
+ if (IS_ERR(wsa884x->regmap))
+ return dev_err_probe(dev, PTR_ERR(wsa884x->regmap),
+ "regmap_init failed\n");
+
+ /* Start in cache-only until device is enumerated */
+ regcache_cache_only(wsa884x->regmap, true);
+ wsa884x->hw_init = true;
+
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return devm_snd_soc_register_component(dev,
+ &wsa884x_component_drv,
+ wsa884x_dais,
+ ARRAY_SIZE(wsa884x_dais));
+}
+
+static int __maybe_unused wsa884x_runtime_suspend(struct device *dev)
+{
+ struct regmap *regmap = dev_get_regmap(dev, NULL);
+
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+
+ return 0;
+}
+
+static int __maybe_unused wsa884x_runtime_resume(struct device *dev)
+{
+ struct regmap *regmap = dev_get_regmap(dev, NULL);
+
+ regcache_cache_only(regmap, false);
+ regcache_sync(regmap);
+
+ return 0;
+}
+
+static const struct dev_pm_ops wsa884x_pm_ops = {
+ SET_RUNTIME_PM_OPS(wsa884x_runtime_suspend, wsa884x_runtime_resume, NULL)
+};
+
+static const struct sdw_device_id wsa884x_swr_id[] = {
+ SDW_SLAVE_ENTRY(0x0217, 0x204, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, wsa884x_swr_id);
+
+static struct sdw_driver wsa884x_codec_driver = {
+ .driver = {
+ .name = "wsa884x-codec",
+ .pm = &wsa884x_pm_ops,
+ },
+ .probe = wsa884x_probe,
+ .ops = &wsa884x_slave_ops,
+ .id_table = wsa884x_swr_id,
+};
+module_sdw_driver(wsa884x_codec_driver);
+
+MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>");
+MODULE_DESCRIPTION("WSA884x codec driver");
+MODULE_LICENSE("GPL");