aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/Kconfig69
-rw-r--r--sound/soc/codecs/Makefile20
-rw-r--r--sound/soc/codecs/adau1372-i2c.c1
-rw-r--r--sound/soc/codecs/adau1372-spi.c1
-rw-r--r--sound/soc/codecs/adau1372.c8
-rw-r--r--sound/soc/codecs/adau1372.h1
-rw-r--r--sound/soc/codecs/adau1373.c200
-rw-r--r--sound/soc/codecs/aw88081.c1087
-rw-r--r--sound/soc/codecs/aw88081.h286
-rw-r--r--sound/soc/codecs/aw88395/aw88395_device.c2
-rw-r--r--sound/soc/codecs/aw88395/aw88395_lib.c2
-rw-r--r--sound/soc/codecs/aw88399.c2
-rw-r--r--sound/soc/codecs/cpcap.c2
-rw-r--r--sound/soc/codecs/cs-amp-lib-test.c2
-rw-r--r--sound/soc/codecs/cs-amp-lib.c8
-rw-r--r--sound/soc/codecs/cs35l45-i2c.c2
-rw-r--r--sound/soc/codecs/cs35l45-spi.c2
-rw-r--r--sound/soc/codecs/cs35l45-tables.c8
-rw-r--r--sound/soc/codecs/cs35l45.c4
-rw-r--r--sound/soc/codecs/cs35l56-i2c.c4
-rw-r--r--sound/soc/codecs/cs35l56-sdw.c4
-rw-r--r--sound/soc/codecs/cs35l56-shared.c52
-rw-r--r--sound/soc/codecs/cs35l56-spi.c4
-rw-r--r--sound/soc/codecs/cs35l56.c10
-rw-r--r--sound/soc/codecs/cs42l42-i2c.c2
-rw-r--r--sound/soc/codecs/cs42l42-sdw.c2
-rw-r--r--sound/soc/codecs/cs42l42.c32
-rw-r--r--sound/soc/codecs/cs42l43-sdw.c6
-rw-r--r--sound/soc/codecs/cs42l43.c44
-rw-r--r--sound/soc/codecs/cs42l83-i2c.c2
-rw-r--r--sound/soc/codecs/cs42l84.c1111
-rw-r--r--sound/soc/codecs/cs42l84.h210
-rw-r--r--sound/soc/codecs/cs530x-i2c.c2
-rw-r--r--sound/soc/codecs/cs530x.c4
-rw-r--r--sound/soc/codecs/da7213.c27
-rw-r--r--sound/soc/codecs/da7213.h1
-rw-r--r--sound/soc/codecs/da7219.c9
-rw-r--r--sound/soc/codecs/es8323.c792
-rw-r--r--sound/soc/codecs/es8323.h78
-rw-r--r--sound/soc/codecs/es8326.c20
-rw-r--r--sound/soc/codecs/hdmi-codec.c140
-rw-r--r--sound/soc/codecs/max9768.c11
-rw-r--r--sound/soc/codecs/max98088.c86
-rw-r--r--sound/soc/codecs/nau8821.c9
-rw-r--r--sound/soc/codecs/ntp8835.c480
-rw-r--r--sound/soc/codecs/ntp8918.c397
-rw-r--r--sound/soc/codecs/ntpfw.c137
-rw-r--r--sound/soc/codecs/ntpfw.h23
-rw-r--r--sound/soc/codecs/pcm186x.c4
-rw-r--r--sound/soc/codecs/pcm5102a.c2
-rw-r--r--sound/soc/codecs/rt-sdw-common.c238
-rw-r--r--sound/soc/codecs/rt-sdw-common.h66
-rw-r--r--sound/soc/codecs/rt1320-sdw.c3668
-rw-r--r--sound/soc/codecs/rt1320-sdw.h6
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.c1
-rw-r--r--sound/soc/codecs/rt712-sdca.c38
-rw-r--r--sound/soc/codecs/rt712-sdca.h1
-rw-r--r--sound/soc/codecs/rt721-sdca-sdw.c546
-rw-r--r--sound/soc/codecs/rt721-sdca-sdw.h150
-rw-r--r--sound/soc/codecs/rt721-sdca.c1545
-rw-r--r--sound/soc/codecs/rt721-sdca.h269
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.c12
-rw-r--r--sound/soc/codecs/rt722-sdca.c22
-rw-r--r--sound/soc/codecs/simple-mux.c39
-rw-r--r--sound/soc/codecs/sma1307.c2049
-rw-r--r--sound/soc/codecs/sma1307.h444
-rw-r--r--sound/soc/codecs/spdif_receiver.c2
-rw-r--r--sound/soc/codecs/spdif_transmitter.c2
-rw-r--r--sound/soc/codecs/tas2781-fmwlib.c20
-rw-r--r--sound/soc/codecs/tas2781-i2c.c39
-rw-r--r--sound/soc/codecs/tas5805m.c2
-rw-r--r--sound/soc/codecs/tas6424.c2
-rw-r--r--sound/soc/codecs/tlv320adc3xxx.c2
-rw-r--r--sound/soc/codecs/twl4030.c12
-rw-r--r--sound/soc/codecs/uda1342.c347
-rw-r--r--sound/soc/codecs/uda1342.h78
-rw-r--r--sound/soc/codecs/wcd9335.c1
-rw-r--r--sound/soc/codecs/wcd937x.c1
-rw-r--r--sound/soc/codecs/wm_adsp.c2
79 files changed, 11370 insertions, 3646 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 7092842480ef..0f2df7c91e18 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -57,6 +57,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_AW8738
imply SND_SOC_AW87390
imply SND_SOC_AW88395
+ imply SND_SOC_AW88081
imply SND_SOC_AW88261
imply SND_SOC_AW88399
imply SND_SOC_BT_SCO
@@ -85,6 +86,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_CS42L52
imply SND_SOC_CS42L56
imply SND_SOC_CS42L73
+ imply SND_SOC_CS42L84
imply SND_SOC_CS4234
imply SND_SOC_CS4265
imply SND_SOC_CS4270
@@ -112,6 +114,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_DA9055
imply SND_SOC_DMIC
imply SND_SOC_ES8316
+ imply SND_SOC_ES8323
imply SND_SOC_ES8326
imply SND_SOC_ES8328_SPI
imply SND_SOC_ES8328_I2C
@@ -222,6 +225,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_RT721_SDCA_SDW
imply SND_SOC_RT722_SDCA_SDW
imply SND_SOC_RT1308_SDW
imply SND_SOC_RT1316_SDW
@@ -236,6 +240,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_SIMPLE_AMPLIFIER
imply SND_SOC_SIMPLE_MUX
imply SND_SOC_SMA1303
+ imply SND_SOC_SMA1307
imply SND_SOC_SPDIF
imply SND_SOC_SRC4XXX_I2C
imply SND_SOC_SSM2305
@@ -281,6 +286,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_TWL4030
imply SND_SOC_TWL6040
imply SND_SOC_UDA1334
+ imply SND_SOC_UDA1342
imply SND_SOC_UDA1380
imply SND_SOC_WCD9335
imply SND_SOC_WCD934X
@@ -461,7 +467,7 @@ config SND_SOC_ADAU1372_SPI
select REGMAP_SPI
config SND_SOC_ADAU1373
- tristate
+ tristate "Analog Devices ADAU1373 CODEC"
depends on I2C
select SND_SOC_ADAU_UTILS
@@ -685,6 +691,17 @@ config SND_SOC_AW88261
boost converter can be adjusted smartly according to
the input amplitude.
+config SND_SOC_AW88081
+ tristate "Soc Audio for awinic aw88081"
+ depends on I2C
+ select REGMAP_I2C
+ select SND_SOC_AW88395_LIB
+ help
+ This option enables support for aw88081 Smart PA.
+ The awinic AW88081 is an I2S/TDM input, high efficiency
+ digital Smart K audio amplifier. Due to its 9uV noise
+ floor and ultra-low distortion, clean listening is guaranteed.
+
config SND_SOC_AW87390
tristate "Soc Audio for awinic aw87390"
depends on I2C
@@ -926,6 +943,12 @@ config SND_SOC_CS42L83
select REGMAP_I2C
select SND_SOC_CS42L42_CORE
+config SND_SOC_CS42L84
+ tristate "Cirrus Logic CS42L84 CODEC"
+ depends on I2C
+ select REGMAP
+ select REGMAP_I2C
+
config SND_SOC_CS4234
tristate "Cirrus Logic CS4234 CODEC"
depends on I2C
@@ -1143,6 +1166,10 @@ config SND_SOC_ES8316
tristate "Everest Semi ES8316 CODEC"
depends on I2C
+config SND_SOC_ES8323
+ tristate "Everest Semi ES8323 CODEC"
+ depends on I2C
+
config SND_SOC_ES8326
tristate "Everest Semi ES8326 CODEC"
depends on I2C
@@ -1545,6 +1572,11 @@ config SND_SOC_RL6231
default m if SND_SOC_RT1305=m
default m if SND_SOC_RT1308=m
+config SND_SOC_RT_SDW_COMMON
+ tristate
+ default y if SND_SOC_RT721_SDCA_SDW=y
+ default m if SND_SOC_RT721_SDCA_SDW=m
+
config SND_SOC_RL6347A
tristate
default y if SND_SOC_RT274=y
@@ -1743,6 +1775,12 @@ config SND_SOC_RT712_SDCA_DMIC_SDW
select REGMAP_SOUNDWIRE
select REGMAP_SOUNDWIRE_MBQ
+config SND_SOC_RT721_SDCA_SDW
+ tristate "Realtek RT721 SDCA Codec - SDW"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ select REGMAP_SOUNDWIRE_MBQ
+
config SND_SOC_RT722_SDCA_SDW
tristate "Realtek RT722 SDCA Codec - SDW"
depends on SOUNDWIRE
@@ -1836,6 +1874,15 @@ config SND_SOC_SMA1303
help
Enable support for Iron Device SMA1303 Boosted Class-D amplifier
+config SND_SOC_SMA1307
+ tristate "Iron Device SMA1307 Audio Amplifier"
+ depends on I2C
+ help
+ Enable support for Iron Device SMA1307 boosted digital speaker
+ amplifier with feedback-loop.
+ If you are using a system with an SMA1307 amplifier connected
+ via I2C, enable this option.
+
config SND_SOC_SPDIF
tristate "S/PDIF CODEC"
@@ -2114,6 +2161,13 @@ config SND_SOC_UDA1334
and has basic features such as de-emphasis (at 44.1 kHz sampling
rate) and mute.
+config SND_SOC_UDA1342
+ tristate "NXP UDA1342 CODEC"
+ depends on I2C
+ help
+ The UDA1342 is an NXP audio codec, support 2x Stereo audio ADC (4x PGA
+ mic inputs), stereo audio DAC, with basic audio processing.
+
config SND_SOC_UDA1380
tristate
depends on I2C
@@ -2565,6 +2619,19 @@ config SND_SOC_NAU8825
tristate
depends on I2C
+config SND_SOC_NTPFW
+ tristate
+
+config SND_SOC_NTP8918
+ select SND_SOC_NTPFW
+ tristate "NeoFidelity NTP8918 amplifier"
+ depends on I2C
+
+config SND_SOC_NTP8835
+ select SND_SOC_NTPFW
+ tristate "NeoFidelity NTP8835 and NTP8835C amplifiers"
+ depends on I2C
+
config SND_SOC_TPA6130A2
tristate "Texas Instruments TPA6130A2 headphone amplifier"
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 54cbc3feae32..f37e82ddb7a1 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -49,6 +49,7 @@ snd-soc-arizona-y := arizona.o arizona-jack.o
snd-soc-audio-iio-aux-y := audio-iio-aux.o
snd-soc-aw8738-y := aw8738.o
snd-soc-aw87390-y := aw87390.o
+snd-soc-aw88081-y := aw88081.o
snd-soc-aw88395-lib-y := aw88395/aw88395_lib.o
snd-soc-aw88395-y := aw88395/aw88395.o \
aw88395/aw88395_device.o
@@ -91,6 +92,7 @@ snd-soc-cs42l52-y := cs42l52.o
snd-soc-cs42l56-y := cs42l56.o
snd-soc-cs42l73-y := cs42l73.o
snd-soc-cs42l83-i2c-y := cs42l83-i2c.o
+snd-soc-cs42l84-objs := cs42l84.o
snd-soc-cs4234-y := cs4234.o
snd-soc-cs4265-y := cs4265.o
snd-soc-cs4270-y := cs4270.o
@@ -125,6 +127,7 @@ snd-soc-es7241-y := es7241.o
snd-soc-es83xx-dsm-common-y := es83xx-dsm-common.o
snd-soc-es8311-y := es8311.o
snd-soc-es8316-y := es8316.o
+snd-soc-es8323-y := es8323.o
snd-soc-es8326-y := es8326.o
snd-soc-es8328-y := es8328.o
snd-soc-es8328-i2c-y := es8328-i2c.o
@@ -189,6 +192,9 @@ snd-soc-nau8821-y := nau8821.o
snd-soc-nau8822-y := nau8822.o
snd-soc-nau8824-y := nau8824.o
snd-soc-nau8825-y := nau8825.o
+snd-soc-ntp8835-y := ntp8835.o
+snd-soc-ntp8918-y := ntp8918.o
+snd-soc-ntpfw-y := ntpfw.o
snd-soc-hdmi-codec-y := hdmi-codec.o
snd-soc-pcm1681-y := pcm1681.o
snd-soc-pcm1789-codec-y := pcm1789.o
@@ -216,6 +222,7 @@ snd-soc-rk3308-y := rk3308_codec.o
snd-soc-rk3328-y := rk3328_codec.o
snd-soc-rk817-y := rk817_codec.o
snd-soc-rl6231-y := rl6231.o
+snd-soc-rt-sdw-common-y := rt-sdw-common.o
snd-soc-rl6347a-y := rl6347a.o
snd-soc-rt1011-y := rt1011.o
snd-soc-rt1015-y := rt1015.o
@@ -259,6 +266,7 @@ snd-soc-rt712-sdca-y := rt712-sdca.o rt712-sdca-sdw.o
snd-soc-rt712-sdca-dmic-y := rt712-sdca-dmic.o
snd-soc-rt715-y := rt715.o rt715-sdw.o
snd-soc-rt715-sdca-y := rt715-sdca.o rt715-sdca-sdw.o
+snd-soc-rt721-sdca-y := rt721-sdca.o rt721-sdca-sdw.o
snd-soc-rt722-sdca-y := rt722-sdca.o rt722-sdca-sdw.o
snd-soc-rt9120-y := rt9120.o
snd-soc-rtq9128-y := rtq9128.o
@@ -271,6 +279,7 @@ snd-soc-sigmadsp-i2c-y := sigmadsp-i2c.o
snd-soc-sigmadsp-regmap-y := sigmadsp-regmap.o
snd-soc-si476x-y := si476x.o
snd-soc-sma1303-y := sma1303.o
+snd-soc-sma1307-y := sma1307.o
snd-soc-spdif-tx-y := spdif_transmitter.o
snd-soc-spdif-rx-y := spdif_receiver.o
snd-soc-src4xxx-y := src4xxx.o
@@ -319,6 +328,7 @@ snd-soc-ts3a227e-y := ts3a227e.o
snd-soc-twl4030-y := twl4030.o
snd-soc-twl6040-y := twl6040.o
snd-soc-uda1334-y := uda1334.o
+snd-soc-uda1342-y := uda1342.o
snd-soc-uda1380-y := uda1380.o
snd-soc-wcd-classh-y := wcd-clsh-v2.o
snd-soc-wcd-mbhc-y := wcd-mbhc-v2.o
@@ -457,6 +467,7 @@ obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o
obj-$(CONFIG_SND_SOC_AUDIO_IIO_AUX) += snd-soc-audio-iio-aux.o
obj-$(CONFIG_SND_SOC_AW8738) += snd-soc-aw8738.o
obj-$(CONFIG_SND_SOC_AW87390) += snd-soc-aw87390.o
+obj-$(CONFIG_SND_SOC_AW88081) += snd-soc-aw88081.o
obj-$(CONFIG_SND_SOC_AW88395_LIB) += snd-soc-aw88395-lib.o
obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o
obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o
@@ -498,6 +509,7 @@ obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o
obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o
obj-$(CONFIG_SND_SOC_CS42L83) += snd-soc-cs42l83-i2c.o
+obj-$(CONFIG_SND_SOC_CS42L84) += snd-soc-cs42l84.o
obj-$(CONFIG_SND_SOC_CS4234) += snd-soc-cs4234.o
obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
@@ -532,6 +544,7 @@ obj-$(CONFIG_SND_SOC_ES7241) += snd-soc-es7241.o
obj-$(CONFIG_SND_SOC_ES83XX_DSM_COMMON) += snd-soc-es83xx-dsm-common.o
obj-$(CONFIG_SND_SOC_ES8311) += snd-soc-es8311.o
obj-$(CONFIG_SND_SOC_ES8316) += snd-soc-es8316.o
+obj-$(CONFIG_SND_SOC_ES8323) += snd-soc-es8323.o
obj-$(CONFIG_SND_SOC_ES8326) += snd-soc-es8326.o
obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o
obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
@@ -591,6 +604,9 @@ obj-$(CONFIG_SND_SOC_NAU8821) += snd-soc-nau8821.o
obj-$(CONFIG_SND_SOC_NAU8822) += snd-soc-nau8822.o
obj-$(CONFIG_SND_SOC_NAU8824) += snd-soc-nau8824.o
obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o
+obj-$(CONFIG_SND_SOC_NTP8835) += snd-soc-ntp8835.o
+obj-$(CONFIG_SND_SOC_NTP8918) += snd-soc-ntp8918.o
+obj-$(CONFIG_SND_SOC_NTPFW) += snd-soc-ntpfw.o
obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o
@@ -618,6 +634,7 @@ obj-$(CONFIG_SND_SOC_RK3308) += snd-soc-rk3308.o
obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o
obj-$(CONFIG_SND_SOC_RK817) += snd-soc-rk817.o
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
+obj-$(CONFIG_SND_SOC_RT_SDW_COMMON) += snd-soc-rt-sdw-common.o
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o
obj-$(CONFIG_SND_SOC_RT1015) += snd-soc-rt1015.o
@@ -662,6 +679,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_RT721_SDCA_SDW) += snd-soc-rt721-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_RTQ9128) += snd-soc-rtq9128.o
@@ -672,6 +690,7 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o
obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o
obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o
obj-$(CONFIG_SND_SOC_SMA1303) += snd-soc-sma1303.o
+obj-$(CONFIG_SND_SOC_SMA1307) += snd-soc-sma1307.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
obj-$(CONFIG_SND_SOC_SRC4XXX) += snd-soc-src4xxx.o
obj-$(CONFIG_SND_SOC_SRC4XXX_I2C) += snd-soc-src4xxx-i2c.o
@@ -723,6 +742,7 @@ obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
obj-$(CONFIG_SND_SOC_UDA1334) += snd-soc-uda1334.o
+obj-$(CONFIG_SND_SOC_UDA1342) += snd-soc-uda1342.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
obj-$(CONFIG_SND_SOC_WCD_CLASSH) += snd-soc-wcd-classh.o
obj-$(CONFIG_SND_SOC_WCD_MBHC) += snd-soc-wcd-mbhc.o
diff --git a/sound/soc/codecs/adau1372-i2c.c b/sound/soc/codecs/adau1372-i2c.c
index 2869325f9ace..73f83be38f74 100644
--- a/sound/soc/codecs/adau1372-i2c.c
+++ b/sound/soc/codecs/adau1372-i2c.c
@@ -29,6 +29,7 @@ MODULE_DEVICE_TABLE(i2c, adau1372_i2c_ids);
static struct i2c_driver adau1372_i2c_driver = {
.driver = {
.name = "adau1372",
+ .of_match_table = adau1372_of_match,
},
.probe = adau1372_i2c_probe,
.id_table = adau1372_i2c_ids,
diff --git a/sound/soc/codecs/adau1372-spi.c b/sound/soc/codecs/adau1372-spi.c
index 51298e00fbd6..656bd1fabeb3 100644
--- a/sound/soc/codecs/adau1372-spi.c
+++ b/sound/soc/codecs/adau1372-spi.c
@@ -47,6 +47,7 @@ MODULE_DEVICE_TABLE(spi, adau1372_spi_id);
static struct spi_driver adau1372_spi_driver = {
.driver = {
.name = "adau1372",
+ .of_match_table = adau1372_of_match,
},
.probe = adau1372_spi_probe,
.id_table = adau1372_spi_id,
diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c
index 98380a7ce64d..fdee689cae53 100644
--- a/sound/soc/codecs/adau1372.c
+++ b/sound/soc/codecs/adau1372.c
@@ -11,6 +11,7 @@
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/pm.h>
#include <linux/slab.h>
@@ -1060,6 +1061,13 @@ const struct regmap_config adau1372_regmap_config = {
};
EXPORT_SYMBOL_GPL(adau1372_regmap_config);
+const struct of_device_id adau1372_of_match[] = {
+ { .compatible = "adi,adau1372" },
+ { }
+};
+EXPORT_SYMBOL_GPL(adau1372_of_match);
+MODULE_DEVICE_TABLE(of, adau1372_of_match);
+
MODULE_DESCRIPTION("ASoC ADAU1372 CODEC driver");
MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/adau1372.h b/sound/soc/codecs/adau1372.h
index a9d2c59b73a9..c55b1c24fe39 100644
--- a/sound/soc/codecs/adau1372.h
+++ b/sound/soc/codecs/adau1372.h
@@ -13,6 +13,7 @@
struct device;
+extern const struct of_device_id adau1372_of_match[];
int adau1372_probe(struct device *dev, struct regmap *regmap,
void (*switch_mode)(struct device *dev));
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index a910e252aa12..16b9b2658341 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -8,8 +8,10 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/pm.h>
+#include <linux/property.h>
#include <linux/i2c.h>
#include <linux/slab.h>
@@ -18,7 +20,6 @@
#include <sound/pcm_params.h>
#include <sound/tlv.h>
#include <sound/soc.h>
-#include <sound/adau1373.h>
#include "adau1373.h"
#include "adau-utils.h"
@@ -30,9 +31,28 @@ struct adau1373_dai {
bool clock_provider;
};
+enum adau1373_micbias_voltage {
+ ADAU1373_MICBIAS_2_9V,
+ ADAU1373_MICBIAS_2_2V,
+ ADAU1373_MICBIAS_2_6V,
+ ADAU1373_MICBIAS_1_8V,
+};
+
+#define ADAU1373_DRC_SIZE 13
+
struct adau1373 {
struct regmap *regmap;
struct adau1373_dai dais[3];
+
+ bool input_differential[4];
+ bool lineout_differential;
+ bool lineout_ground_sense;
+
+ unsigned int num_drc;
+ u8 drc_setting[3][ADAU1373_DRC_SIZE];
+
+ enum adau1373_micbias_voltage micbias1;
+ enum adau1373_micbias_voltage micbias2;
};
#define ADAU1373_INPUT_MODE 0x00
@@ -1332,66 +1352,61 @@ static void adau1373_load_drc_settings(struct adau1373 *adau1373,
regmap_write(adau1373->regmap, ADAU1373_DRC(nr) + i, drc[i]);
}
-static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias)
+static int adau1373_get_micbias(unsigned int val,
+ enum adau1373_micbias_voltage *micbias)
{
- switch (micbias) {
- case ADAU1373_MICBIAS_2_9V:
- case ADAU1373_MICBIAS_2_2V:
- case ADAU1373_MICBIAS_2_6V:
- case ADAU1373_MICBIAS_1_8V:
- return true;
+ switch (val) {
+ case 2900000:
+ *micbias = ADAU1373_MICBIAS_2_9V;
+ return 0;
+ case 2200000:
+ *micbias = ADAU1373_MICBIAS_2_2V;
+ return 0;
+ case 2600000:
+ *micbias = ADAU1373_MICBIAS_2_6V;
+ return 0;
+ case 1800000:
+ *micbias = ADAU1373_MICBIAS_1_8V;
+ return 0;
default:
- break;
+ return -EINVAL;
}
- return false;
}
static int adau1373_probe(struct snd_soc_component *component)
{
struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
- struct adau1373_platform_data *pdata = component->dev->platform_data;
- bool lineout_differential = false;
unsigned int val;
int i;
- if (pdata) {
- if (pdata->num_drc > ARRAY_SIZE(pdata->drc_setting))
- return -EINVAL;
-
- if (!adau1373_valid_micbias(pdata->micbias1) ||
- !adau1373_valid_micbias(pdata->micbias2))
- return -EINVAL;
-
- for (i = 0; i < pdata->num_drc; ++i) {
- adau1373_load_drc_settings(adau1373, i,
- pdata->drc_setting[i]);
- }
+ for (i = 0; i < adau1373->num_drc; ++i) {
+ adau1373_load_drc_settings(adau1373, i,
+ adau1373->drc_setting[i]);
+ }
- snd_soc_add_component_controls(component, adau1373_drc_controls,
- pdata->num_drc);
+ snd_soc_add_component_controls(component, adau1373_drc_controls,
+ adau1373->num_drc);
- val = 0;
- for (i = 0; i < 4; ++i) {
- if (pdata->input_differential[i])
- val |= BIT(i);
- }
- regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val);
+ val = 0;
+ for (i = 0; i < ARRAY_SIZE(adau1373->input_differential); ++i) {
+ if (adau1373->input_differential[i])
+ val |= BIT(i);
+ }
+ regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val);
- val = 0;
- if (pdata->lineout_differential)
- val |= ADAU1373_OUTPUT_CTRL_LDIFF;
- if (pdata->lineout_ground_sense)
- val |= ADAU1373_OUTPUT_CTRL_LNFBEN;
- regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val);
+ val = 0;
+ if (adau1373->lineout_differential)
+ val |= ADAU1373_OUTPUT_CTRL_LDIFF;
+ if (adau1373->lineout_ground_sense)
+ val |= ADAU1373_OUTPUT_CTRL_LNFBEN;
- lineout_differential = pdata->lineout_differential;
+ regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val);
- regmap_write(adau1373->regmap, ADAU1373_EP_CTRL,
- (pdata->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) |
- (pdata->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET));
- }
+ regmap_write(adau1373->regmap, ADAU1373_EP_CTRL,
+ (adau1373->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) |
+ (adau1373->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET));
- if (!lineout_differential) {
+ if (!adau1373->lineout_differential) {
snd_soc_add_component_controls(component, adau1373_lineout2_controls,
ARRAY_SIZE(adau1373_lineout2_controls));
}
@@ -1471,9 +1486,74 @@ static const struct snd_soc_component_driver adau1373_component_driver = {
.endianness = 1,
};
+static void adau1373_reset(void *reset_gpio)
+{
+ gpiod_set_value_cansleep(reset_gpio, 1);
+}
+
+static int adau1373_parse_fw(struct device *dev, struct adau1373 *adau1373)
+{
+ int ret, drc_count;
+ unsigned int val;
+
+ if (device_property_present(dev, "adi,input1-differential"))
+ adau1373->input_differential[0] = true;
+ if (device_property_present(dev, "adi,input2-differential"))
+ adau1373->input_differential[1] = true;
+ if (device_property_present(dev, "adi,input3-differential"))
+ adau1373->input_differential[2] = true;
+ if (device_property_present(dev, "adi,input4-differential"))
+ adau1373->input_differential[3] = true;
+
+ if (device_property_present(dev, "adi,lineout-differential"))
+ adau1373->lineout_differential = true;
+ if (device_property_present(dev, "adi,lineout-gnd-sense"))
+ adau1373->lineout_ground_sense = true;
+
+ ret = device_property_read_u32(dev, "adi,micbias1-microvolt", &val);
+ if (!ret) {
+ ret = adau1373_get_micbias(val, &adau1373->micbias1);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get micbias1(%u)\n", val);
+ }
+
+ ret = device_property_read_u32(dev, "adi,micbias2-microvolt", &val);
+ if (!ret) {
+ ret = adau1373_get_micbias(val, &adau1373->micbias2);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get micbias2(%u)\n", val);
+ }
+
+ drc_count = device_property_count_u8(dev, "adi,drc-settings");
+ if (drc_count < 0)
+ return 0;
+ if (drc_count % ADAU1373_DRC_SIZE != 0)
+ return dev_err_probe(dev, -EINVAL,
+ "DRC count(%u) not multiple of %u\n",
+ drc_count, ADAU1373_DRC_SIZE);
+
+ adau1373->num_drc = drc_count / ADAU1373_DRC_SIZE;
+ if (adau1373->num_drc > ARRAY_SIZE(adau1373->drc_setting))
+ return dev_err_probe(dev, -EINVAL,
+ "Too many DRC settings(%u)\n",
+ adau1373->num_drc);
+
+ ret = device_property_read_u8_array(dev, "adi,drc-settings",
+ (u8 *)&adau1373->drc_setting[0],
+ drc_count);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to read DRC settings\n");
+
+ return 0;
+}
+
static int adau1373_i2c_probe(struct i2c_client *client)
{
struct adau1373 *adau1373;
+ struct gpio_desc *gpiod;
int ret;
adau1373 = devm_kzalloc(&client->dev, sizeof(*adau1373), GFP_KERNEL);
@@ -1485,10 +1565,33 @@ static int adau1373_i2c_probe(struct i2c_client *client)
if (IS_ERR(adau1373->regmap))
return PTR_ERR(adau1373->regmap);
- regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00);
+ /*
+ * If the powerdown GPIO is specified, we use it for reset. Otherwise
+ * a software reset is done.
+ */
+ gpiod = devm_gpiod_get_optional(&client->dev, "powerdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(gpiod))
+ return PTR_ERR(gpiod);
+
+ if (gpiod) {
+ gpiod_set_value_cansleep(gpiod, 0);
+ fsleep(10);
+
+ ret = devm_add_action_or_reset(&client->dev, adau1373_reset,
+ gpiod);
+ if (ret)
+ return ret;
+ } else {
+ regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00);
+ }
dev_set_drvdata(&client->dev, adau1373);
+ ret = adau1373_parse_fw(&client->dev, adau1373);
+ if (ret)
+ return ret;
+
ret = devm_snd_soc_register_component(&client->dev,
&adau1373_component_driver,
adau1373_dai_driver, ARRAY_SIZE(adau1373_dai_driver));
@@ -1501,9 +1604,16 @@ static const struct i2c_device_id adau1373_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, adau1373_i2c_id);
+static const struct of_device_id adau1373_of_match[] = {
+ { .compatible = "adi,adau1373", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adau1373_of_match);
+
static struct i2c_driver adau1373_i2c_driver = {
.driver = {
.name = "adau1373",
+ .of_match_table = adau1373_of_match,
},
.probe = adau1373_i2c_probe,
.id_table = adau1373_i2c_id,
diff --git a/sound/soc/codecs/aw88081.c b/sound/soc/codecs/aw88081.c
new file mode 100644
index 000000000000..58b8e002d76f
--- /dev/null
+++ b/sound/soc/codecs/aw88081.c
@@ -0,0 +1,1087 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88081.c -- AW88081 ALSA SoC Audio driver
+//
+// Copyright (c) 2024 awinic Technology CO., LTD
+//
+// Author: Weidong Wang <[email protected]>
+//
+
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "aw88081.h"
+#include "aw88395/aw88395_device.h"
+
+struct aw88081 {
+ struct aw_device *aw_pa;
+ struct mutex lock;
+ struct delayed_work start_work;
+ struct regmap *regmap;
+ struct aw_container *aw_cfg;
+
+ bool phase_sync;
+};
+
+static const struct regmap_config aw88081_regmap_config = {
+ .val_bits = 16,
+ .reg_bits = 8,
+ .max_register = AW88081_REG_MAX,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static int aw88081_dev_get_iis_status(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88081_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+ if ((reg_val & AW88081_BIT_PLL_CHECK) != AW88081_BIT_PLL_CHECK) {
+ dev_err(aw_dev->dev, "check pll lock fail,reg_val:0x%04x", reg_val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int aw88081_dev_check_mode1_pll(struct aw_device *aw_dev)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw88081_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode1 iis signal check error");
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 10);
+ } else {
+ return 0;
+ }
+ }
+
+ return -EPERM;
+}
+
+static int aw88081_dev_check_mode2_pll(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret, i;
+
+ ret = regmap_read(aw_dev->regmap, AW88081_PLLCTRL1_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_val &= (~AW88081_CCO_MUX_MASK);
+ if (reg_val == AW88081_CCO_MUX_DIVIDED_VALUE) {
+ dev_dbg(aw_dev->dev, "CCO_MUX is already divider");
+ return -EPERM;
+ }
+
+ /* change mode2 */
+ ret = regmap_update_bits(aw_dev->regmap, AW88081_PLLCTRL1_REG,
+ ~AW88081_CCO_MUX_MASK, AW88081_CCO_MUX_DIVIDED_VALUE);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw88081_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 iis check error");
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+
+ /* change mode1 */
+ ret = regmap_update_bits(aw_dev->regmap, AW88081_PLLCTRL1_REG,
+ ~AW88081_CCO_MUX_MASK, AW88081_CCO_MUX_BYPASS_VALUE);
+ if (ret == 0) {
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 10);
+ for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw88081_dev_check_mode1_pll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 switch to mode1, iis check error");
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int aw88081_dev_check_syspll(struct aw_device *aw_dev)
+{
+ int ret;
+
+ ret = aw88081_dev_check_mode1_pll(aw_dev);
+ if (ret) {
+ dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
+ ret = aw88081_dev_check_mode2_pll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 check iis failed");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int aw88081_dev_check_sysst(struct aw_device *aw_dev)
+{
+ unsigned int check_val;
+ unsigned int reg_val;
+ unsigned int value;
+ int ret, i;
+
+ ret = regmap_read(aw_dev->regmap, AW88081_PWMCTRL4_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ if (reg_val & (~AW88081_NOISE_GATE_EN_MASK))
+ check_val = AW88081_NO_SWS_SYSST_CHECK;
+ else
+ check_val = AW88081_SWS_SYSST_CHECK;
+
+ for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) {
+ ret = regmap_read(aw_dev->regmap, AW88081_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ value = reg_val & (~AW88081_BIT_SYSST_CHECK_MASK) & check_val;
+ if (value != check_val) {
+ dev_err(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x",
+ reg_val, check_val);
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 10);
+ } else {
+ return 0;
+ }
+ }
+
+ return -EPERM;
+}
+
+static void aw88081_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
+{
+ if (flag)
+ regmap_update_bits(aw_dev->regmap, AW88081_I2SCTRL3_REG,
+ ~AW88081_I2STXEN_MASK, AW88081_I2STXEN_ENABLE_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88081_I2SCTRL3_REG,
+ ~AW88081_I2STXEN_MASK, AW88081_I2STXEN_DISABLE_VALUE);
+}
+
+static void aw88081_dev_pwd(struct aw_device *aw_dev, bool pwd)
+{
+ if (pwd)
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_PWDN_MASK, AW88081_PWDN_POWER_DOWN_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_PWDN_MASK, AW88081_PWDN_WORKING_VALUE);
+}
+
+static void aw88081_dev_amppd(struct aw_device *aw_dev, bool amppd)
+{
+ if (amppd)
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_EN_PA_MASK, AW88081_EN_PA_POWER_DOWN_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_EN_PA_MASK, AW88081_EN_PA_WORKING_VALUE);
+}
+
+static void aw88081_dev_clear_int_status(struct aw_device *aw_dev)
+{
+ unsigned int int_status;
+
+ /* read int status and clear */
+ regmap_read(aw_dev->regmap, AW88081_SYSINT_REG, &int_status);
+ /* make sure int status is clear */
+ regmap_read(aw_dev->regmap, AW88081_SYSINT_REG, &int_status);
+
+ dev_dbg(aw_dev->dev, "read interrupt reg = 0x%04x", int_status);
+}
+
+static void aw88081_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
+{
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ unsigned int volume;
+
+ volume = min((value + vol_desc->init_volume), (unsigned int)AW88081_MUTE_VOL);
+
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL2_REG, ~AW88081_VOL_MASK, volume);
+}
+
+static void aw88081_dev_fade_in(struct aw_device *aw_dev)
+{
+ struct aw_volume_desc *desc = &aw_dev->volume_desc;
+ int fade_in_vol = desc->ctl_volume;
+ int fade_step = aw_dev->fade_step;
+ int i;
+
+ if (fade_step == 0 || aw_dev->fade_in_time == 0) {
+ aw88081_dev_set_volume(aw_dev, fade_in_vol);
+ return;
+ }
+
+ for (i = AW88081_MUTE_VOL; i >= fade_in_vol; i -= fade_step) {
+ aw88081_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10);
+ }
+
+ if (i != fade_in_vol)
+ aw88081_dev_set_volume(aw_dev, fade_in_vol);
+}
+
+static void aw88081_dev_fade_out(struct aw_device *aw_dev)
+{
+ struct aw_volume_desc *desc = &aw_dev->volume_desc;
+ int fade_step = aw_dev->fade_step;
+ int i;
+
+ if (fade_step == 0 || aw_dev->fade_out_time == 0) {
+ aw88081_dev_set_volume(aw_dev, AW88081_MUTE_VOL);
+ return;
+ }
+
+ for (i = desc->ctl_volume; i <= AW88081_MUTE_VOL; i += fade_step) {
+ aw88081_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+
+ if (i != AW88081_MUTE_VOL)
+ aw88081_dev_set_volume(aw_dev, AW88081_MUTE_VOL);
+}
+
+static void aw88081_dev_mute(struct aw_device *aw_dev, bool is_mute)
+{
+ if (is_mute) {
+ aw88081_dev_fade_out(aw_dev);
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_HMUTE_MASK, AW88081_HMUTE_ENABLE_VALUE);
+ } else {
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_HMUTE_MASK, AW88081_HMUTE_DISABLE_VALUE);
+ aw88081_dev_fade_in(aw_dev);
+ }
+}
+
+static void aw88081_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute)
+{
+ if (uls_hmute)
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_ULS_HMUTE_MASK,
+ AW88081_ULS_HMUTE_ENABLE_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_ULS_HMUTE_MASK,
+ AW88081_ULS_HMUTE_DISABLE_VALUE);
+}
+
+static int aw88081_dev_reg_update(struct aw88081 *aw88081,
+ unsigned char *data, unsigned int len)
+{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ unsigned int read_vol;
+ int data_len, i, ret;
+ int16_t *reg_data;
+ u16 reg_val;
+ u8 reg_addr;
+
+ if (!len || !data) {
+ dev_err(aw_dev->dev, "reg data is null or len is 0");
+ return -EINVAL;
+ }
+
+ reg_data = (int16_t *)data;
+ data_len = len >> 1;
+
+ if (data_len & 0x1) {
+ dev_err(aw_dev->dev, "data len:%d unsupported", data_len);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < data_len; i += 2) {
+ reg_addr = reg_data[i];
+ reg_val = reg_data[i + 1];
+
+ if (reg_addr == AW88081_SYSCTRL_REG) {
+ reg_val &= ~(~AW88081_EN_PA_MASK |
+ ~AW88081_PWDN_MASK |
+ ~AW88081_HMUTE_MASK |
+ ~AW88081_ULS_HMUTE_MASK);
+
+ reg_val |= AW88081_EN_PA_POWER_DOWN_VALUE |
+ AW88081_PWDN_POWER_DOWN_VALUE |
+ AW88081_HMUTE_ENABLE_VALUE |
+ AW88081_ULS_HMUTE_ENABLE_VALUE;
+ }
+
+ if (reg_addr == AW88081_SYSCTRL2_REG) {
+ read_vol = (reg_val & (~AW88081_VOL_MASK)) >>
+ AW88081_VOL_START_BIT;
+ aw_dev->volume_desc.init_volume = read_vol;
+ }
+
+ /* i2stxen */
+ if (reg_addr == AW88081_I2SCTRL3_REG) {
+ /* close tx */
+ reg_val &= AW88081_I2STXEN_MASK;
+ reg_val |= AW88081_I2STXEN_DISABLE_VALUE;
+ }
+
+ ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
+ if (ret)
+ return ret;
+ }
+
+ if (aw_dev->prof_cur != aw_dev->prof_index)
+ vol_desc->ctl_volume = 0;
+
+ /* keep min volume */
+ aw88081_dev_set_volume(aw_dev, vol_desc->mute_volume);
+
+ return 0;
+}
+
+static int aw88081_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name)
+{
+ struct aw_prof_info *prof_info = &aw_dev->prof_info;
+ struct aw_prof_desc *prof_desc;
+
+ if ((index >= aw_dev->prof_info.count) || (index < 0)) {
+ dev_err(aw_dev->dev, "index[%d] overflow count[%d]",
+ index, aw_dev->prof_info.count);
+ return -EINVAL;
+ }
+
+ prof_desc = &aw_dev->prof_info.prof_desc[index];
+
+ *prof_name = prof_info->prof_name_list[prof_desc->id];
+
+ return 0;
+}
+
+static int aw88081_dev_get_prof_data(struct aw_device *aw_dev, int index,
+ struct aw_prof_desc **prof_desc)
+{
+ if ((index >= aw_dev->prof_info.count) || (index < 0)) {
+ dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n",
+ __func__, index, aw_dev->prof_info.count);
+ return -EINVAL;
+ }
+
+ *prof_desc = &aw_dev->prof_info.prof_desc[index];
+
+ return 0;
+}
+
+static int aw88081_dev_fw_update(struct aw88081 *aw88081)
+{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+ struct aw_prof_desc *prof_index_desc;
+ struct aw_sec_data_desc *sec_desc;
+ char *prof_name;
+ int ret;
+
+ ret = aw88081_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name);
+ if (ret) {
+ dev_err(aw_dev->dev, "get prof name failed");
+ return -EINVAL;
+ }
+
+ dev_dbg(aw_dev->dev, "start update %s", prof_name);
+
+ ret = aw88081_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc);
+ if (ret)
+ return ret;
+
+ /* update reg */
+ sec_desc = prof_index_desc->sec_desc;
+ ret = aw88081_dev_reg_update(aw88081, sec_desc[AW88395_DATA_TYPE_REG].data,
+ sec_desc[AW88395_DATA_TYPE_REG].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update reg failed");
+ return ret;
+ }
+
+ aw_dev->prof_cur = aw_dev->prof_index;
+
+ return 0;
+}
+
+static int aw88081_dev_start(struct aw88081 *aw88081)
+{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+ int ret;
+
+ if (aw_dev->status == AW88081_DEV_PW_ON) {
+ dev_dbg(aw_dev->dev, "already power on");
+ return 0;
+ }
+
+ /* power on */
+ aw88081_dev_pwd(aw_dev, false);
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 10);
+
+ ret = aw88081_dev_check_syspll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "pll check failed cannot start");
+ goto pll_check_fail;
+ }
+
+ /* amppd on */
+ aw88081_dev_amppd(aw_dev, false);
+ usleep_range(AW88081_1000_US, AW88081_1000_US + 50);
+
+ /* check i2s status */
+ ret = aw88081_dev_check_sysst(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "sysst check failed");
+ goto sysst_check_fail;
+ }
+
+ /* enable tx feedback */
+ aw88081_dev_i2s_tx_enable(aw_dev, true);
+
+ /* close uls mute */
+ aw88081_dev_uls_hmute(aw_dev, false);
+
+ /* close mute */
+ aw88081_dev_mute(aw_dev, false);
+
+ /* clear inturrupt */
+ aw88081_dev_clear_int_status(aw_dev);
+ aw_dev->status = AW88081_DEV_PW_ON;
+
+ return 0;
+
+sysst_check_fail:
+ aw88081_dev_i2s_tx_enable(aw_dev, false);
+ aw88081_dev_clear_int_status(aw_dev);
+ aw88081_dev_amppd(aw_dev, true);
+pll_check_fail:
+ aw88081_dev_pwd(aw_dev, true);
+ aw_dev->status = AW88081_DEV_PW_OFF;
+
+ return ret;
+}
+
+static int aw88081_dev_stop(struct aw_device *aw_dev)
+{
+ if (aw_dev->status == AW88081_DEV_PW_OFF) {
+ dev_dbg(aw_dev->dev, "already power off");
+ return 0;
+ }
+
+ aw_dev->status = AW88081_DEV_PW_OFF;
+
+ /* clear inturrupt */
+ aw88081_dev_clear_int_status(aw_dev);
+
+ aw88081_dev_uls_hmute(aw_dev, true);
+ /* set mute */
+ aw88081_dev_mute(aw_dev, true);
+
+ /* close tx feedback */
+ aw88081_dev_i2s_tx_enable(aw_dev, false);
+ usleep_range(AW88081_1000_US, AW88081_1000_US + 100);
+
+ /* enable amppd */
+ aw88081_dev_amppd(aw_dev, true);
+
+ /* set power down */
+ aw88081_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+
+static int aw88081_reg_update(struct aw88081 *aw88081, bool force)
+{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+ int ret;
+
+ if (force) {
+ ret = regmap_write(aw_dev->regmap,
+ AW88081_ID_REG, AW88081_SOFT_RESET_VALUE);
+ if (ret)
+ return ret;
+
+ ret = aw88081_dev_fw_update(aw88081);
+ if (ret)
+ return ret;
+ } else {
+ if (aw_dev->prof_cur != aw_dev->prof_index) {
+ ret = aw88081_dev_fw_update(aw88081);
+ if (ret)
+ return ret;
+ }
+ }
+
+ aw_dev->prof_cur = aw_dev->prof_index;
+
+ return 0;
+}
+
+static void aw88081_start_pa(struct aw88081 *aw88081)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88081_START_RETRIES; i++) {
+ ret = aw88081_reg_update(aw88081, aw88081->phase_sync);
+ if (ret) {
+ dev_err(aw88081->aw_pa->dev, "fw update failed, cnt:%d\n", i);
+ continue;
+ }
+ ret = aw88081_dev_start(aw88081);
+ if (ret) {
+ dev_err(aw88081->aw_pa->dev, "aw88081 device start failed. retry = %d", i);
+ continue;
+ } else {
+ dev_dbg(aw88081->aw_pa->dev, "start success\n");
+ break;
+ }
+ }
+}
+
+static void aw88081_startup_work(struct work_struct *work)
+{
+ struct aw88081 *aw88081 =
+ container_of(work, struct aw88081, start_work.work);
+
+ mutex_lock(&aw88081->lock);
+ aw88081_start_pa(aw88081);
+ mutex_unlock(&aw88081->lock);
+}
+
+static void aw88081_start(struct aw88081 *aw88081, bool sync_start)
+{
+ if (aw88081->aw_pa->fw_status != AW88081_DEV_FW_OK)
+ return;
+
+ if (aw88081->aw_pa->status == AW88081_DEV_PW_ON)
+ return;
+
+ if (sync_start == AW88081_SYNC_START)
+ aw88081_start_pa(aw88081);
+ else
+ queue_delayed_work(system_wq,
+ &aw88081->start_work,
+ AW88081_START_WORK_DELAY_MS);
+}
+
+static struct snd_soc_dai_driver aw88081_dai[] = {
+ {
+ .name = "aw88081-aif",
+ .id = 1,
+ .playback = {
+ .stream_name = "Speaker_Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AW88081_RATES,
+ .formats = AW88081_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Speaker_Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AW88081_RATES,
+ .formats = AW88081_FORMATS,
+ },
+ },
+};
+
+static int aw88081_get_fade_in_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component);
+ struct aw_device *aw_dev = aw88081->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->fade_in_time;
+
+ return 0;
+}
+
+static int aw88081_set_fade_in_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct aw_device *aw_dev = aw88081->aw_pa;
+ int time;
+
+ time = ucontrol->value.integer.value[0];
+
+ if (time < mc->min || time > mc->max)
+ return -EINVAL;
+
+ if (time != aw_dev->fade_in_time) {
+ aw_dev->fade_in_time = time;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int aw88081_get_fade_out_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component);
+ struct aw_device *aw_dev = aw88081->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->fade_out_time;
+
+ return 0;
+}
+
+static int aw88081_set_fade_out_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct aw_device *aw_dev = aw88081->aw_pa;
+ int time;
+
+ time = ucontrol->value.integer.value[0];
+ if (time < mc->min || time > mc->max)
+ return -EINVAL;
+
+ if (time != aw_dev->fade_out_time) {
+ aw_dev->fade_out_time = time;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int aw88081_dev_set_profile_index(struct aw_device *aw_dev, int index)
+{
+ /* check the index whether is valid */
+ if ((index >= aw_dev->prof_info.count) || (index < 0))
+ return -EINVAL;
+ /* check the index whether change */
+ if (aw_dev->prof_index == index)
+ return -EPERM;
+
+ aw_dev->prof_index = index;
+
+ return 0;
+}
+
+static int aw88081_profile_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec);
+ char *prof_name;
+ int count, ret;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+
+ count = aw88081->aw_pa->prof_info.count;
+ if (count <= 0) {
+ uinfo->value.enumerated.items = 0;
+ return 0;
+ }
+
+ uinfo->value.enumerated.items = count;
+
+ if (uinfo->value.enumerated.item >= count)
+ uinfo->value.enumerated.item = count - 1;
+
+ count = uinfo->value.enumerated.item;
+
+ ret = aw88081_dev_get_prof_name(aw88081->aw_pa, count, &prof_name);
+ if (ret) {
+ strscpy(uinfo->value.enumerated.name, "null",
+ sizeof(uinfo->value.enumerated.name));
+ return 0;
+ }
+
+ strscpy(uinfo->value.enumerated.name, prof_name, sizeof(uinfo->value.enumerated.name));
+
+ return 0;
+}
+
+static int aw88081_profile_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = aw88081->aw_pa->prof_index;
+
+ return 0;
+}
+
+static int aw88081_profile_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec);
+ int ret;
+
+ /* pa stop or stopping just set profile */
+ mutex_lock(&aw88081->lock);
+ ret = aw88081_dev_set_profile_index(aw88081->aw_pa, ucontrol->value.integer.value[0]);
+ if (ret) {
+ dev_dbg(codec->dev, "profile index does not change");
+ mutex_unlock(&aw88081->lock);
+ return 0;
+ }
+
+ if (aw88081->aw_pa->status) {
+ aw88081_dev_stop(aw88081->aw_pa);
+ aw88081_start(aw88081, AW88081_SYNC_START);
+ }
+
+ mutex_unlock(&aw88081->lock);
+
+ return 1;
+}
+
+static int aw88081_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec);
+ struct aw_volume_desc *vol_desc = &aw88081->aw_pa->volume_desc;
+
+ ucontrol->value.integer.value[0] = vol_desc->ctl_volume;
+
+ return 0;
+}
+
+static int aw88081_volume_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec);
+ struct aw_volume_desc *vol_desc = &aw88081->aw_pa->volume_desc;
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int value;
+
+ value = ucontrol->value.integer.value[0];
+
+ if (value < mc->min || value > mc->max)
+ return -EINVAL;
+
+ if (vol_desc->ctl_volume != value) {
+ vol_desc->ctl_volume = value;
+ aw88081_dev_set_volume(aw88081->aw_pa, vol_desc->ctl_volume);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int aw88081_get_fade_step(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = aw88081->aw_pa->fade_step;
+
+ return 0;
+}
+
+static int aw88081_set_fade_step(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int value;
+
+ value = ucontrol->value.integer.value[0];
+ if (value < mc->min || value > mc->max)
+ return -EINVAL;
+
+ if (aw88081->aw_pa->fade_step != value) {
+ aw88081->aw_pa->fade_step = value;
+ return 1;
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new aw88081_controls[] = {
+ SOC_SINGLE_EXT("PCM Playback Volume", AW88081_SYSCTRL2_REG,
+ 0, AW88081_MUTE_VOL, 0, aw88081_volume_get,
+ aw88081_volume_set),
+ SOC_SINGLE_EXT("Fade Step", 0, 0, AW88081_MUTE_VOL, 0,
+ aw88081_get_fade_step, aw88081_set_fade_step),
+ SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, 0,
+ aw88081_get_fade_in_time, aw88081_set_fade_in_time),
+ SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, 0,
+ aw88081_get_fade_out_time, aw88081_set_fade_out_time),
+ AW88081_PROFILE_EXT("Profile Set", aw88081_profile_info,
+ aw88081_profile_get, aw88081_profile_set),
+};
+
+static void aw88081_parse_channel_dt(struct aw88081 *aw88081)
+{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+ struct device_node *np = aw_dev->dev->of_node;
+ u32 channel_value = AW88081_DEV_DEFAULT_CH;
+
+ of_property_read_u32(np, "awinic,audio-channel", &channel_value);
+ aw88081->phase_sync = of_property_read_bool(np, "awinic,sync-flag");
+
+ aw_dev->channel = channel_value;
+}
+
+static int aw88081_init(struct aw88081 *aw88081, struct i2c_client *i2c, struct regmap *regmap)
+{
+ struct aw_device *aw_dev;
+ unsigned int chip_id;
+ int ret;
+
+ /* read chip id */
+ ret = regmap_read(regmap, AW88081_ID_REG, &chip_id);
+ if (ret) {
+ dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
+ return ret;
+ }
+ if (chip_id != AW88081_CHIP_ID) {
+ dev_err(&i2c->dev, "unsupported device");
+ return -ENXIO;
+ }
+
+ dev_dbg(&i2c->dev, "chip id = %x\n", chip_id);
+
+ aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
+ if (!aw_dev)
+ return -ENOMEM;
+
+ aw88081->aw_pa = aw_dev;
+ aw_dev->i2c = i2c;
+ aw_dev->regmap = regmap;
+ aw_dev->dev = &i2c->dev;
+ aw_dev->chip_id = AW88081_CHIP_ID;
+ aw_dev->acf = NULL;
+ aw_dev->prof_info.prof_desc = NULL;
+ aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
+ aw_dev->fade_step = AW88081_VOLUME_STEP_DB;
+ aw_dev->volume_desc.mute_volume = AW88081_MUTE_VOL;
+ aw88081_parse_channel_dt(aw88081);
+
+ return 0;
+}
+
+static int aw88081_dev_init(struct aw88081 *aw88081, struct aw_container *aw_cfg)
+{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+ int ret;
+
+ ret = aw88395_dev_cfg_load(aw_dev, aw_cfg);
+ if (ret) {
+ dev_err(aw_dev->dev, "aw_dev acf parse failed");
+ return -EINVAL;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW88081_ID_REG, AW88081_SOFT_RESET_VALUE);
+ if (ret)
+ return ret;
+
+ aw_dev->fade_in_time = AW88081_500_US;
+ aw_dev->fade_out_time = AW88081_500_US;
+ aw_dev->prof_cur = AW88081_INIT_PROFILE;
+ aw_dev->prof_index = AW88081_INIT_PROFILE;
+
+ ret = aw88081_dev_fw_update(aw88081);
+ if (ret) {
+ dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret);
+ return ret;
+ }
+
+ aw88081_dev_clear_int_status(aw_dev);
+
+ aw88081_dev_uls_hmute(aw_dev, true);
+
+ aw88081_dev_mute(aw_dev, true);
+
+ usleep_range(AW88081_5000_US, AW88081_5000_US + 10);
+
+ aw88081_dev_i2s_tx_enable(aw_dev, false);
+
+ usleep_range(AW88081_1000_US, AW88081_1000_US + 100);
+
+ aw88081_dev_amppd(aw_dev, true);
+
+ aw88081_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+
+static int aw88081_request_firmware_file(struct aw88081 *aw88081)
+{
+ const struct firmware *cont = NULL;
+ int ret;
+
+ aw88081->aw_pa->fw_status = AW88081_DEV_FW_FAILED;
+
+ ret = request_firmware(&cont, AW88081_ACF_FILE, aw88081->aw_pa->dev);
+ if (ret)
+ return ret;
+
+ dev_dbg(aw88081->aw_pa->dev, "loaded %s - size: %zu\n",
+ AW88081_ACF_FILE, cont ? cont->size : 0);
+
+ aw88081->aw_cfg = devm_kzalloc(aw88081->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL);
+ if (!aw88081->aw_cfg) {
+ release_firmware(cont);
+ return -ENOMEM;
+ }
+ aw88081->aw_cfg->len = (int)cont->size;
+ memcpy(aw88081->aw_cfg->data, cont->data, cont->size);
+ release_firmware(cont);
+
+ ret = aw88395_dev_load_acf_check(aw88081->aw_pa, aw88081->aw_cfg);
+ if (ret)
+ return ret;
+
+ mutex_lock(&aw88081->lock);
+ ret = aw88081_dev_init(aw88081, aw88081->aw_cfg);
+ mutex_unlock(&aw88081->lock);
+
+ return ret;
+}
+
+static int aw88081_playback_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&aw88081->lock);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ aw88081_start(aw88081, AW88081_ASYNC_START);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ aw88081_dev_stop(aw88081->aw_pa);
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&aw88081->lock);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget aw88081_dapm_widgets[] = {
+ /* playback */
+ SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, SND_SOC_NOPM, 0, 0,
+ aw88081_playback_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUTPUT("DAC Output"),
+
+ /* capture */
+ SND_SOC_DAPM_AIF_OUT("AIF_TX", "Speaker_Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_INPUT("ADC Input"),
+};
+
+static const struct snd_soc_dapm_route aw88081_audio_map[] = {
+ {"DAC Output", NULL, "AIF_RX"},
+ {"AIF_TX", NULL, "ADC Input"},
+};
+
+static int aw88081_codec_probe(struct snd_soc_component *component)
+{
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ INIT_DELAYED_WORK(&aw88081->start_work, aw88081_startup_work);
+
+ ret = aw88081_request_firmware_file(aw88081);
+ if (ret)
+ dev_err(aw88081->aw_pa->dev, "%s: request firmware failed\n", __func__);
+
+ return ret;
+}
+
+static void aw88081_codec_remove(struct snd_soc_component *aw_codec)
+{
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(aw_codec);
+
+ cancel_delayed_work_sync(&aw88081->start_work);
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_aw88081 = {
+ .probe = aw88081_codec_probe,
+ .remove = aw88081_codec_remove,
+ .dapm_widgets = aw88081_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(aw88081_dapm_widgets),
+ .dapm_routes = aw88081_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(aw88081_audio_map),
+ .controls = aw88081_controls,
+ .num_controls = ARRAY_SIZE(aw88081_controls),
+};
+
+static int aw88081_i2c_probe(struct i2c_client *i2c)
+{
+ struct aw88081 *aw88081;
+ int ret;
+
+ ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C);
+ if (!ret)
+ return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed");
+
+ aw88081 = devm_kzalloc(&i2c->dev, sizeof(*aw88081), GFP_KERNEL);
+ if (!aw88081)
+ return -ENOMEM;
+
+ mutex_init(&aw88081->lock);
+
+ i2c_set_clientdata(i2c, aw88081);
+
+ aw88081->regmap = devm_regmap_init_i2c(i2c, &aw88081_regmap_config);
+ if (IS_ERR(aw88081->regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(aw88081->regmap),
+ "failed to init regmap\n");
+
+ /* aw pa init */
+ ret = aw88081_init(aw88081, i2c, aw88081->regmap);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_component(&i2c->dev,
+ &soc_codec_dev_aw88081,
+ aw88081_dai, ARRAY_SIZE(aw88081_dai));
+}
+
+static const struct i2c_device_id aw88081_i2c_id[] = {
+ { AW88081_I2C_NAME },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, aw88081_i2c_id);
+
+static struct i2c_driver aw88081_i2c_driver = {
+ .driver = {
+ .name = AW88081_I2C_NAME,
+ },
+ .probe = aw88081_i2c_probe,
+ .id_table = aw88081_i2c_id,
+};
+module_i2c_driver(aw88081_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC AW88081 Smart PA Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/aw88081.h b/sound/soc/codecs/aw88081.h
new file mode 100644
index 000000000000..b4bf7288021a
--- /dev/null
+++ b/sound/soc/codecs/aw88081.h
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88081.h -- AW88081 ALSA SoC Audio driver
+//
+// Copyright (c) 2024 awinic Technology CO., LTD
+//
+// Author: Weidong Wang <[email protected]>
+//
+
+#ifndef __AW88081_H__
+#define __AW88081_H__
+
+#define AW88081_ID_REG (0x00)
+#define AW88081_SYSST_REG (0x01)
+#define AW88081_SYSINT_REG (0x02)
+#define AW88081_SYSINTM_REG (0x03)
+#define AW88081_SYSCTRL_REG (0x04)
+#define AW88081_SYSCTRL2_REG (0x05)
+#define AW88081_I2SCTRL1_REG (0x06)
+#define AW88081_I2SCTRL2_REG (0x07)
+#define AW88081_I2SCTRL3_REG (0x08)
+#define AW88081_DACCFG1_REG (0x09)
+#define AW88081_DACCFG2_REG (0x0A)
+#define AW88081_DACCFG3_REG (0x0B)
+#define AW88081_DACCFG4_REG (0x0C)
+#define AW88081_DACCFG5_REG (0x0D)
+#define AW88081_DACCFG6_REG (0x0E)
+#define AW88081_DACCFG7_REG (0x11)
+#define AW88081_PWMCTRL1_REG (0x13)
+#define AW88081_PWMCTRL2_REG (0x14)
+#define AW88081_PWMCTRL3_REG (0x15)
+#define AW88081_PWMCTRL4_REG (0x16)
+#define AW88081_I2SCFG1_REG (0x17)
+#define AW88081_DBGCTRL_REG (0x18)
+#define AW88081_PDMCTRL_REG (0x19)
+#define AW88081_DACST_REG (0x20)
+#define AW88081_PATTERNST_REG (0x21)
+#define AW88081_I2SINT_REG (0x26)
+#define AW88081_I2SCAPCNT_REG (0x27)
+#define AW88081_ANASTA1_REG (0x28)
+#define AW88081_ANASTA2_REG (0x29)
+#define AW88081_ANASTA3_REG (0x2A)
+#define AW88081_VBAT_REG (0x21)
+#define AW88081_TEMP_REG (0x22)
+#define AW88081_PVDD_REG (0x23)
+#define AW88081_ISNDAT_REG (0x24)
+#define AW88081_VSNDAT_REG (0x25)
+#define AW88081_DSMCFG1_REG (0x30)
+#define AW88081_DSMCFG2_REG (0x31)
+#define AW88081_DSMCFG3_REG (0x32)
+#define AW88081_DSMCFG4_REG (0x33)
+#define AW88081_DSMCFG5_REG (0x34)
+#define AW88081_DSMCFG6_REG (0x35)
+#define AW88081_DSMCFG7_REG (0x36)
+#define AW88081_DSMCFG8_REG (0x37)
+#define AW88081_TESTIN_REG (0x38)
+#define AW88081_TESTOUT_REG (0x39)
+#define AW88081_BOPCTRL1_REG (0x40)
+#define AW88081_BOPCTRL2_REG (0x41)
+#define AW88081_BOPCTRL3_REG (0x42)
+#define AW88081_BOPSTA_REG (0x43)
+#define AW88081_PLLCTRL1_REG (0x54)
+#define AW88081_PLLCTRL2_REG (0x55)
+#define AW88081_PLLCTRL3_REG (0x56)
+#define AW88081_CDACTRL1_REG (0x57)
+#define AW88081_CDACTRL2_REG (0x58)
+#define AW88081_CDACTRL3_REG (0x59)
+#define AW88081_DITHERCFG1_REG (0x5A)
+#define AW88081_DITHERCFG2_REG (0x5B)
+#define AW88081_DITHERCFG3_REG (0x5C)
+#define AW88081_TM_REG (0x6E)
+#define AW88081_TM2_REG (0x6F)
+#define AW88081_TESTCTRL1_REG (0x70)
+#define AW88081_TESTCTRL2_REG (0x71)
+
+#define AW88081_REG_MAX (0x72)
+
+#define AW88081_UVLS_START_BIT (14)
+#define AW88081_UVLS_UVLO (1)
+#define AW88081_UVLS_UVLO_VALUE \
+ (AW88081_UVLS_UVLO << AW88081_UVLS_START_BIT)
+
+#define AW88081_SWS_START_BIT (8)
+#define AW88081_SWS_SWITCHING (1)
+#define AW88081_SWS_SWITCHING_VALUE \
+ (AW88081_SWS_SWITCHING << AW88081_SWS_START_BIT)
+
+#define AW88081_NOCLKS_START_BIT (5)
+#define AW88081_NOCLKS_NO_CLOCK (1)
+#define AW88081_NOCLKS_NO_CLOCK_VALUE \
+ (AW88081_NOCLKS_NO_CLOCK << AW88081_NOCLKS_START_BIT)
+
+#define AW88081_CLKS_START_BIT (4)
+#define AW88081_CLKS_STABLE (1)
+#define AW88081_CLKS_STABLE_VALUE \
+ (AW88081_CLKS_STABLE << AW88081_CLKS_START_BIT)
+
+#define AW88081_OCDS_START_BIT (3)
+#define AW88081_OCDS_OC (1)
+#define AW88081_OCDS_OC_VALUE \
+ (AW88081_OCDS_OC << AW88081_OCDS_START_BIT)
+
+#define AW88081_OTHS_START_BIT (1)
+#define AW88081_OTHS_OT (1)
+#define AW88081_OTHS_OT_VALUE \
+ (AW88081_OTHS_OT << AW88081_OTHS_START_BIT)
+
+#define AW88081_PLLS_START_BIT (0)
+#define AW88081_PLLS_LOCKED (1)
+#define AW88081_PLLS_LOCKED_VALUE \
+ (AW88081_PLLS_LOCKED << AW88081_PLLS_START_BIT)
+
+#define AW88081_BIT_PLL_CHECK \
+ (AW88081_CLKS_STABLE_VALUE | \
+ AW88081_PLLS_LOCKED_VALUE)
+
+#define AW88081_BIT_SYSST_CHECK_MASK \
+ (~(AW88081_UVLS_UVLO_VALUE | \
+ AW88081_SWS_SWITCHING_VALUE | \
+ AW88081_NOCLKS_NO_CLOCK_VALUE | \
+ AW88081_CLKS_STABLE_VALUE | \
+ AW88081_OCDS_OC_VALUE | \
+ AW88081_OTHS_OT_VALUE | \
+ AW88081_PLLS_LOCKED_VALUE))
+
+#define AW88081_NO_SWS_SYSST_CHECK \
+ (AW88081_CLKS_STABLE_VALUE | \
+ AW88081_PLLS_LOCKED_VALUE)
+
+#define AW88081_SWS_SYSST_CHECK \
+ (AW88081_SWS_SWITCHING_VALUE | \
+ AW88081_CLKS_STABLE_VALUE | \
+ AW88081_PLLS_LOCKED_VALUE)
+
+#define AW88081_ULS_HMUTE_START_BIT (14)
+#define AW88081_ULS_HMUTE_BITS_LEN (1)
+#define AW88081_ULS_HMUTE_MASK \
+ (~(((1<<AW88081_ULS_HMUTE_BITS_LEN)-1) << AW88081_ULS_HMUTE_START_BIT))
+
+#define AW88081_ULS_HMUTE_DISABLE (0)
+#define AW88081_ULS_HMUTE_DISABLE_VALUE \
+ (AW88081_ULS_HMUTE_DISABLE << AW88081_ULS_HMUTE_START_BIT)
+
+#define AW88081_ULS_HMUTE_ENABLE (1)
+#define AW88081_ULS_HMUTE_ENABLE_VALUE \
+ (AW88081_ULS_HMUTE_ENABLE << AW88081_ULS_HMUTE_START_BIT)
+
+#define AW88081_HMUTE_START_BIT (8)
+#define AW88081_HMUTE_BITS_LEN (1)
+#define AW88081_HMUTE_MASK \
+ (~(((1<<AW88081_HMUTE_BITS_LEN)-1) << AW88081_HMUTE_START_BIT))
+
+#define AW88081_HMUTE_DISABLE (0)
+#define AW88081_HMUTE_DISABLE_VALUE \
+ (AW88081_HMUTE_DISABLE << AW88081_HMUTE_START_BIT)
+
+#define AW88081_HMUTE_ENABLE (1)
+#define AW88081_HMUTE_ENABLE_VALUE \
+ (AW88081_HMUTE_ENABLE << AW88081_HMUTE_START_BIT)
+
+#define AW88081_EN_PA_START_BIT (1)
+#define AW88081_EN_PA_BITS_LEN (1)
+#define AW88081_EN_PA_MASK \
+ (~(((1<<AW88081_EN_PA_BITS_LEN)-1) << AW88081_EN_PA_START_BIT))
+
+#define AW88081_EN_PA_WORKING (1)
+#define AW88081_EN_PA_WORKING_VALUE \
+ (AW88081_EN_PA_WORKING << AW88081_EN_PA_START_BIT)
+
+#define AW88081_EN_PA_POWER_DOWN (0)
+#define AW88081_EN_PA_POWER_DOWN_VALUE \
+ (AW88081_EN_PA_POWER_DOWN << AW88081_EN_PA_START_BIT)
+
+#define AW88081_PWDN_START_BIT (0)
+#define AW88081_PWDN_BITS_LEN (1)
+#define AW88081_PWDN_MASK \
+ (~(((1<<AW88081_PWDN_BITS_LEN)-1) << AW88081_PWDN_START_BIT))
+
+#define AW88081_PWDN_WORKING (0)
+#define AW88081_PWDN_WORKING_VALUE \
+ (AW88081_PWDN_WORKING << AW88081_PWDN_START_BIT)
+
+#define AW88081_PWDN_POWER_DOWN (1)
+#define AW88081_PWDN_POWER_DOWN_VALUE \
+ (AW88081_PWDN_POWER_DOWN << AW88081_PWDN_START_BIT)
+
+#define AW88081_VOL_START_BIT (0)
+#define AW88081_VOL_BITS_LEN (10)
+#define AW88081_VOL_MASK \
+ (~(((1<<AW88081_VOL_BITS_LEN)-1) << AW88081_VOL_START_BIT))
+
+#define AW88081_VOLUME_STEP_DB (64)
+#define AW88081_MUTE_VOL (1023)
+
+#define AW88081_I2STXEN_START_BIT (6)
+#define AW88081_I2STXEN_BITS_LEN (1)
+#define AW88081_I2STXEN_MASK \
+ (~(((1<<AW88081_I2STXEN_BITS_LEN)-1) << AW88081_I2STXEN_START_BIT))
+
+#define AW88081_I2STXEN_DISABLE (0)
+#define AW88081_I2STXEN_DISABLE_VALUE \
+ (AW88081_I2STXEN_DISABLE << AW88081_I2STXEN_START_BIT)
+
+#define AW88081_I2STXEN_ENABLE (1)
+#define AW88081_I2STXEN_ENABLE_VALUE \
+ (AW88081_I2STXEN_ENABLE << AW88081_I2STXEN_START_BIT)
+
+#define AW88081_NOISE_GATE_EN_START_BIT (13)
+#define AW88081_NOISE_GATE_EN_BITS_LEN (1)
+#define AW88081_NOISE_GATE_EN_MASK \
+ (~(((1<<AW88081_NOISE_GATE_EN_BITS_LEN)-1) << AW88081_NOISE_GATE_EN_START_BIT))
+
+#define AW88081_NOISE_GATE_EN_DISABLE (0)
+#define AW88081_NOISE_GATE_EN_DISABLE_VALUE \
+ (AW88081_NOISE_GATE_EN_DISABLE << AW88081_NOISE_GATE_EN_START_BIT)
+
+#define AW88081_NOISE_GATE_EN_ENABLE (1)
+#define AW88081_NOISE_GATE_EN_ENABLE_VALUE \
+ (AW88081_NOISE_GATE_EN_ENABLE << AW88081_NOISE_GATE_EN_START_BIT)
+
+#define AW88081_CCO_MUX_START_BIT (13)
+#define AW88081_CCO_MUX_BITS_LEN (1)
+#define AW88081_CCO_MUX_MASK \
+ (~(((1<<AW88081_CCO_MUX_BITS_LEN)-1) << AW88081_CCO_MUX_START_BIT))
+
+#define AW88081_CCO_MUX_DIVIDED (0)
+#define AW88081_CCO_MUX_DIVIDED_VALUE \
+ (AW88081_CCO_MUX_DIVIDED << AW88081_CCO_MUX_START_BIT)
+
+#define AW88081_CCO_MUX_BYPASS (1)
+#define AW88081_CCO_MUX_BYPASS_VALUE \
+ (AW88081_CCO_MUX_BYPASS << AW88081_CCO_MUX_START_BIT)
+
+#define AW88081_START_RETRIES (5)
+#define AW88081_START_WORK_DELAY_MS (0)
+
+#define AW88081_I2C_NAME "aw88081"
+#define AW88081_CHIP_ID 0x2116
+
+#define AW88081_RATES (SNDRV_PCM_RATE_8000_48000 | \
+ SNDRV_PCM_RATE_96000)
+#define AW88081_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define FADE_TIME_MAX 100000
+
+#define AW88081_DEV_DEFAULT_CH (0)
+#define AW88081_ACF_FILE "aw88081_acf.bin"
+#define AW88081_DEV_SYSST_CHECK_MAX (10)
+#define AW88081_SOFT_RESET_VALUE (0x55aa)
+
+#define AW88081_INIT_PROFILE (0)
+
+#define AW88081_PROFILE_EXT(xname, profile_info, profile_get, profile_set) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .info = profile_info, \
+ .get = profile_get, \
+ .put = profile_set, \
+}
+
+enum {
+ AW88081_SYNC_START = 0,
+ AW88081_ASYNC_START,
+};
+
+enum {
+ AW88081_500_US = 500,
+ AW88081_1000_US = 1000,
+ AW88081_2000_US = 2000,
+ AW88081_5000_US = 5000,
+};
+
+enum {
+ AW88081_DEV_PW_OFF = 0,
+ AW88081_DEV_PW_ON,
+};
+
+enum {
+ AW88081_DEV_FW_FAILED = 0,
+ AW88081_DEV_FW_OK,
+};
+
+#endif
diff --git a/sound/soc/codecs/aw88395/aw88395_device.c b/sound/soc/codecs/aw88395/aw88395_device.c
index fd1f67d5f22f..6b333d1c6e94 100644
--- a/sound/soc/codecs/aw88395/aw88395_device.c
+++ b/sound/soc/codecs/aw88395/aw88395_device.c
@@ -703,7 +703,7 @@ static int aw_dev_set_vcalb(struct aw_device *aw_dev)
AW88395_VSCAL_FACTOR_DAC, icalk, vcalk);
break;
default:
- dev_err(aw_dev->dev, "unsupport vsense status");
+ dev_err(aw_dev->dev, "unsupported vsense status");
return -EINVAL;
}
diff --git a/sound/soc/codecs/aw88395/aw88395_lib.c b/sound/soc/codecs/aw88395/aw88395_lib.c
index 769ca32a5c8e..ceb7fc43d018 100644
--- a/sound/soc/codecs/aw88395/aw88395_lib.c
+++ b/sound/soc/codecs/aw88395/aw88395_lib.c
@@ -688,7 +688,7 @@ static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev,
ret = aw_dev_cfg_get_reg_valid_prof(aw_dev, all_prof_info);
break;
default:
- dev_err(aw_dev->dev, "unsupport data type\n");
+ dev_err(aw_dev->dev, "unsupported data type\n");
ret = -EINVAL;
break;
}
diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c
index bba59885242d..ee3cc2a95f85 100644
--- a/sound/soc/codecs/aw88399.c
+++ b/sound/soc/codecs/aw88399.c
@@ -462,7 +462,7 @@ static int aw_dev_set_vcalb(struct aw88399 *aw88399)
vcal_k * aw88399->vcalb_init_val;
break;
default:
- dev_err(aw_dev->dev, "%s: unsupport vsense\n", __func__);
+ dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__);
ret = -EINVAL;
break;
}
diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
index 4f9dabd9d78a..04304a7ad915 100644
--- a/sound/soc/codecs/cpcap.c
+++ b/sound/soc/codecs/cpcap.c
@@ -1649,7 +1649,7 @@ static int cpcap_soc_probe(struct snd_soc_component *component)
return cpcap_audio_reset(component, false);
}
-static struct snd_soc_component_driver soc_codec_dev_cpcap = {
+static const struct snd_soc_component_driver soc_codec_dev_cpcap = {
.probe = cpcap_soc_probe,
.controls = cpcap_snd_controls,
.num_controls = ARRAY_SIZE(cpcap_snd_controls),
diff --git a/sound/soc/codecs/cs-amp-lib-test.c b/sound/soc/codecs/cs-amp-lib-test.c
index a6e8348a1bd5..45626f99a417 100644
--- a/sound/soc/codecs/cs-amp-lib-test.c
+++ b/sound/soc/codecs/cs-amp-lib-test.c
@@ -756,7 +756,7 @@ static struct kunit_suite cs_amp_lib_test_suite = {
kunit_test_suite(cs_amp_lib_test_suite);
-MODULE_IMPORT_NS(SND_SOC_CS_AMP_LIB);
+MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
MODULE_DESCRIPTION("KUnit test for Cirrus Logic amplifier library");
MODULE_AUTHOR("Richard Fitzgerald <[email protected]>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c
index 51b128c80671..c677868c5d5f 100644
--- a/sound/soc/codecs/cs-amp-lib.c
+++ b/sound/soc/codecs/cs-amp-lib.c
@@ -97,7 +97,7 @@ int cs_amp_write_cal_coeffs(struct cs_dsp *dsp,
else
return -ENODEV;
}
-EXPORT_SYMBOL_NS_GPL(cs_amp_write_cal_coeffs, SND_SOC_CS_AMP_LIB);
+EXPORT_SYMBOL_NS_GPL(cs_amp_write_cal_coeffs, "SND_SOC_CS_AMP_LIB");
static efi_status_t cs_amp_get_efi_variable(efi_char16_t *name,
efi_guid_t *guid,
@@ -270,7 +270,7 @@ int cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_
else
return -ENOENT;
}
-EXPORT_SYMBOL_NS_GPL(cs_amp_get_efi_calibration_data, SND_SOC_CS_AMP_LIB);
+EXPORT_SYMBOL_NS_GPL(cs_amp_get_efi_calibration_data, "SND_SOC_CS_AMP_LIB");
static const struct cs_amp_test_hooks cs_amp_test_hook_ptrs = {
.get_efi_variable = cs_amp_get_efi_variable,
@@ -279,9 +279,9 @@ static const struct cs_amp_test_hooks cs_amp_test_hook_ptrs = {
const struct cs_amp_test_hooks * const cs_amp_test_hooks =
PTR_IF(IS_ENABLED(CONFIG_SND_SOC_CS_AMP_LIB_TEST), &cs_amp_test_hook_ptrs);
-EXPORT_SYMBOL_NS_GPL(cs_amp_test_hooks, SND_SOC_CS_AMP_LIB);
+EXPORT_SYMBOL_NS_GPL(cs_amp_test_hooks, "SND_SOC_CS_AMP_LIB");
MODULE_DESCRIPTION("Cirrus Logic amplifier library");
MODULE_AUTHOR("Richard Fitzgerald <[email protected]>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(FW_CS_DSP);
+MODULE_IMPORT_NS("FW_CS_DSP");
diff --git a/sound/soc/codecs/cs35l45-i2c.c b/sound/soc/codecs/cs35l45-i2c.c
index f5fc42dcc8c7..a09aa3b92ae1 100644
--- a/sound/soc/codecs/cs35l45-i2c.c
+++ b/sound/soc/codecs/cs35l45-i2c.c
@@ -73,4 +73,4 @@ module_i2c_driver(cs35l45_i2c_driver);
MODULE_DESCRIPTION("I2C CS35L45 driver");
MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <[email protected]>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_CS35L45);
+MODULE_IMPORT_NS("SND_SOC_CS35L45");
diff --git a/sound/soc/codecs/cs35l45-spi.c b/sound/soc/codecs/cs35l45-spi.c
index 39e203a5f060..5f91472c3fd2 100644
--- a/sound/soc/codecs/cs35l45-spi.c
+++ b/sound/soc/codecs/cs35l45-spi.c
@@ -75,4 +75,4 @@ module_spi_driver(cs35l45_spi_driver);
MODULE_DESCRIPTION("SPI CS35L45 driver");
MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <[email protected]>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_CS35L45);
+MODULE_IMPORT_NS("SND_SOC_CS35L45");
diff --git a/sound/soc/codecs/cs35l45-tables.c b/sound/soc/codecs/cs35l45-tables.c
index 405dab137b3b..d2ecc7b3f619 100644
--- a/sound/soc/codecs/cs35l45-tables.c
+++ b/sound/soc/codecs/cs35l45-tables.c
@@ -38,7 +38,7 @@ int cs35l45_apply_patch(struct cs35l45_private *cs35l45)
return regmap_register_patch(cs35l45->regmap, cs35l45_patch,
ARRAY_SIZE(cs35l45_patch));
}
-EXPORT_SYMBOL_NS_GPL(cs35l45_apply_patch, SND_SOC_CS35L45);
+EXPORT_SYMBOL_NS_GPL(cs35l45_apply_patch, "SND_SOC_CS35L45");
static const struct reg_default cs35l45_defaults[] = {
{ CS35L45_BLOCK_ENABLES, 0x00003323 },
@@ -260,7 +260,7 @@ const struct regmap_config cs35l45_i2c_regmap = {
.readable_reg = cs35l45_readable_reg,
.cache_type = REGCACHE_MAPLE,
};
-EXPORT_SYMBOL_NS_GPL(cs35l45_i2c_regmap, SND_SOC_CS35L45);
+EXPORT_SYMBOL_NS_GPL(cs35l45_i2c_regmap, "SND_SOC_CS35L45");
const struct regmap_config cs35l45_spi_regmap = {
.reg_bits = 32,
@@ -276,7 +276,7 @@ const struct regmap_config cs35l45_spi_regmap = {
.readable_reg = cs35l45_readable_reg,
.cache_type = REGCACHE_MAPLE,
};
-EXPORT_SYMBOL_NS_GPL(cs35l45_spi_regmap, SND_SOC_CS35L45);
+EXPORT_SYMBOL_NS_GPL(cs35l45_spi_regmap, "SND_SOC_CS35L45");
static const struct {
u8 cfg_id;
@@ -329,4 +329,4 @@ int cs35l45_get_clk_freq_id(unsigned int freq)
return -EINVAL;
}
-EXPORT_SYMBOL_NS_GPL(cs35l45_get_clk_freq_id, SND_SOC_CS35L45);
+EXPORT_SYMBOL_NS_GPL(cs35l45_get_clk_freq_id, "SND_SOC_CS35L45");
diff --git a/sound/soc/codecs/cs35l45.c b/sound/soc/codecs/cs35l45.c
index fa1d9d9151f9..432a19f4de2b 100644
--- a/sound/soc/codecs/cs35l45.c
+++ b/sound/soc/codecs/cs35l45.c
@@ -1486,7 +1486,7 @@ err:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs35l45_probe, SND_SOC_CS35L45);
+EXPORT_SYMBOL_NS_GPL(cs35l45_probe, "SND_SOC_CS35L45");
void cs35l45_remove(struct cs35l45_private *cs35l45)
{
@@ -1501,7 +1501,7 @@ void cs35l45_remove(struct cs35l45_private *cs35l45)
/* VDD_BATT must be the last to power-off */
regulator_disable(cs35l45->vdd_batt);
}
-EXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45);
+EXPORT_SYMBOL_NS_GPL(cs35l45_remove, "SND_SOC_CS35L45");
EXPORT_GPL_DEV_PM_OPS(cs35l45_pm_ops) = {
RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL)
diff --git a/sound/soc/codecs/cs35l56-i2c.c b/sound/soc/codecs/cs35l56-i2c.c
index 2bd2ff75cd50..8a518df1e16e 100644
--- a/sound/soc/codecs/cs35l56-i2c.c
+++ b/sound/soc/codecs/cs35l56-i2c.c
@@ -84,8 +84,8 @@ static struct i2c_driver cs35l56_i2c_driver = {
module_i2c_driver(cs35l56_i2c_driver);
MODULE_DESCRIPTION("ASoC CS35L56 I2C driver");
-MODULE_IMPORT_NS(SND_SOC_CS35L56_CORE);
-MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED);
+MODULE_IMPORT_NS("SND_SOC_CS35L56_CORE");
+MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
MODULE_AUTHOR("Richard Fitzgerald <[email protected]>");
MODULE_AUTHOR("Simon Trimmer <[email protected]>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c
index 7c9a17fe2195..3f91cb3f9ae7 100644
--- a/sound/soc/codecs/cs35l56-sdw.c
+++ b/sound/soc/codecs/cs35l56-sdw.c
@@ -582,8 +582,8 @@ static struct sdw_driver cs35l56_sdw_driver = {
module_sdw_driver(cs35l56_sdw_driver);
MODULE_DESCRIPTION("ASoC CS35L56 SoundWire driver");
-MODULE_IMPORT_NS(SND_SOC_CS35L56_CORE);
-MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED);
+MODULE_IMPORT_NS("SND_SOC_CS35L56_CORE");
+MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
MODULE_AUTHOR("Richard Fitzgerald <[email protected]>");
MODULE_AUTHOR("Simon Trimmer <[email protected]>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index e45e9ae01bc6..e0ed4fc11155 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -49,7 +49,7 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base)
return regmap_register_patch(cs35l56_base->regmap, cs35l56_patch,
ARRAY_SIZE(cs35l56_patch));
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, "SND_SOC_CS35L56_SHARED");
static const struct reg_default cs35l56_reg_defaults[] = {
/* no defaults for OTP_MEM - first read populates cache */
@@ -241,7 +241,7 @@ int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, "SND_SOC_CS35L56_SHARED");
int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base)
{
@@ -261,7 +261,7 @@ int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base)
val, ret);
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_firmware_shutdown, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_firmware_shutdown, "SND_SOC_CS35L56_SHARED");
int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base)
{
@@ -287,21 +287,21 @@ int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_wait_for_firmware_boot, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_wait_for_firmware_boot, "SND_SOC_CS35L56_SHARED");
void cs35l56_wait_control_port_ready(void)
{
/* Wait for control port to be ready (datasheet tIRS). */
usleep_range(CS35L56_CONTROL_PORT_READY_US, 2 * CS35L56_CONTROL_PORT_READY_US);
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_wait_control_port_ready, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_wait_control_port_ready, "SND_SOC_CS35L56_SHARED");
void cs35l56_wait_min_reset_pulse(void)
{
/* Satisfy minimum reset pulse width spec */
usleep_range(CS35L56_RESET_PULSE_MIN_US, 2 * CS35L56_RESET_PULSE_MIN_US);
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_wait_min_reset_pulse, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_wait_min_reset_pulse, "SND_SOC_CS35L56_SHARED");
static const struct reg_sequence cs35l56_system_reset_seq[] = {
REG_SEQ0(CS35L56_DSP1_HALO_STATE, 0),
@@ -327,7 +327,7 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire)
/* Leave in cache-only. This will be revoked when the chip has rebooted. */
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, "SND_SOC_CS35L56_SHARED");
int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq)
{
@@ -346,7 +346,7 @@ int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq)
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, "SND_SOC_CS35L56_SHARED");
irqreturn_t cs35l56_irq(int irq, void *data)
{
@@ -413,7 +413,7 @@ err_unlock:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_irq, "SND_SOC_CS35L56_SHARED");
int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base)
{
@@ -444,7 +444,7 @@ int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base)
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_is_fw_reload_needed, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_is_fw_reload_needed, "SND_SOC_CS35L56_SHARED");
static const struct reg_sequence cs35l56_hibernate_seq[] = {
/* This must be the last register access */
@@ -513,7 +513,7 @@ int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend_common, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend_common, "SND_SOC_CS35L56_SHARED");
int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire)
{
@@ -565,7 +565,7 @@ err:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, "SND_SOC_CS35L56_SHARED");
static const struct cs_dsp_region cs35l56_dsp1_regions[] = {
{ .type = WMFW_HALO_PM_PACKED, .base = CS35L56_DSP1_PMEM_0 },
@@ -588,7 +588,7 @@ void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_ds
cs_dsp->num_mems = ARRAY_SIZE(cs35l56_dsp1_regions);
cs_dsp->no_core_startstop = true;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_init_cs_dsp, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_init_cs_dsp, "SND_SOC_CS35L56_SHARED");
struct cs35l56_pte {
u8 x;
@@ -634,7 +634,7 @@ const struct cirrus_amp_cal_controls cs35l56_calibration_controls = {
.status = "CAL_STATUS",
.checksum = "CAL_CHECKSUM",
};
-EXPORT_SYMBOL_NS_GPL(cs35l56_calibration_controls, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_calibration_controls, "SND_SOC_CS35L56_SHARED");
int cs35l56_get_calibration(struct cs35l56_base *cs35l56_base)
{
@@ -664,7 +664,7 @@ int cs35l56_get_calibration(struct cs35l56_base *cs35l56_base)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_get_calibration, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_get_calibration, "SND_SOC_CS35L56_SHARED");
int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base,
bool *fw_missing, unsigned int *fw_version)
@@ -688,7 +688,7 @@ int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base,
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_read_prot_status, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_read_prot_status, "SND_SOC_CS35L56_SHARED");
int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
{
@@ -774,7 +774,7 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, "SND_SOC_CS35L56_SHARED");
int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base)
{
@@ -816,7 +816,7 @@ err:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_get_speaker_id, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_get_speaker_id, "SND_SOC_CS35L56_SHARED");
static const u32 cs35l56_bclk_valid_for_pll_freq_table[] = {
[0x0C] = 128000,
@@ -865,7 +865,7 @@ int cs35l56_get_bclk_freq_id(unsigned int freq)
return -EINVAL;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_get_bclk_freq_id, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_get_bclk_freq_id, "SND_SOC_CS35L56_SHARED");
static const char * const cs35l56_supplies[/* auto-sized */] = {
"VDD_P",
@@ -881,7 +881,7 @@ void cs35l56_fill_supply_names(struct regulator_bulk_data *data)
for (i = 0; i < ARRAY_SIZE(cs35l56_supplies); i++)
data[i].supply = cs35l56_supplies[i];
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_fill_supply_names, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_fill_supply_names, "SND_SOC_CS35L56_SHARED");
const char * const cs35l56_tx_input_texts[] = {
"None", "ASP1RX1", "ASP1RX2", "VMON", "IMON", "ERRVOL", "CLASSH",
@@ -889,7 +889,7 @@ const char * const cs35l56_tx_input_texts[] = {
"DSP1TX5", "DSP1TX6", "DSP1TX7", "DSP1TX8", "TEMPMON",
"INTERPOLATOR", "SDW1RX1", "SDW1RX2",
};
-EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_texts, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_texts, "SND_SOC_CS35L56_SHARED");
const unsigned int cs35l56_tx_input_values[] = {
CS35L56_INPUT_SRC_NONE,
@@ -914,7 +914,7 @@ const unsigned int cs35l56_tx_input_values[] = {
CS35L56_INPUT_SRC_SWIRE_DP1_CHANNEL1,
CS35L56_INPUT_SRC_SWIRE_DP1_CHANNEL2,
};
-EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_values, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_values, "SND_SOC_CS35L56_SHARED");
const struct regmap_config cs35l56_regmap_i2c = {
.reg_bits = 32,
@@ -930,7 +930,7 @@ const struct regmap_config cs35l56_regmap_i2c = {
.precious_reg = cs35l56_precious_reg,
.cache_type = REGCACHE_MAPLE,
};
-EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_i2c, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_i2c, "SND_SOC_CS35L56_SHARED");
const struct regmap_config cs35l56_regmap_spi = {
.reg_bits = 32,
@@ -947,7 +947,7 @@ const struct regmap_config cs35l56_regmap_spi = {
.precious_reg = cs35l56_precious_reg,
.cache_type = REGCACHE_MAPLE,
};
-EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_spi, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_spi, "SND_SOC_CS35L56_SHARED");
const struct regmap_config cs35l56_regmap_sdw = {
.reg_bits = 32,
@@ -963,10 +963,10 @@ const struct regmap_config cs35l56_regmap_sdw = {
.precious_reg = cs35l56_precious_reg,
.cache_type = REGCACHE_MAPLE,
};
-EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_sdw, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_sdw, "SND_SOC_CS35L56_SHARED");
MODULE_DESCRIPTION("ASoC CS35L56 Shared");
MODULE_AUTHOR("Richard Fitzgerald <[email protected]>");
MODULE_AUTHOR("Simon Trimmer <[email protected]>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_CS_AMP_LIB);
+MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
diff --git a/sound/soc/codecs/cs35l56-spi.c b/sound/soc/codecs/cs35l56-spi.c
index b07b798b0b45..c101134e8532 100644
--- a/sound/soc/codecs/cs35l56-spi.c
+++ b/sound/soc/codecs/cs35l56-spi.c
@@ -82,8 +82,8 @@ static struct spi_driver cs35l56_spi_driver = {
module_spi_driver(cs35l56_spi_driver);
MODULE_DESCRIPTION("ASoC CS35L56 SPI driver");
-MODULE_IMPORT_NS(SND_SOC_CS35L56_CORE);
-MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED);
+MODULE_IMPORT_NS("SND_SOC_CS35L56_CORE");
+MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
MODULE_AUTHOR("Richard Fitzgerald <[email protected]>");
MODULE_AUTHOR("Simon Trimmer <[email protected]>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index 757ade6373ed..ae045c88c48d 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -1341,7 +1341,7 @@ err:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_common_probe, SND_SOC_CS35L56_CORE);
+EXPORT_SYMBOL_NS_GPL(cs35l56_common_probe, "SND_SOC_CS35L56_CORE");
int cs35l56_init(struct cs35l56_private *cs35l56)
{
@@ -1422,7 +1422,7 @@ post_soft_reset:
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_init, SND_SOC_CS35L56_CORE);
+EXPORT_SYMBOL_NS_GPL(cs35l56_init, "SND_SOC_CS35L56_CORE");
void cs35l56_remove(struct cs35l56_private *cs35l56)
{
@@ -1447,7 +1447,7 @@ void cs35l56_remove(struct cs35l56_private *cs35l56)
gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_remove, SND_SOC_CS35L56_CORE);
+EXPORT_SYMBOL_NS_GPL(cs35l56_remove, "SND_SOC_CS35L56_CORE");
#if IS_ENABLED(CONFIG_SND_SOC_CS35L56_I2C) || IS_ENABLED(CONFIG_SND_SOC_CS35L56_SPI)
EXPORT_NS_GPL_DEV_PM_OPS(cs35l56_pm_ops_i2c_spi, SND_SOC_CS35L56_CORE) = {
@@ -1459,8 +1459,8 @@ EXPORT_NS_GPL_DEV_PM_OPS(cs35l56_pm_ops_i2c_spi, SND_SOC_CS35L56_CORE) = {
#endif
MODULE_DESCRIPTION("ASoC CS35L56 driver");
-MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED);
-MODULE_IMPORT_NS(SND_SOC_CS_AMP_LIB);
+MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
+MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
MODULE_AUTHOR("Richard Fitzgerald <[email protected]>");
MODULE_AUTHOR("Simon Trimmer <[email protected]>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l42-i2c.c b/sound/soc/codecs/cs42l42-i2c.c
index 8d10f9328e02..8a1d5c7a61d7 100644
--- a/sound/soc/codecs/cs42l42-i2c.c
+++ b/sound/soc/codecs/cs42l42-i2c.c
@@ -101,4 +101,4 @@ module_i2c_driver(cs42l42_i2c_driver);
MODULE_DESCRIPTION("ASoC CS42L42 I2C driver");
MODULE_AUTHOR("Richard Fitzgerald <[email protected]>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE);
+MODULE_IMPORT_NS("SND_SOC_CS42L42_CORE");
diff --git a/sound/soc/codecs/cs42l42-sdw.c b/sound/soc/codecs/cs42l42-sdw.c
index 29891c1f6bec..ae1401b250a3 100644
--- a/sound/soc/codecs/cs42l42-sdw.c
+++ b/sound/soc/codecs/cs42l42-sdw.c
@@ -622,4 +622,4 @@ module_sdw_driver(cs42l42_sdw_driver);
MODULE_DESCRIPTION("ASoC CS42L42 SoundWire driver");
MODULE_AUTHOR("Richard Fitzgerald <[email protected]>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE);
+MODULE_IMPORT_NS("SND_SOC_CS42L42_CORE");
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 6400ac875e6f..501c951cc327 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -329,7 +329,7 @@ bool cs42l42_readable_register(struct device *dev, unsigned int reg)
return false;
}
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_readable_register, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_readable_register, "SND_SOC_CS42L42_CORE");
bool cs42l42_volatile_register(struct device *dev, unsigned int reg)
{
@@ -363,7 +363,7 @@ bool cs42l42_volatile_register(struct device *dev, unsigned int reg)
return false;
}
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_volatile_register, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_volatile_register, "SND_SOC_CS42L42_CORE");
const struct regmap_range_cfg cs42l42_page_range = {
.name = "Pages",
@@ -375,7 +375,7 @@ const struct regmap_range_cfg cs42l42_page_range = {
.window_start = 0,
.window_len = 256,
};
-EXPORT_SYMBOL_NS_GPL(cs42l42_page_range, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_page_range, "SND_SOC_CS42L42_CORE");
const struct regmap_config cs42l42_regmap = {
.reg_bits = 8,
@@ -395,7 +395,7 @@ const struct regmap_config cs42l42_regmap = {
.use_single_read = true,
.use_single_write = true,
};
-EXPORT_SYMBOL_NS_GPL(cs42l42_regmap, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_regmap, "SND_SOC_CS42L42_CORE");
static DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 100, true);
static DECLARE_TLV_DB_SCALE(mixer_tlv, -6300, 100, true);
@@ -596,7 +596,7 @@ const struct snd_soc_component_driver cs42l42_soc_component = {
.num_controls = ARRAY_SIZE(cs42l42_snd_controls),
.endianness = 1,
};
-EXPORT_SYMBOL_NS_GPL(cs42l42_soc_component, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_soc_component, "SND_SOC_CS42L42_CORE");
/* Switch to SCLK. Atomic delay after the write to allow the switch to complete. */
static const struct reg_sequence cs42l42_to_sclk_seq[] = {
@@ -748,7 +748,7 @@ int cs42l42_pll_config(struct snd_soc_component *component, unsigned int clk,
return -EINVAL;
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_pll_config, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_pll_config, "SND_SOC_CS42L42_CORE");
void cs42l42_src_config(struct snd_soc_component *component, unsigned int sample_rate)
{
@@ -782,7 +782,7 @@ void cs42l42_src_config(struct snd_soc_component *component, unsigned int sample
CS42L42_CLK_OASRC_SEL_MASK,
fs << CS42L42_CLK_OASRC_SEL_SHIFT);
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_src_config, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_src_config, "SND_SOC_CS42L42_CORE");
static int cs42l42_asp_config(struct snd_soc_component *component,
unsigned int sclk, unsigned int sample_rate)
@@ -1116,7 +1116,7 @@ int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_mute_stream, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_mute_stream, "SND_SOC_CS42L42_CORE");
#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
@@ -1151,7 +1151,7 @@ struct snd_soc_dai_driver cs42l42_dai = {
.symmetric_sample_bits = 1,
.ops = &cs42l42_ops,
};
-EXPORT_SYMBOL_NS_GPL(cs42l42_dai, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_dai, "SND_SOC_CS42L42_CORE");
static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42)
{
@@ -1780,7 +1780,7 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data)
return IRQ_HANDLED;
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_irq_thread, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_irq_thread, "SND_SOC_CS42L42_CORE");
static void cs42l42_set_interrupt_masks(struct cs42l42_private *cs42l42)
{
@@ -2211,7 +2211,7 @@ int cs42l42_suspend(struct device *dev)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_suspend, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_suspend, "SND_SOC_CS42L42_CORE");
int cs42l42_resume(struct device *dev)
{
@@ -2242,7 +2242,7 @@ int cs42l42_resume(struct device *dev)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_resume, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_resume, "SND_SOC_CS42L42_CORE");
void cs42l42_resume_restore(struct device *dev)
{
@@ -2261,7 +2261,7 @@ void cs42l42_resume_restore(struct device *dev)
dev_dbg(dev, "System resumed\n");
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_resume_restore, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_resume_restore, "SND_SOC_CS42L42_CORE");
static int __maybe_unused cs42l42_i2c_resume(struct device *dev)
{
@@ -2370,7 +2370,7 @@ err_disable_noreset:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_common_probe, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_common_probe, "SND_SOC_CS42L42_CORE");
int cs42l42_init(struct cs42l42_private *cs42l42)
{
@@ -2464,7 +2464,7 @@ err_disable:
cs42l42->supplies);
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_init, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_init, "SND_SOC_CS42L42_CORE");
void cs42l42_common_remove(struct cs42l42_private *cs42l42)
{
@@ -2484,7 +2484,7 @@ void cs42l42_common_remove(struct cs42l42_private *cs42l42)
gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies);
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_common_remove, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_common_remove, "SND_SOC_CS42L42_CORE");
MODULE_DESCRIPTION("ASoC CS42L42 driver");
MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <[email protected]>");
diff --git a/sound/soc/codecs/cs42l43-sdw.c b/sound/soc/codecs/cs42l43-sdw.c
index 60c00c05da05..336e88a7a987 100644
--- a/sound/soc/codecs/cs42l43-sdw.c
+++ b/sound/soc/codecs/cs42l43-sdw.c
@@ -42,7 +42,7 @@ int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream,
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_add_peripheral, SND_SOC_CS42L43);
+EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_add_peripheral, "SND_SOC_CS42L43");
int cs42l43_sdw_remove_peripheral(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
@@ -56,7 +56,7 @@ int cs42l43_sdw_remove_peripheral(struct snd_pcm_substream *substream,
return sdw_stream_remove_slave(sdw, sdw_stream);
}
-EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_remove_peripheral, SND_SOC_CS42L43);
+EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_remove_peripheral, "SND_SOC_CS42L43");
int cs42l43_sdw_set_stream(struct snd_soc_dai *dai, void *sdw_stream, int direction)
{
@@ -64,7 +64,7 @@ int cs42l43_sdw_set_stream(struct snd_soc_dai *dai, void *sdw_stream, int direct
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_set_stream, SND_SOC_CS42L43);
+EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_set_stream, "SND_SOC_CS42L43");
MODULE_DESCRIPTION("CS42L43 CODEC SoundWire Driver");
MODULE_AUTHOR("Charles Keepax <[email protected]>");
diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c
index d0098b4558b5..4236f78beec0 100644
--- a/sound/soc/codecs/cs42l43.c
+++ b/sound/soc/codecs/cs42l43.c
@@ -2402,49 +2402,7 @@ static int cs42l43_codec_runtime_resume(struct device *dev)
return 0;
}
-static int cs42l43_codec_suspend(struct device *dev)
-{
- struct cs42l43_codec *priv = dev_get_drvdata(dev);
- struct cs42l43 *cs42l43 = priv->core;
-
- disable_irq(cs42l43->irq);
-
- return 0;
-}
-
-static int cs42l43_codec_suspend_noirq(struct device *dev)
-{
- struct cs42l43_codec *priv = dev_get_drvdata(dev);
- struct cs42l43 *cs42l43 = priv->core;
-
- enable_irq(cs42l43->irq);
-
- return 0;
-}
-
-static int cs42l43_codec_resume(struct device *dev)
-{
- struct cs42l43_codec *priv = dev_get_drvdata(dev);
- struct cs42l43 *cs42l43 = priv->core;
-
- enable_irq(cs42l43->irq);
-
- return 0;
-}
-
-static int cs42l43_codec_resume_noirq(struct device *dev)
-{
- struct cs42l43_codec *priv = dev_get_drvdata(dev);
- struct cs42l43 *cs42l43 = priv->core;
-
- disable_irq(cs42l43->irq);
-
- return 0;
-}
-
static const struct dev_pm_ops cs42l43_codec_pm_ops = {
- SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend, cs42l43_codec_resume)
- NOIRQ_SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend_noirq, cs42l43_codec_resume_noirq)
RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL)
};
@@ -2466,7 +2424,7 @@ static struct platform_driver cs42l43_codec_driver = {
};
module_platform_driver(cs42l43_codec_driver);
-MODULE_IMPORT_NS(SND_SOC_CS42L43);
+MODULE_IMPORT_NS("SND_SOC_CS42L43");
MODULE_DESCRIPTION("CS42L43 CODEC Driver");
MODULE_AUTHOR("Charles Keepax <[email protected]>");
diff --git a/sound/soc/codecs/cs42l83-i2c.c b/sound/soc/codecs/cs42l83-i2c.c
index f482b6a4f5c3..42c3e1efdc08 100644
--- a/sound/soc/codecs/cs42l83-i2c.c
+++ b/sound/soc/codecs/cs42l83-i2c.c
@@ -237,4 +237,4 @@ module_i2c_driver(cs42l83_i2c_driver);
MODULE_DESCRIPTION("ASoC CS42L83 I2C driver");
MODULE_AUTHOR("Martin PoviÅ¡er <[email protected]>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE);
+MODULE_IMPORT_NS("SND_SOC_CS42L42_CORE");
diff --git a/sound/soc/codecs/cs42l84.c b/sound/soc/codecs/cs42l84.c
new file mode 100644
index 000000000000..17d5c96e334d
--- /dev/null
+++ b/sound/soc/codecs/cs42l84.c
@@ -0,0 +1,1111 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * cs42l84.c -- CS42L84 ALSA SoC audio driver
+ *
+ * Copyright (C) The Asahi Linux Contributors
+ *
+ * Based on sound/soc/codecs/cs42l42{.c,.h}
+ * Copyright 2016 Cirrus Logic, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "cs42l84.h"
+#include "cirrus_legacy.h"
+
+struct cs42l84_private {
+ struct regmap *regmap;
+ struct device *dev;
+ struct gpio_desc *reset_gpio;
+ struct snd_soc_jack *jack;
+ struct mutex irq_lock;
+ u8 tip_state;
+ u8 ring_state;
+ int pll_config;
+ int bclk;
+ u8 pll_mclk_f;
+ u32 srate;
+ u8 stream_use;
+ int hs_type;
+};
+
+static bool cs42l84_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42L84_DEVID ... CS42L84_DEVID+5:
+ case CS42L84_TSRS_PLUG_INT_STATUS:
+ case CS42L84_PLL_LOCK_STATUS:
+ case CS42L84_TSRS_PLUG_STATUS:
+ case CS42L84_HS_DET_STATUS2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config cs42l84_regmap = {
+ .reg_bits = 16,
+ .val_bits = 8,
+
+ .volatile_reg = cs42l84_volatile_register,
+
+ .max_register = 0x73fe,
+
+ .cache_type = REGCACHE_MAPLE,
+
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int cs42l84_put_dac_vol(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kctl);
+ struct soc_mixer_control *mc = (struct soc_mixer_control *) kctl->private_value;
+ int vola, volb;
+ int ret, ret2, updated = 0;
+
+ vola = val->value.integer.value[0] + mc->min;
+ volb = val->value.integer.value[1] + mc->min;
+
+ if (vola < mc->min || vola > mc->max || volb < mc->min || volb > mc->max)
+ return -EINVAL;
+
+ ret = snd_soc_component_update_bits(component, CS42L84_FRZ_CTL,
+ CS42L84_FRZ_CTL_ENGAGE,
+ CS42L84_FRZ_CTL_ENGAGE);
+ if (ret < 0)
+ goto bail;
+ updated |= ret;
+
+ ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHA_VOL_LSB,
+ 0xff, vola & 0xff);
+ if (ret < 0)
+ goto bail;
+ updated |= ret;
+
+ ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHA_VOL_MSB,
+ 0xff, (vola >> 8) & 0x01);
+ if (ret < 0)
+ goto bail;
+ updated |= ret;
+
+ ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHB_VOL_LSB,
+ 0xff, volb & 0xff);
+ if (ret < 0)
+ goto bail;
+ updated |= ret;
+
+ ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHB_VOL_MSB,
+ 0xff, (volb >> 8) & 0x01);
+ if (ret < 0)
+ goto bail;
+ ret |= updated;
+
+bail:
+ ret2 = snd_soc_component_update_bits(component, CS42L84_FRZ_CTL,
+ CS42L84_FRZ_CTL_ENGAGE, 0);
+ if (ret2 < 0 && ret >= 0)
+ ret = ret2;
+
+ return ret;
+}
+
+static int cs42l84_get_dac_vol(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kctl);
+ struct soc_mixer_control *mc = (struct soc_mixer_control *) kctl->private_value;
+ int vola, volb;
+ int ret;
+
+ ret = snd_soc_component_read(component, CS42L84_DAC_CHA_VOL_LSB);
+ if (ret < 0)
+ return ret;
+ vola = ret;
+
+ ret = snd_soc_component_read(component, CS42L84_DAC_CHA_VOL_MSB);
+ if (ret < 0)
+ return ret;
+ vola |= (ret & 1) << 8;
+
+ ret = snd_soc_component_read(component, CS42L84_DAC_CHB_VOL_LSB);
+ if (ret < 0)
+ return ret;
+ volb = ret;
+
+ ret = snd_soc_component_read(component, CS42L84_DAC_CHB_VOL_MSB);
+ if (ret < 0)
+ return ret;
+ volb |= (ret & 1) << 8;
+
+ if (vola & BIT(8))
+ vola |= ~((int)(BIT(8) - 1));
+ if (volb & BIT(8))
+ volb |= ~((int)(BIT(8) - 1));
+
+ val->value.integer.value[0] = vola - mc->min;
+ val->value.integer.value[1] = volb - mc->min;
+
+ return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(cs42l84_dac_tlv, -12800, 50, true);
+static const DECLARE_TLV_DB_SCALE(cs42l84_adc_tlv, -1200, 50, false);
+static const DECLARE_TLV_DB_SCALE(cs42l84_pre_tlv, 0, 1000, false);
+
+static const struct snd_kcontrol_new cs42l84_snd_controls[] = {
+ SOC_DOUBLE_R_S_EXT_TLV("DAC Playback Volume", CS42L84_DAC_CHA_VOL_LSB,
+ CS42L84_DAC_CHB_VOL_LSB, 0, -256, 24, 8, 0,
+ cs42l84_get_dac_vol, cs42l84_put_dac_vol, cs42l84_dac_tlv),
+ SOC_SINGLE_TLV("ADC Preamp Capture Volume", CS42L84_ADC_CTL1,
+ CS42L84_ADC_CTL1_PREAMP_GAIN_SHIFT, 2, 0, cs42l84_pre_tlv),
+ SOC_SINGLE_TLV("ADC PGA Capture Volume", CS42L84_ADC_CTL1,
+ CS42L84_ADC_CTL1_PGA_GAIN_SHIFT, 24, 0, cs42l84_adc_tlv),
+ SOC_SINGLE("ADC WNF Switch", CS42L84_ADC_CTL4,
+ CS42L84_ADC_CTL4_WNF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("WNF Corner Frequency", CS42L84_ADC_CTL4,
+ CS42L84_ADC_CTL4_WNF_CF_SHIFT, 3, 0),
+ SOC_SINGLE("ADC HPF Switch", CS42L84_ADC_CTL4,
+ CS42L84_ADC_CTL4_HPF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("HPF Corner Frequency", CS42L84_ADC_CTL4,
+ CS42L84_ADC_CTL4_HPF_CF_SHIFT, 3, 0),
+};
+
+static const char * const cs42l84_mux_text[] = {
+ "Blank", "ADC", "ASP RX CH1", "ASP RX CH2",
+};
+
+static const unsigned int cs42l84_mux_values[] = {
+ 0b0000, 0b0111, 0b1101, 0b1110,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_daca_mux_enum,
+ CS42L84_BUS_DAC_SRC, CS42L84_BUS_DAC_SRC_DACA_SHIFT,
+ 0b1111, cs42l84_mux_text, cs42l84_mux_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_dacb_mux_enum,
+ CS42L84_BUS_DAC_SRC, CS42L84_BUS_DAC_SRC_DACB_SHIFT,
+ 0b1111, cs42l84_mux_text, cs42l84_mux_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_sdout1_mux_enum,
+ CS42L84_BUS_ASP_TX_SRC, CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT,
+ 0b1111, cs42l84_mux_text, cs42l84_mux_values);
+
+static const struct snd_kcontrol_new cs42l84_daca_mux_ctrl =
+ SOC_DAPM_ENUM("DACA Select", cs42l84_daca_mux_enum);
+
+static const struct snd_kcontrol_new cs42l84_dacb_mux_ctrl =
+ SOC_DAPM_ENUM("DACB Select", cs42l84_dacb_mux_enum);
+
+static const struct snd_kcontrol_new cs42l84_sdout1_mux_ctrl =
+ SOC_DAPM_ENUM("SDOUT1 Select", cs42l84_sdout1_mux_enum);
+
+static const struct snd_soc_dapm_widget cs42l84_dapm_widgets[] = {
+ /* Playback Path */
+ SND_SOC_DAPM_OUTPUT("HP"),
+ SND_SOC_DAPM_DAC("DAC", NULL, CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_DAC_SHIFT, 0),
+ SND_SOC_DAPM_MUX("DACA Select", SND_SOC_NOPM, 0, 0, &cs42l84_daca_mux_ctrl),
+ SND_SOC_DAPM_MUX("DACB Select", SND_SOC_NOPM, 0, 0, &cs42l84_dacb_mux_ctrl),
+ SND_SOC_DAPM_AIF_IN("SDIN1", NULL, 0, CS42L84_ASP_RX_EN, CS42L84_ASP_RX_EN_CH1_SHIFT, 0),
+ SND_SOC_DAPM_AIF_IN("SDIN2", NULL, 1, CS42L84_ASP_RX_EN, CS42L84_ASP_RX_EN_CH2_SHIFT, 0),
+
+ /* Capture Path */
+ SND_SOC_DAPM_INPUT("HS"),
+ SND_SOC_DAPM_ADC("ADC", NULL, CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_ADC_SHIFT, 0),
+ SND_SOC_DAPM_MUX("SDOUT1 Select", SND_SOC_NOPM, 0, 0, &cs42l84_sdout1_mux_ctrl),
+ SND_SOC_DAPM_AIF_OUT("SDOUT1", NULL, 0, CS42L84_ASP_TX_EN, CS42L84_ASP_TX_EN_CH1_SHIFT, 0),
+
+ /* Playback/Capture Requirements */
+ SND_SOC_DAPM_SUPPLY("BUS", CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_BUS_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ASP", CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_ASP_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BCLK", CS42L84_ASP_CTL, CS42L84_ASP_CTL_BCLK_EN_SHIFT, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route cs42l84_audio_map[] = {
+ /* Playback Path */
+ {"HP", NULL, "DAC"},
+ {"DAC", NULL, "DACA Select"},
+ {"DAC", NULL, "DACB Select"},
+ {"DACA Select", "ASP RX CH1", "SDIN1"},
+ {"DACA Select", "ASP RX CH2", "SDIN2"},
+ {"DACB Select", "ASP RX CH1", "SDIN1"},
+ {"DACB Select", "ASP RX CH2", "SDIN2"},
+ {"SDIN1", NULL, "Playback"},
+ {"SDIN2", NULL, "Playback"},
+
+ {"ADC", NULL, "HS"},
+ {"SDOUT1 Select", "ADC", "ADC"},
+ {"SDOUT1", NULL, "SDOUT1 Select"},
+ {"Capture", NULL, "SDOUT1"},
+
+ /* Playback Requirements */
+ {"DAC", NULL, "BUS"},
+ {"SDIN1", NULL, "ASP"},
+ {"SDIN2", NULL, "ASP"},
+ {"SDIN1", NULL, "BCLK"},
+ {"SDIN2", NULL, "BCLK"},
+
+ /* Capture Requirements */
+ {"SDOUT1", NULL, "BUS"},
+ {"SDOUT1", NULL, "ASP"},
+ {"SDOUT1", NULL, "BCLK"},
+};
+
+static int cs42l84_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jk, void *d)
+{
+ struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component);
+
+ /* Prevent race with interrupt handler */
+ mutex_lock(&cs42l84->irq_lock);
+ cs42l84->jack = jk;
+ snd_soc_jack_report(jk, cs42l84->hs_type, SND_JACK_HEADSET);
+ mutex_unlock(&cs42l84->irq_lock);
+
+ return 0;
+}
+
+static int cs42l84_component_probe(struct snd_soc_component *component)
+{
+ snd_soc_component_update_bits(component, CS42L84_ASP_CTL,
+ CS42L84_ASP_CTL_TDM_MODE, 0);
+ snd_soc_component_update_bits(component, CS42L84_HP_VOL_CTL,
+ CS42L84_HP_VOL_CTL_SOFT | CS42L84_HP_VOL_CTL_ZERO_CROSS,
+ CS42L84_HP_VOL_CTL_ZERO_CROSS);
+
+ /* TDM settings */
+ snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH1_CTL1,
+ CS42L84_ASP_RX_CHx_CTL1_EDGE |
+ CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, 0);
+ snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH1_CTL2,
+ CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0);
+ snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH2_CTL1,
+ CS42L84_ASP_RX_CHx_CTL1_EDGE |
+ CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB,
+ CS42L84_ASP_RX_CHx_CTL1_EDGE);
+ snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH2_CTL2,
+ CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0);
+ snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH1_CTL1,
+ CS42L84_ASP_RX_CHx_CTL1_EDGE | \
+ CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, 0);
+ snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH1_CTL2,
+ CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0);
+ snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH2_CTL1,
+ CS42L84_ASP_RX_CHx_CTL1_EDGE | \
+ CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB,
+ CS42L84_ASP_RX_CHx_CTL1_EDGE);
+ snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH2_CTL2,
+ CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0);
+ /* Routing defaults */
+ snd_soc_component_write(component, CS42L84_BUS_DAC_SRC,
+ 0b1101 << CS42L84_BUS_DAC_SRC_DACA_SHIFT |
+ 0b1110 << CS42L84_BUS_DAC_SRC_DACB_SHIFT);
+ snd_soc_component_write(component, CS42L84_BUS_ASP_TX_SRC,
+ 0b0111 << CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_cs42l84 = {
+ .set_jack = cs42l84_set_jack,
+ .probe = cs42l84_component_probe,
+ .controls = cs42l84_snd_controls,
+ .num_controls = ARRAY_SIZE(cs42l84_snd_controls),
+ .dapm_widgets = cs42l84_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs42l84_dapm_widgets),
+ .dapm_routes = cs42l84_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(cs42l84_audio_map),
+ .endianness = 1,
+};
+
+struct cs42l84_pll_params {
+ u32 bclk;
+ u8 mclk_src_sel;
+ u8 bclk_prediv;
+ u8 pll_div_int;
+ u32 pll_div_frac;
+ u8 pll_mode;
+ u8 pll_divout;
+ u32 mclk_int;
+};
+
+/*
+ * Common PLL Settings for given BCLK
+ */
+static const struct cs42l84_pll_params pll_ratio_table[] = {
+ { 3072000, 1, 0, 0x40, 0x000000, 0x03, 0x10, 12288000},
+ { 6144000, 1, 1, 0x40, 0x000000, 0x03, 0x10, 12288000},
+ { 12288000, 0, 0, 0, 0, 0, 0, 12288000},
+ { 24576000, 1, 3, 0x40, 0x000000, 0x03, 0x10, 12288000},
+};
+
+static int cs42l84_pll_config(struct snd_soc_component *component)
+{
+ struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component);
+ int i;
+ u32 clk;
+ u32 fsync;
+
+ clk = cs42l84->bclk;
+
+ /* Don't reconfigure if there is an audio stream running */
+ if (cs42l84->stream_use) {
+ if (pll_ratio_table[cs42l84->pll_config].bclk == clk)
+ return 0;
+ else
+ return -EBUSY;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
+ if (pll_ratio_table[i].bclk == clk) {
+ cs42l84->pll_config = i;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(pll_ratio_table))
+ return -EINVAL;
+
+ /* Set up the LRCLK */
+ fsync = clk / cs42l84->srate;
+ if (((fsync * cs42l84->srate) != clk)
+ || ((fsync % 2) != 0)) {
+ dev_err(component->dev,
+ "Unsupported bclk %d/sample rate %d\n",
+ clk, cs42l84->srate);
+ return -EINVAL;
+ }
+
+ /* Set the LRCLK period */
+ snd_soc_component_update_bits(component, CS42L84_ASP_FSYNC_CTL2,
+ CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO,
+ FIELD_PREP(CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO, fsync & 0x7f));
+ snd_soc_component_update_bits(component, CS42L84_ASP_FSYNC_CTL3,
+ CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI,
+ FIELD_PREP(CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI, fsync >> 7));
+
+ /* Save what the MCLK will be */
+ switch (pll_ratio_table[i].mclk_int) {
+ case 12000000:
+ cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_12MHZ;
+ break;
+ case 12288000:
+ cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_12_288KHZ;
+ break;
+ case 24000000:
+ cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_24MHZ;
+ break;
+ case 24576000:
+ cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_24_576KHZ;
+ break;
+ }
+
+ snd_soc_component_update_bits(component, CS42L84_PLL_CTL1, CS42L84_PLL_CTL1_EN, 0);
+
+ if (pll_ratio_table[i].mclk_src_sel) {
+ /* Configure PLL */
+ snd_soc_component_update_bits(component,
+ CS42L84_CCM_CTL3, CS42L84_CCM_CTL3_REFCLK_DIV,
+ FIELD_PREP(CS42L84_CCM_CTL3_REFCLK_DIV, pll_ratio_table[i].bclk_prediv));
+ snd_soc_component_write(component,
+ CS42L84_PLL_DIV_INT,
+ pll_ratio_table[i].pll_div_int);
+ snd_soc_component_write(component,
+ CS42L84_PLL_DIV_FRAC0,
+ pll_ratio_table[i].pll_div_frac);
+ snd_soc_component_write(component,
+ CS42L84_PLL_DIV_FRAC1,
+ pll_ratio_table[i].pll_div_frac >> 8);
+ snd_soc_component_write(component,
+ CS42L84_PLL_DIV_FRAC2,
+ pll_ratio_table[i].pll_div_frac >> 16);
+ snd_soc_component_update_bits(component,
+ CS42L84_PLL_CTL1, CS42L84_PLL_CTL1_MODE,
+ FIELD_PREP(CS42L84_PLL_CTL1_MODE, pll_ratio_table[i].pll_mode));
+ snd_soc_component_write(component,
+ CS42L84_PLL_DIVOUT,
+ pll_ratio_table[i].pll_divout);
+ }
+
+ return 0;
+}
+
+static int cs42l84_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Bitclock/frame inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cs42l84_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 cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component);
+ int ret;
+ u32 ccm_samp_rate;
+
+ cs42l84->srate = params_rate(params);
+
+ ret = cs42l84_pll_config(component);
+ if (ret)
+ return ret;
+
+ switch (params_rate(params)) {
+ case 44100:
+ ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_44K1HZ;
+ break;
+ case 48000:
+ ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_48KHZ;
+ break;
+ case 88200:
+ ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_88K2HZ;
+ break;
+ case 96000:
+ ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_96KHZ;
+ break;
+ case 176400:
+ ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_176K4HZ;
+ break;
+ case 192000:
+ ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_192KHZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_write(component, CS42L84_CCM_SAMP_RATE, ccm_samp_rate);
+
+ switch (substream->stream) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ snd_soc_component_write(component, CS42L84_ASP_RX_CH1_WIDTH,
+ params_width(params) - 1);
+ snd_soc_component_write(component, CS42L84_ASP_RX_CH2_WIDTH,
+ params_width(params) - 1);
+ break;
+
+ case SNDRV_PCM_STREAM_CAPTURE:
+ snd_soc_component_write(component, CS42L84_ASP_TX_CH1_WIDTH,
+ params_width(params) - 1);
+ snd_soc_component_write(component, CS42L84_ASP_TX_CH2_WIDTH,
+ params_width(params) - 1);
+ break;
+ }
+
+ return 0;
+}
+
+static int cs42l84_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component);
+ int i;
+
+ if (freq == 0) {
+ cs42l84->bclk = 0;
+ return 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
+ if (pll_ratio_table[i].bclk == freq) {
+ cs42l84->bclk = freq;
+ return 0;
+ }
+ }
+
+ dev_err(component->dev, "BCLK %u not supported\n", freq);
+
+ return -EINVAL;
+}
+
+static int cs42l84_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component);
+ unsigned int regval;
+ int ret;
+
+ if (mute) {
+ /* Mute the headphone */
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_component_update_bits(component, CS42L84_DAC_CTL1,
+ CS42L84_DAC_CTL1_UNMUTE, 0);
+ cs42l84->stream_use &= ~(1 << stream);
+ if (!cs42l84->stream_use) {
+ /* Must disconnect PLL before stopping it */
+ snd_soc_component_write(component, CS42L84_CCM_CTL1,
+ CS42L84_CCM_CTL1_RCO);
+
+ usleep_range(150, 300);
+
+ snd_soc_component_update_bits(component, CS42L84_PLL_CTL1,
+ CS42L84_PLL_CTL1_EN, 0);
+
+ snd_soc_component_update_bits(component, CS42L84_CCM_CTL4,
+ CS42L84_CCM_CTL4_REFCLK_EN, 0);
+ }
+ } else {
+ if (!cs42l84->stream_use) {
+ /* SCLK must be running before codec unmute.
+ *
+ * Note carried over from CS42L42:
+ *
+ * PLL must not be started with ADC and HP both off
+ * otherwise the FILT+ supply will not charge properly.
+ * DAPM widgets power-up before stream unmute so at least
+ * one of the "DAC" or "ADC" widgets will already have
+ * powered-up.
+ */
+
+ snd_soc_component_update_bits(component, CS42L84_CCM_CTL4,
+ CS42L84_CCM_CTL4_REFCLK_EN,
+ CS42L84_CCM_CTL4_REFCLK_EN);
+
+ if (pll_ratio_table[cs42l84->pll_config].mclk_src_sel) {
+ snd_soc_component_update_bits(component, CS42L84_PLL_CTL1,
+ CS42L84_PLL_CTL1_EN,
+ CS42L84_PLL_CTL1_EN);
+ /* TODO: should we be doing something with divout here? */
+
+ ret = regmap_read_poll_timeout(cs42l84->regmap,
+ CS42L84_PLL_LOCK_STATUS,
+ regval,
+ (regval & CS42L84_PLL_LOCK_STATUS_LOCKED),
+ CS42L84_PLL_LOCK_POLL_US,
+ CS42L84_PLL_LOCK_TIMEOUT_US);
+ if (ret < 0)
+ dev_warn(component->dev, "PLL failed to lock: %d\n", ret);
+
+ if (regval & CS42L84_PLL_LOCK_STATUS_ERROR)
+ dev_warn(component->dev, "PLL lock error\n");
+
+ /* PLL must be running to drive glitchless switch logic */
+ snd_soc_component_update_bits(component,
+ CS42L84_CCM_CTL1,
+ CS42L84_CCM_CTL1_MCLK_SRC | CS42L84_CCM_CTL1_MCLK_FREQ,
+ FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_PLL)
+ | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, cs42l84->pll_mclk_f));
+ usleep_range(CS42L84_CLOCK_SWITCH_DELAY_US, CS42L84_CLOCK_SWITCH_DELAY_US*2);
+ } else {
+ snd_soc_component_update_bits(component,
+ CS42L84_CCM_CTL1,
+ CS42L84_CCM_CTL1_MCLK_SRC | CS42L84_CCM_CTL1_MCLK_FREQ,
+ FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_BCLK)
+ | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, cs42l84->pll_mclk_f));
+ usleep_range(CS42L84_CLOCK_SWITCH_DELAY_US, CS42L84_CLOCK_SWITCH_DELAY_US*2);
+ }
+ }
+ cs42l84->stream_use |= 1 << stream;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ /* Un-mute the headphone */
+ snd_soc_component_update_bits(component, CS42L84_DAC_CTL1,
+ CS42L84_DAC_CTL1_UNMUTE,
+ CS42L84_DAC_CTL1_UNMUTE);
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops cs42l84_ops = {
+ .hw_params = cs42l84_pcm_hw_params,
+ .set_fmt = cs42l84_set_dai_fmt,
+ .set_sysclk = cs42l84_set_sysclk,
+ .mute_stream = cs42l84_mute_stream,
+};
+
+#define CS42L84_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver cs42l84_dai = {
+ .name = "cs42l84",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000,
+ .formats = CS42L84_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000,
+ .formats = CS42L84_FORMATS,
+ },
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+ .ops = &cs42l84_ops,
+};
+
+struct cs42l84_irq_params {
+ u16 status_addr;
+ u16 mask_addr;
+ u8 mask;
+};
+
+static const struct cs42l84_irq_params irq_params_table[] = {
+ {CS42L84_TSRS_PLUG_INT_STATUS, CS42L84_TSRS_PLUG_INT_MASK,
+ CS42L84_TSRS_PLUG_VAL_MASK}
+};
+
+static void cs42l84_detect_hs(struct cs42l84_private *cs42l84)
+{
+ unsigned int reg;
+
+ /* Power up HSBIAS */
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_MISC_DET_CTL,
+ CS42L84_MISC_DET_CTL_HSBIAS_CTL | CS42L84_MISC_DET_CTL_DETECT_MODE,
+ FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 3) | /* 2.7 V */
+ FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 0));
+
+ /* Power up level detection circuitry */
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_MISC_DET_CTL,
+ CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET, 0);
+
+ /* TODO: Optimize */
+ msleep(50);
+
+ /* Connect HSBIAS in CTIA wiring */
+ /* TODO: Should likely be subject of detection */
+ regmap_write(cs42l84->regmap,
+ CS42L84_HS_SWITCH_CTL,
+ CS42L84_HS_SWITCH_CTL_REF_HS3 | \
+ CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \
+ CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \
+ CS42L84_HS_SWITCH_CTL_HSB_HS4);
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_HS_DET_CTL2,
+ CS42L84_HS_DET_CTL2_SET,
+ FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 0));
+
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_MISC_DET_CTL,
+ CS42L84_MISC_DET_CTL_DETECT_MODE,
+ FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 3));
+
+ /* TODO: Optimize */
+ msleep(50);
+
+ regmap_read(cs42l84->regmap, CS42L84_HS_DET_STATUS2, &reg);
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_MISC_DET_CTL,
+ CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET,
+ CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET);
+
+ switch (reg & 0b11) {
+ case 0b11: /* shorted */
+ case 0b00: /* open */
+ /* Power down HSBIAS */
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_MISC_DET_CTL,
+ CS42L84_MISC_DET_CTL_HSBIAS_CTL,
+ FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 1)); /* 0.0 V */
+ break;
+ }
+
+ switch (reg & 0b11) {
+ case 0b10: /* load */
+ dev_dbg(cs42l84->dev, "Detected mic\n");
+ cs42l84->hs_type = SND_JACK_HEADSET;
+ snd_soc_jack_report(cs42l84->jack, SND_JACK_HEADSET,
+ SND_JACK_HEADSET);
+ break;
+
+ case 0b00: /* open */
+ dev_dbg(cs42l84->dev, "Detected open circuit on HS4\n");
+ fallthrough;
+ case 0b11: /* shorted */
+ default:
+ snd_soc_jack_report(cs42l84->jack, SND_JACK_HEADPHONE,
+ SND_JACK_HEADSET);
+ cs42l84->hs_type = SND_JACK_HEADPHONE;
+ dev_dbg(cs42l84->dev, "Detected bare headphone (no mic)\n");
+ break;
+ }
+}
+
+static void cs42l84_revert_hs(struct cs42l84_private *cs42l84)
+{
+ /* Power down HSBIAS */
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_MISC_DET_CTL,
+ CS42L84_MISC_DET_CTL_HSBIAS_CTL | CS42L84_MISC_DET_CTL_DETECT_MODE,
+ FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 1) | /* 0.0 V */
+ FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 0));
+
+ /* Disconnect HSBIAS */
+ regmap_write(cs42l84->regmap,
+ CS42L84_HS_SWITCH_CTL,
+ CS42L84_HS_SWITCH_CTL_REF_HS3 | \
+ CS42L84_HS_SWITCH_CTL_REF_HS4 | \
+ CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \
+ CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 | \
+ CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \
+ CS42L84_HS_SWITCH_CTL_GNDHS_HS4);
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_HS_DET_CTL2,
+ CS42L84_HS_DET_CTL2_SET,
+ FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 2));
+}
+
+static void cs42l84_set_interrupt_masks(struct cs42l84_private *cs42l84,
+ unsigned int val)
+{
+ regmap_update_bits(cs42l84->regmap, CS42L84_TSRS_PLUG_INT_MASK,
+ CS42L84_RS_PLUG | CS42L84_RS_UNPLUG |
+ CS42L84_TS_PLUG | CS42L84_TS_UNPLUG,
+ val);
+}
+
+static irqreturn_t cs42l84_irq_thread(int irq, void *data)
+{
+ struct cs42l84_private *cs42l84 = (struct cs42l84_private *)data;
+ unsigned int stickies[1];
+ unsigned int masks[1];
+ unsigned int reg;
+ u8 current_tip_state;
+ u8 current_ring_state;
+ int i;
+
+ mutex_lock(&cs42l84->irq_lock);
+ /* Read sticky registers to clear interrupt */
+ for (i = 0; i < ARRAY_SIZE(stickies); i++) {
+ regmap_read(cs42l84->regmap, irq_params_table[i].status_addr,
+ &(stickies[i]));
+ regmap_read(cs42l84->regmap, irq_params_table[i].mask_addr,
+ &(masks[i]));
+ stickies[i] = stickies[i] & (~masks[i]) &
+ irq_params_table[i].mask;
+ }
+
+ /* When handling plug sene IRQs, we only care about EITHER tip OR ring.
+ * Ring is useless on remove, and is only useful on insert for
+ * detecting if the plug state has changed AFTER we have handled the
+ * tip sense IRQ, e.g. if the plug was not fully seated within the tip
+ * sense debounce time.
+ */
+
+ if ((~masks[0]) & irq_params_table[0].mask) {
+ regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, &reg);
+
+ current_tip_state = (((char) reg) &
+ (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >>
+ CS42L84_TS_PLUG_SHIFT;
+
+ if (current_tip_state != cs42l84->tip_state) {
+ cs42l84->tip_state = current_tip_state;
+ switch (current_tip_state) {
+ case CS42L84_PLUG:
+ dev_dbg(cs42l84->dev, "Plug event\n");
+
+ cs42l84_detect_hs(cs42l84);
+
+ /*
+ * Check the tip sense status again, and possibly invalidate
+ * the detection result
+ *
+ * Thanks to debounce, this should reliably indicate if the tip
+ * was disconnected at any point during the detection procedure.
+ */
+ regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, &reg);
+ current_tip_state = (((char) reg) &
+ (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >>
+ CS42L84_TS_PLUG_SHIFT;
+ if (current_tip_state != CS42L84_PLUG) {
+ dev_dbg(cs42l84->dev, "Wobbly connection, detection invalidated\n");
+ cs42l84->tip_state = CS42L84_UNPLUG;
+ cs42l84_revert_hs(cs42l84);
+ }
+
+ /* Unmask ring sense interrupts */
+ cs42l84_set_interrupt_masks(cs42l84, 0);
+ break;
+ case CS42L84_UNPLUG:
+ cs42l84->ring_state = CS42L84_UNPLUG;
+ dev_dbg(cs42l84->dev, "Unplug event\n");
+
+ cs42l84_revert_hs(cs42l84);
+ cs42l84->hs_type = 0;
+ snd_soc_jack_report(cs42l84->jack, 0,
+ SND_JACK_HEADSET);
+
+ /* Mask ring sense interrupts */
+ cs42l84_set_interrupt_masks(cs42l84,
+ CS42L84_RS_PLUG | CS42L84_RS_UNPLUG);
+ break;
+ default:
+ cs42l84->ring_state = CS42L84_TRANS;
+ break;
+ }
+
+ mutex_unlock(&cs42l84->irq_lock);
+
+ return IRQ_HANDLED;
+ }
+
+ /* Tip state didn't change, we must've got a ring sense IRQ */
+ current_ring_state = (((char) reg) &
+ (CS42L84_RS_PLUG | CS42L84_RS_UNPLUG)) >>
+ CS42L84_RS_PLUG_SHIFT;
+
+ if (current_ring_state != cs42l84->ring_state) {
+ cs42l84->ring_state = current_ring_state;
+ if (current_ring_state == CS42L84_PLUG)
+ cs42l84_detect_hs(cs42l84);
+ }
+ }
+
+ mutex_unlock(&cs42l84->irq_lock);
+
+ return IRQ_HANDLED;
+}
+
+static void cs42l84_setup_plug_detect(struct cs42l84_private *cs42l84)
+{
+ unsigned int reg;
+
+ /* Set up plug detection */
+ regmap_update_bits(cs42l84->regmap, CS42L84_MIC_DET_CTL4,
+ CS42L84_MIC_DET_CTL4_LATCH_TO_VP,
+ CS42L84_MIC_DET_CTL4_LATCH_TO_VP);
+ regmap_update_bits(cs42l84->regmap, CS42L84_TIP_SENSE_CTL2,
+ CS42L84_TIP_SENSE_CTL2_MODE,
+ FIELD_PREP(CS42L84_TIP_SENSE_CTL2_MODE, CS42L84_TIP_SENSE_CTL2_MODE_SHORT_DET));
+ regmap_update_bits(cs42l84->regmap, CS42L84_RING_SENSE_CTL,
+ CS42L84_RING_SENSE_CTL_INV | CS42L84_RING_SENSE_CTL_UNK1 |
+ CS42L84_RING_SENSE_CTL_RISETIME | CS42L84_RING_SENSE_CTL_FALLTIME,
+ CS42L84_RING_SENSE_CTL_INV | CS42L84_RING_SENSE_CTL_UNK1 |
+ FIELD_PREP(CS42L84_RING_SENSE_CTL_RISETIME, CS42L84_DEBOUNCE_TIME_125MS) |
+ FIELD_PREP(CS42L84_RING_SENSE_CTL_FALLTIME, CS42L84_DEBOUNCE_TIME_125MS));
+ regmap_update_bits(cs42l84->regmap, CS42L84_TIP_SENSE_CTL,
+ CS42L84_TIP_SENSE_CTL_INV |
+ CS42L84_TIP_SENSE_CTL_RISETIME | CS42L84_TIP_SENSE_CTL_FALLTIME,
+ CS42L84_TIP_SENSE_CTL_INV |
+ FIELD_PREP(CS42L84_TIP_SENSE_CTL_RISETIME, CS42L84_DEBOUNCE_TIME_500MS) |
+ FIELD_PREP(CS42L84_TIP_SENSE_CTL_FALLTIME, CS42L84_DEBOUNCE_TIME_125MS));
+ regmap_update_bits(cs42l84->regmap, CS42L84_MSM_BLOCK_EN3,
+ CS42L84_MSM_BLOCK_EN3_TR_SENSE,
+ CS42L84_MSM_BLOCK_EN3_TR_SENSE);
+
+ /* Save the initial status of the tip sense */
+ regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, &reg);
+ cs42l84->tip_state = (((char) reg) &
+ (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >>
+ CS42L84_TS_PLUG_SHIFT;
+
+ /* Set mic-detection threshold */
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_MIC_DET_CTL1, CS42L84_MIC_DET_CTL1_HS_DET_LEVEL,
+ FIELD_PREP(CS42L84_MIC_DET_CTL1_HS_DET_LEVEL, 0x2c)); /* ~1.9 V */
+
+ /* Disconnect HSBIAS (initially) */
+ regmap_write(cs42l84->regmap,
+ CS42L84_HS_SWITCH_CTL,
+ CS42L84_HS_SWITCH_CTL_REF_HS3 | \
+ CS42L84_HS_SWITCH_CTL_REF_HS4 | \
+ CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \
+ CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 | \
+ CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \
+ CS42L84_HS_SWITCH_CTL_GNDHS_HS4);
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_HS_DET_CTL2,
+ CS42L84_HS_DET_CTL2_SET | CS42L84_HS_DET_CTL2_CTL,
+ FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 2) |
+ FIELD_PREP(CS42L84_HS_DET_CTL2_CTL, 0));
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_HS_CLAMP_DISABLE, 1, 1);
+
+}
+
+static int cs42l84_i2c_probe(struct i2c_client *i2c_client)
+{
+ struct cs42l84_private *cs42l84;
+ int ret, devid;
+ unsigned int reg;
+
+ cs42l84 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l84_private),
+ GFP_KERNEL);
+ if (!cs42l84)
+ return -ENOMEM;
+
+ cs42l84->dev = &i2c_client->dev;
+ i2c_set_clientdata(i2c_client, cs42l84);
+ mutex_init(&cs42l84->irq_lock);
+
+ cs42l84->regmap = devm_regmap_init_i2c(i2c_client, &cs42l84_regmap);
+ if (IS_ERR(cs42l84->regmap)) {
+ ret = PTR_ERR(cs42l84->regmap);
+ dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Reset the Device */
+ cs42l84->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+ "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(cs42l84->reset_gpio)) {
+ ret = PTR_ERR(cs42l84->reset_gpio);
+ goto err_disable_noreset;
+ }
+
+ if (cs42l84->reset_gpio) {
+ dev_dbg(&i2c_client->dev, "Found reset GPIO\n");
+ gpiod_set_value_cansleep(cs42l84->reset_gpio, 1);
+ }
+ usleep_range(CS42L84_BOOT_TIME_US, CS42L84_BOOT_TIME_US * 2);
+
+ /* Request IRQ if one was specified */
+ if (i2c_client->irq) {
+ ret = request_threaded_irq(i2c_client->irq,
+ NULL, cs42l84_irq_thread,
+ IRQF_ONESHOT,
+ "cs42l84", cs42l84);
+ if (ret == -EPROBE_DEFER) {
+ goto err_disable_noirq;
+ } else if (ret != 0) {
+ dev_err(&i2c_client->dev,
+ "Failed to request IRQ: %d\n", ret);
+ goto err_disable_noirq;
+ }
+ }
+
+ /* initialize codec */
+ devid = cirrus_read_device_id(cs42l84->regmap, CS42L84_DEVID);
+ if (devid < 0) {
+ ret = devid;
+ dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret);
+ goto err_disable;
+ }
+
+ if (devid != CS42L84_CHIP_ID) {
+ dev_err(&i2c_client->dev,
+ "CS42L84 Device ID (%X). Expected %X\n",
+ devid, CS42L84_CHIP_ID);
+ ret = -EINVAL;
+ goto err_disable;
+ }
+
+ ret = regmap_read(cs42l84->regmap, CS42L84_REVID, &reg);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+ goto err_shutdown;
+ }
+
+ dev_info(&i2c_client->dev,
+ "Cirrus Logic CS42L84, Revision: %02X\n", reg & 0xFF);
+
+ /* Setup plug detection */
+ cs42l84_setup_plug_detect(cs42l84);
+
+ /* Mask ring sense interrupts */
+ cs42l84_set_interrupt_masks(cs42l84, CS42L84_RS_PLUG | CS42L84_RS_UNPLUG);
+
+ /* Register codec for machine driver */
+ ret = devm_snd_soc_register_component(&i2c_client->dev,
+ &soc_component_dev_cs42l84, &cs42l84_dai, 1);
+ if (ret < 0)
+ goto err_shutdown;
+
+ return 0;
+
+err_shutdown:
+ /* Nothing to do */
+
+err_disable:
+ if (i2c_client->irq)
+ free_irq(i2c_client->irq, cs42l84);
+
+err_disable_noirq:
+ gpiod_set_value_cansleep(cs42l84->reset_gpio, 0);
+err_disable_noreset:
+ return ret;
+}
+
+static void cs42l84_i2c_remove(struct i2c_client *i2c_client)
+{
+ struct cs42l84_private *cs42l84 = i2c_get_clientdata(i2c_client);
+
+ if (i2c_client->irq)
+ free_irq(i2c_client->irq, cs42l84);
+
+ gpiod_set_value_cansleep(cs42l84->reset_gpio, 0);
+}
+
+static const struct of_device_id cs42l84_of_match[] = {
+ { .compatible = "cirrus,cs42l84", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cs42l84_of_match);
+
+static const struct i2c_device_id cs42l84_id[] = {
+ {"cs42l84", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs42l84_id);
+
+static struct i2c_driver cs42l84_i2c_driver = {
+ .driver = {
+ .name = "cs42l84",
+ .of_match_table = cs42l84_of_match,
+ },
+ .id_table = cs42l84_id,
+ .probe = cs42l84_i2c_probe,
+ .remove = cs42l84_i2c_remove,
+};
+
+module_i2c_driver(cs42l84_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L84 driver");
+MODULE_AUTHOR("Martin PoviÅ¡er <[email protected]>");
+MODULE_AUTHOR("Hector Martin <[email protected]>");
+MODULE_AUTHOR("James Calligeros <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l84.h b/sound/soc/codecs/cs42l84.h
new file mode 100644
index 000000000000..dbf778a902b9
--- /dev/null
+++ b/sound/soc/codecs/cs42l84.h
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) The Asahi Linux Contributors
+ *
+ * Based on sound/soc/codecs/cs42l42.h
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ */
+
+
+#ifndef __CS42L84_H__
+#define __CS42L84_H__
+
+#include <linux/bits.h>
+
+#define CS42L84_CHIP_ID 0x42a84
+
+#define CS42L84_DEVID 0x0000
+#define CS42L84_REVID 0x73fe
+#define CS42L84_FRZ_CTL 0x0006
+#define CS42L84_FRZ_CTL_ENGAGE BIT(0)
+
+#define CS42L84_TSRS_PLUG_INT_STATUS 0x0400
+#define CS42L84_TSRS_PLUG_INT_MASK 0x0418
+#define CS42L84_RS_PLUG_SHIFT 0
+#define CS42L84_RS_PLUG BIT(0)
+#define CS42L84_RS_UNPLUG BIT(1)
+#define CS42L84_TS_PLUG_SHIFT 2
+#define CS42L84_TS_PLUG BIT(2)
+#define CS42L84_TS_UNPLUG BIT(3)
+#define CS42L84_TSRS_PLUG_VAL_MASK GENMASK(3, 0)
+#define CS42L84_PLL_LOCK_STATUS 0x040e // probably bit 0x10
+#define CS42L84_PLL_LOCK_STATUS_LOCKED BIT(4)
+#define CS42L84_PLL_LOCK_STATUS_ERROR BIT(5)
+
+#define CS42L84_PLUG 3
+#define CS42L84_UNPLUG 0
+#define CS42L84_TRANS 1
+
+#define CS42L84_CCM_CTL1 0x0600
+#define CS42L84_CCM_CTL1_MCLK_SRC GENMASK(1, 0)
+#define CS42L84_CCM_CTL1_MCLK_SRC_RCO 0
+#define CS42L84_CCM_CTL1_MCLK_SRC_MCLK 1
+#define CS42L84_CCM_CTL1_MCLK_SRC_BCLK 2
+#define CS42L84_CCM_CTL1_MCLK_SRC_PLL 3
+#define CS42L84_CCM_CTL1_MCLK_FREQ GENMASK(3, 2)
+#define CS42L84_CCM_CTL1_MCLK_F_12MHZ 0b00
+#define CS42L84_CCM_CTL1_MCLK_F_24MHZ 0b01
+#define CS42L84_CCM_CTL1_MCLK_F_12_288KHZ 0b10
+#define CS42L84_CCM_CTL1_MCLK_F_24_576KHZ 0b11
+#define CS42L84_CCM_CTL1_RCO \
+ (FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_RCO) \
+ | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, CS42L84_CCM_CTL1_MCLK_F_12MHZ))
+
+#define CS42L84_CCM_SAMP_RATE 0x0601
+#define CS42L84_CCM_SAMP_RATE_RATE_48KHZ 4
+#define CS42L84_CCM_SAMP_RATE_RATE_96KHZ 5
+#define CS42L84_CCM_SAMP_RATE_RATE_192KHZ 6
+#define CS42L84_CCM_SAMP_RATE_RATE_44K1HZ 12
+#define CS42L84_CCM_SAMP_RATE_RATE_88K2HZ 13
+#define CS42L84_CCM_SAMP_RATE_RATE_176K4HZ 14
+#define CS42L84_CCM_CTL3 0x0602
+#define CS42L84_CCM_CTL3_REFCLK_DIV GENMASK(2, 1)
+#define CS42L84_CCM_CTL4 0x0603
+#define CS42L84_CCM_CTL4_REFCLK_EN BIT(0)
+
+#define CS42L84_CCM_ASP_CLK_CTRL 0x0608
+
+#define CS42L84_PLL_CTL1 0x0800
+#define CS42L84_PLL_CTL1_EN BIT(0)
+#define CS42L84_PLL_CTL1_MODE GENMASK(2, 1)
+#define CS42L84_PLL_DIV_FRAC0 0x0804
+#define CS42L84_PLL_DIV_FRAC1 0x0805
+#define CS42L84_PLL_DIV_FRAC2 0x0806
+#define CS42L84_PLL_DIV_INT 0x0807
+#define CS42L84_PLL_DIVOUT 0x0808
+
+#define CS42L84_RING_SENSE_CTL 0x1282
+#define CS42L84_RING_SENSE_CTL_INV BIT(7)
+#define CS42L84_RING_SENSE_CTL_UNK1 BIT(6)
+#define CS42L84_RING_SENSE_CTL_FALLTIME GENMASK(5, 3)
+#define CS42L84_RING_SENSE_CTL_RISETIME GENMASK(2, 0)
+#define CS42L84_TIP_SENSE_CTL 0x1283
+#define CS42L84_TIP_SENSE_CTL_INV BIT(7)
+#define CS42L84_TIP_SENSE_CTL_FALLTIME GENMASK(5, 3)
+#define CS42L84_TIP_SENSE_CTL_RISETIME GENMASK(2, 0)
+
+#define CS42L84_TSRS_PLUG_STATUS 0x1288
+
+#define CS42L84_TIP_SENSE_CTL2 0x1473
+#define CS42L84_TIP_SENSE_CTL2_MODE GENMASK(7, 6)
+#define CS42L84_TIP_SENSE_CTL2_MODE_DISABLED 0b00
+#define CS42L84_TIP_SENSE_CTL2_MODE_DIG_INPUT 0b01
+#define CS42L84_TIP_SENSE_CTL2_MODE_SHORT_DET 0b11
+#define CS42L84_TIP_SENSE_CTL2_INV BIT(5)
+
+#define CS42L84_MISC_DET_CTL 0x1474
+#define CS42L84_MISC_DET_CTL_DETECT_MODE GENMASK(4, 3)
+#define CS42L84_MISC_DET_CTL_HSBIAS_CTL GENMASK(2, 1)
+#define CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET BIT(0)
+
+#define CS42L84_MIC_DET_CTL1 0x1475
+#define CS42L84_MIC_DET_CTL1_HS_DET_LEVEL GENMASK(5, 0)
+
+#define CS42L84_MIC_DET_CTL4 0x1477
+#define CS42L84_MIC_DET_CTL4_LATCH_TO_VP BIT(1)
+
+#define CS42L84_HS_DET_STATUS2 0x147d
+
+#define CS42L84_MSM_BLOCK_EN1 0x1800
+#define CS42L84_MSM_BLOCK_EN2 0x1801
+#define CS42L84_MSM_BLOCK_EN2_ASP_SHIFT 6
+#define CS42L84_MSM_BLOCK_EN2_BUS_SHIFT 5
+#define CS42L84_MSM_BLOCK_EN2_DAC_SHIFT 4
+#define CS42L84_MSM_BLOCK_EN2_ADC_SHIFT 3
+#define CS42L84_MSM_BLOCK_EN3 0x1802
+#define CS42L84_MSM_BLOCK_EN3_TR_SENSE BIT(3)
+
+#define CS42L84_HS_DET_CTL2 0x1811
+#define CS42L84_HS_DET_CTL2_CTL GENMASK(7, 6)
+#define CS42L84_HS_DET_CTL2_SET GENMASK(5, 4)
+#define CS42L84_HS_DET_CTL2_REF BIT(3)
+#define CS42L84_HS_DET_CTL2_AUTO_TIME GENMASK(1, 0)
+
+#define CS42L84_HS_SWITCH_CTL 0x1812
+#define CS42L84_HS_SWITCH_CTL_REF_HS3 BIT(7)
+#define CS42L84_HS_SWITCH_CTL_REF_HS4 BIT(6)
+#define CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 BIT(5)
+#define CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 BIT(4)
+#define CS42L84_HS_SWITCH_CTL_HSB_HS3 BIT(3)
+#define CS42L84_HS_SWITCH_CTL_HSB_HS4 BIT(2)
+#define CS42L84_HS_SWITCH_CTL_GNDHS_HS3 BIT(1)
+#define CS42L84_HS_SWITCH_CTL_GNDHS_HS4 BIT(0)
+
+#define CS42L84_HS_CLAMP_DISABLE 0x1813
+
+#define CS42L84_ADC_CTL1 0x2000
+#define CS42L84_ADC_CTL1_PREAMP_GAIN_SHIFT 6
+#define CS42L84_ADC_CTL1_PGA_GAIN_SHIFT 0
+#define CS42L84_ADC_CTL4 0x2003
+#define CS42L84_ADC_CTL4_WNF_CF_SHIFT 4
+#define CS42L84_ADC_CTL4_WNF_EN_SHIFT 3
+#define CS42L84_ADC_CTL4_HPF_CF_SHIFT 1
+#define CS42L84_ADC_CTL4_HPF_EN_SHIFT 0
+
+#define CS42L84_DAC_CTL1 0x3000
+#define CS42L84_DAC_CTL1_UNMUTE BIT(0)
+//#define CS42L84_DAC_CTL1_DACB_INV_SHIFT 1
+//#define CS42L84_DAC_CTL1_DACA_INV_SHIFT 0
+#define CS42L84_DAC_CTL2 0x3001
+
+#define CS42L84_DAC_CHA_VOL_LSB 0x3004
+#define CS42L84_DAC_CHA_VOL_MSB 0x3005
+#define CS42L84_DAC_CHB_VOL_LSB 0x3006
+#define CS42L84_DAC_CHB_VOL_MSB 0x3007
+#define CS42L84_HP_VOL_CTL 0x3020
+#define CS42L84_HP_VOL_CTL_ZERO_CROSS BIT(1)
+#define CS42L84_HP_VOL_CTL_SOFT BIT(0)
+
+#define CS42L84_SRC_ASP_RX_CH1 0b1101
+#define CS42L84_SRC_ASP_RX_CH2 0b1110
+
+#define CS42L84_BUS_ASP_TX_SRC 0x4000
+#define CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT 0
+#define CS42L84_BUS_DAC_SRC 0x4001
+#define CS42L84_BUS_DAC_SRC_DACA_SHIFT 0
+#define CS42L84_BUS_DAC_SRC_DACB_SHIFT 4
+
+#define CS42L84_ASP_CTL 0x5000
+#define CS42L84_ASP_CTL_BCLK_EN_SHIFT 1
+#define CS42L84_ASP_CTL_TDM_MODE BIT(2)
+#define CS42L84_ASP_FSYNC_CTL2 0x5010
+#define CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO GENMASK(7, 1)
+#define CS42L84_ASP_FSYNC_CTL3 0x5011
+#define CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI GENMASK(4, 0)
+#define CS42L84_ASP_DATA_CTL 0x5018
+
+#define CS42L84_ASP_RX_EN 0x5020
+#define CS42L84_ASP_RX_EN_CH1_SHIFT 0
+#define CS42L84_ASP_RX_EN_CH2_SHIFT 1
+#define CS42L84_ASP_TX_EN 0x5024
+#define CS42L84_ASP_TX_EN_CH1_SHIFT 0
+
+#define CS42L84_ASP_RX_CH1_CTL1 0x5028
+#define CS42L84_ASP_RX_CH1_CTL2 0x5029
+#define CS42L84_ASP_RX_CH1_WIDTH 0x502a
+#define CS42L84_ASP_RX_CH2_CTL1 0x502c
+#define CS42L84_ASP_RX_CH2_CTL2 0x502d
+#define CS42L84_ASP_RX_CH2_WIDTH 0x502e
+
+#define CS42L84_ASP_RX_CHx_CTL1_EDGE BIT(0)
+#define CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB GENMASK(7, 1)
+#define CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB GENMASK(2, 0)
+
+#define CS42L84_ASP_TX_CH1_CTL1 0x5068
+#define CS42L84_ASP_TX_CH1_CTL2 0x5069
+#define CS42L84_ASP_TX_CH1_WIDTH 0x506a
+#define CS42L84_ASP_TX_CH2_CTL1 0x506c
+#define CS42L84_ASP_TX_CH2_CTL2 0x506d
+#define CS42L84_ASP_TX_CH2_WIDTH 0x506e
+
+#define CS42L84_DEBOUNCE_TIME_125MS 0b001
+#define CS42L84_DEBOUNCE_TIME_500MS 0b011
+
+#define CS42L84_BOOT_TIME_US 3000
+#define CS42L84_CLOCK_SWITCH_DELAY_US 150
+#define CS42L84_PLL_LOCK_POLL_US 250
+#define CS42L84_PLL_LOCK_TIMEOUT_US 1250
+
+#endif /* __CS42L84_H__ */
diff --git a/sound/soc/codecs/cs530x-i2c.c b/sound/soc/codecs/cs530x-i2c.c
index 56659bf735db..22b1a4d6b61c 100644
--- a/sound/soc/codecs/cs530x-i2c.c
+++ b/sound/soc/codecs/cs530x-i2c.c
@@ -67,6 +67,6 @@ static struct i2c_driver cs530x_i2c_driver = {
module_i2c_driver(cs530x_i2c_driver);
MODULE_DESCRIPTION("I2C CS530X driver");
-MODULE_IMPORT_NS(SND_SOC_CS530X);
+MODULE_IMPORT_NS("SND_SOC_CS530X");
MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <[email protected]>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c
index da52afe56c3c..252e66c8449e 100644
--- a/sound/soc/codecs/cs530x.c
+++ b/sound/soc/codecs/cs530x.c
@@ -821,7 +821,7 @@ const struct regmap_config cs530x_regmap = {
.reg_defaults = cs530x_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults),
};
-EXPORT_SYMBOL_NS_GPL(cs530x_regmap, SND_SOC_CS530X);
+EXPORT_SYMBOL_NS_GPL(cs530x_regmap, "SND_SOC_CS530X");
static int cs530x_check_device_id(struct cs530x_priv *cs530x)
{
@@ -964,7 +964,7 @@ err_regulator:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs530x_probe, SND_SOC_CS530X);
+EXPORT_SYMBOL_NS_GPL(cs530x_probe, "SND_SOC_CS530X");
MODULE_DESCRIPTION("CS530X CODEC Driver");
MODULE_AUTHOR("Paul Handrigan <[email protected]>");
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index f3ef6fb55304..ca4cc954efa8 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -20,6 +20,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <linux/pm_runtime.h>
+#include <linux/units.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@@ -1555,7 +1556,11 @@ static int da7213_set_component_sysclk(struct snd_soc_component *component,
if ((da7213->clk_src == clk_id) && (da7213->mclk_rate == freq))
return 0;
- if (((freq < 5000000) && (freq != 32768)) || (freq > 54000000)) {
+ /* Maybe audio stream is closing. */
+ if (freq == 0)
+ return 0;
+
+ if (((freq < da7213->fin_min_rate) && (freq != 32768)) || (freq > 54000000)) {
dev_err(component->dev, "Unsupported MCLK value %d\n",
freq);
return -EINVAL;
@@ -1854,11 +1859,14 @@ static int da7213_set_bias_level(struct snd_soc_component *component,
return 0;
}
+#define DA7213_FIN_MIN_RATE (5 * MEGA)
+#define DA7212_FIN_MIN_RATE (2 * MEGA)
+
#if defined(CONFIG_OF)
/* DT */
static const struct of_device_id da7213_of_match[] = {
- { .compatible = "dlg,da7212", },
- { .compatible = "dlg,da7213", },
+ { .compatible = "dlg,da7212", .data = (void *)DA7212_FIN_MIN_RATE },
+ { .compatible = "dlg,da7213", .data = (void *)DA7213_FIN_MIN_RATE },
{ }
};
MODULE_DEVICE_TABLE(of, da7213_of_match);
@@ -1866,8 +1874,8 @@ MODULE_DEVICE_TABLE(of, da7213_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id da7213_acpi_match[] = {
- { "DLGS7212", 0},
- { "DLGS7213", 0},
+ { "DLGS7212", DA7212_FIN_MIN_RATE },
+ { "DLGS7213", DA7213_FIN_MIN_RATE },
{ },
};
MODULE_DEVICE_TABLE(acpi, da7213_acpi_match);
@@ -2136,6 +2144,7 @@ static const struct regmap_config da7213_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
+ .max_register = DA7213_TONE_GEN_OFF_PER,
.reg_defaults = da7213_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(da7213_reg_defaults),
.volatile_reg = da7213_volatile_register,
@@ -2162,6 +2171,10 @@ static int da7213_i2c_probe(struct i2c_client *i2c)
if (!da7213)
return -ENOMEM;
+ da7213->fin_min_rate = (uintptr_t)i2c_get_match_data(i2c);
+ if (!da7213->fin_min_rate)
+ return -EINVAL;
+
i2c_set_clientdata(i2c, da7213);
/* Get required supplies */
@@ -2229,12 +2242,12 @@ static int __maybe_unused da7213_runtime_resume(struct device *dev)
if (ret < 0)
return ret;
regcache_cache_only(da7213->regmap, false);
- regcache_sync(da7213->regmap);
- return 0;
+ return regcache_sync(da7213->regmap);
}
static const struct dev_pm_ops da7213_pm = {
SET_RUNTIME_PM_OPS(da7213_runtime_suspend, da7213_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static const struct i2c_device_id da7213_i2c_id[] = {
diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h
index 505b731c0adb..b9ab791d6b88 100644
--- a/sound/soc/codecs/da7213.h
+++ b/sound/soc/codecs/da7213.h
@@ -600,6 +600,7 @@ struct da7213_priv {
struct clk *mclk;
unsigned int mclk_rate;
unsigned int out_rate;
+ unsigned int fin_min_rate;
int clk_src;
bool master;
bool alc_calib_auto;
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 311ea7918b31..e2da3e317b5a 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -1167,17 +1167,20 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
int ret = 0;
- if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq))
+ mutex_lock(&da7219->pll_lock);
+
+ if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq)) {
+ mutex_unlock(&da7219->pll_lock);
return 0;
+ }
if ((freq < 2000000) || (freq > 54000000)) {
+ mutex_unlock(&da7219->pll_lock);
dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
freq);
return -EINVAL;
}
- mutex_lock(&da7219->pll_lock);
-
switch (clk_id) {
case DA7219_CLKSRC_MCLK_SQR:
snd_soc_component_update_bits(component, DA7219_PLL_CTRL,
diff --git a/sound/soc/codecs/es8323.c b/sound/soc/codecs/es8323.c
new file mode 100644
index 000000000000..6f4fa36ea34d
--- /dev/null
+++ b/sound/soc/codecs/es8323.c
@@ -0,0 +1,792 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// es8323.c -- es8323 ALSA SoC audio driver
+//
+// Copyright 2024 Rockchip Electronics Co. Ltd.
+// Copyright 2024 Everest Semiconductor Co.,Ltd.
+// Copyright 2024 Loongson Technology Co.,Ltd.
+//
+// Author: Mark Brown <[email protected]>
+// Jianqun Xu <[email protected]>
+// Nickey Yang <[email protected]>
+// Further cleanup and restructuring by:
+// Binbin Zhou <[email protected]>
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "es8323.h"
+
+struct es8323_priv {
+ unsigned int sysclk;
+ struct clk *mclk;
+ struct regmap *regmap;
+ struct snd_pcm_hw_constraint_list *sysclk_constraints;
+ struct snd_soc_component *component;
+};
+
+/* es8323 register cache */
+static const struct reg_default es8323_reg_defaults[] = {
+ { ES8323_CONTROL1, 0x06 },
+ { ES8323_CONTROL2, 0x1c },
+ { ES8323_CHIPPOWER, 0xc3 },
+ { ES8323_ADCPOWER, 0xfc },
+ { ES8323_DACPOWER, 0xc0 },
+ { ES8323_CHIPLOPOW1, 0x00 },
+ { ES8323_CHIPLOPOW2, 0x00 },
+ { ES8323_ANAVOLMANAG, 0x7c },
+ { ES8323_MASTERMODE, 0x80 },
+ { ES8323_ADCCONTROL1, 0x00 },
+ { ES8323_ADCCONTROL2, 0x00 },
+ { ES8323_ADCCONTROL3, 0x06 },
+ { ES8323_ADCCONTROL4, 0x00 },
+ { ES8323_ADCCONTROL5, 0x06 },
+ { ES8323_ADCCONTROL6, 0x30 },
+ { ES8323_ADC_MUTE, 0x30 },
+ { ES8323_LADC_VOL, 0xc0 },
+ { ES8323_RADC_VOL, 0xc0 },
+ { ES8323_ADCCONTROL10, 0x38 },
+ { ES8323_ADCCONTROL11, 0xb0 },
+ { ES8323_ADCCONTROL12, 0x32 },
+ { ES8323_ADCCONTROL13, 0x06 },
+ { ES8323_ADCCONTROL14, 0x00 },
+ { ES8323_DACCONTROL1, 0x00 },
+ { ES8323_DACCONTROL2, 0x06 },
+ { ES8323_DAC_MUTE, 0x30 },
+ { ES8323_LDAC_VOL, 0xc0 },
+ { ES8323_RDAC_VOL, 0xc0 },
+ { ES8323_DACCONTROL6, 0x08 },
+ { ES8323_DACCONTROL7, 0x06 },
+ { ES8323_DACCONTROL8, 0x1f },
+ { ES8323_DACCONTROL9, 0xf7 },
+ { ES8323_DACCONTROL10, 0xfd },
+ { ES8323_DACCONTROL11, 0xff },
+ { ES8323_DACCONTROL12, 0x1f },
+ { ES8323_DACCONTROL13, 0xf7 },
+ { ES8323_DACCONTROL14, 0xfd },
+ { ES8323_DACCONTROL15, 0xff },
+ { ES8323_DACCONTROL16, 0x00 },
+ { ES8323_DACCONTROL17, 0x38 },
+ { ES8323_DACCONTROL18, 0x38 },
+ { ES8323_DACCONTROL19, 0x38 },
+ { ES8323_DACCONTROL20, 0x38 },
+ { ES8323_DACCONTROL21, 0x38 },
+ { ES8323_DACCONTROL22, 0x38 },
+ { ES8323_DACCONTROL23, 0x00 },
+ { ES8323_LOUT1_VOL, 0x00 },
+ { ES8323_ROUT1_VOL, 0x00 },
+};
+
+static const char *const es8323_stereo_3d_texts[] = { "No 3D ", "Level 1", "Level 2", "Level 3",
+ "Level 4", "Level 5", "Level 6", "Level 7" };
+static SOC_ENUM_SINGLE_DECL(es8323_stereo_3d_enum, ES8323_DACCONTROL7, 2, es8323_stereo_3d_texts);
+
+static const char *const es8323_alc_func_texts[] = { "Off", "Right", "Left", "Stereo" };
+static SOC_ENUM_SINGLE_DECL(es8323_alc_function_enum,
+ ES8323_ADCCONTROL10, 6, es8323_alc_func_texts);
+
+static const char *const es8323_ng_type_texts[] = { "Constant PGA Gain", "Mute ADC Output" };
+static SOC_ENUM_SINGLE_DECL(es8323_alc_ng_type_enum, ES8323_ADCCONTROL14, 1, es8323_ng_type_texts);
+
+static const char *const es8323_deemph_texts[] = { "None", "32Khz", "44.1Khz", "48Khz" };
+static SOC_ENUM_SINGLE_DECL(es8323_playback_deemphasis_enum,
+ ES8323_DACCONTROL6, 6, es8323_deemph_texts);
+
+static const char *const es8323_adcpol_texts[] = { "Normal", "L Invert",
+ "R Invert", "L + R Invert" };
+static SOC_ENUM_SINGLE_DECL(es8323_capture_polarity_enum,
+ ES8323_ADCCONTROL6, 6, es8323_adcpol_texts);
+
+static const DECLARE_TLV_DB_SCALE(es8323_adc_tlv, -9600, 50, 1);
+static const DECLARE_TLV_DB_SCALE(es8323_dac_tlv, -9600, 50, 1);
+static const DECLARE_TLV_DB_SCALE(es8323_out_tlv, -4500, 150, 0);
+static const DECLARE_TLV_DB_SCALE(es8323_bypass_tlv, 0, 300, 0);
+static const DECLARE_TLV_DB_SCALE(es8323_bypass_tlv2, -15, 300, 0);
+
+static const struct snd_kcontrol_new es8323_snd_controls[] = {
+ SOC_ENUM("3D Mode", es8323_stereo_3d_enum),
+ SOC_ENUM("ALC Capture Function", es8323_alc_function_enum),
+ SOC_ENUM("ALC Capture NG Type", es8323_alc_ng_type_enum),
+ SOC_ENUM("Playback De-emphasis", es8323_playback_deemphasis_enum),
+ SOC_ENUM("Capture Polarity", es8323_capture_polarity_enum),
+ SOC_SINGLE("ALC Capture ZC Switch", ES8323_ADCCONTROL13, 6, 1, 0),
+ SOC_SINGLE("ALC Capture Decay Time", ES8323_ADCCONTROL12, 4, 15, 0),
+ SOC_SINGLE("ALC Capture Attack Time", ES8323_ADCCONTROL12, 0, 15, 0),
+ SOC_SINGLE("ALC Capture NG Threshold", ES8323_ADCCONTROL14, 3, 31, 0),
+ SOC_SINGLE("ALC Capture NG Switch", ES8323_ADCCONTROL14, 0, 1, 0),
+ SOC_SINGLE("ZC Timeout Switch", ES8323_ADCCONTROL13, 6, 1, 0),
+ SOC_SINGLE("Capture Mute Switch", ES8323_ADC_MUTE, 2, 1, 0),
+ SOC_SINGLE_TLV("Left Channel Capture Volume", ES8323_ADCCONTROL1, 4, 8,
+ 0, es8323_bypass_tlv),
+ SOC_SINGLE_TLV("Right Channel Capture Volume", ES8323_ADCCONTROL1, 0,
+ 8, 0, es8323_bypass_tlv),
+ SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", ES8323_DACCONTROL17, 3,
+ 7, 1, es8323_bypass_tlv2),
+ SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", ES8323_DACCONTROL20,
+ 3, 7, 1, es8323_bypass_tlv2),
+ SOC_DOUBLE_R_TLV("PCM Volume", ES8323_LDAC_VOL, ES8323_RDAC_VOL,
+ 0, 192, 1, es8323_dac_tlv),
+ SOC_DOUBLE_R_TLV("Capture Digital Volume", ES8323_LADC_VOL,
+ ES8323_RADC_VOL, 0, 192, 1, es8323_adc_tlv),
+ SOC_DOUBLE_R_TLV("Output 1 Playback Volume", ES8323_LOUT1_VOL,
+ ES8323_ROUT1_VOL, 0, 33, 0, es8323_out_tlv),
+ SOC_DOUBLE_R_TLV("Output 2 Playback Volume", ES8323_LOUT2_VOL,
+ ES8323_ROUT2_VOL, 0, 33, 0, es8323_out_tlv),
+};
+
+/* Left DAC Route */
+static const char *const es8323_pga_sell[] = { "Line 1L", "Line 2L", "NC", "DifferentialL" };
+static SOC_ENUM_SINGLE_DECL(es8323_left_dac_enum, ES8323_ADCCONTROL2, 6, es8323_pga_sell);
+static const struct snd_kcontrol_new es8323_left_dac_mux_controls =
+ SOC_DAPM_ENUM("Left DAC Route", es8323_left_dac_enum);
+
+/* Right DAC Route */
+static const char *const es8323_pga_selr[] = { "Line 1R", "Line 2R", "NC", "DifferentialR" };
+static SOC_ENUM_SINGLE_DECL(es8323_right_dac_enum, ES8323_ADCCONTROL2, 4, es8323_pga_selr);
+static const struct snd_kcontrol_new es8323_right_dac_mux_controls =
+ SOC_DAPM_ENUM("Right DAC Route", es8323_right_dac_enum);
+
+/* Left Line Mux */
+static const char *const es8323_lin_sell[] = { "Line 1L", "Line 2L", "NC", "MicL" };
+static SOC_ENUM_SINGLE_DECL(es8323_llin_enum, ES8323_DACCONTROL16, 3, es8323_lin_sell);
+static const struct snd_kcontrol_new es8323_left_line_controls =
+ SOC_DAPM_ENUM("LLIN Mux", es8323_llin_enum);
+
+/* Right Line Mux */
+static const char *const es8323_lin_selr[] = { "Line 1R", "Line 2R", "NC", "MicR" };
+static SOC_ENUM_SINGLE_DECL(es8323_rlin_enum, ES8323_DACCONTROL16, 0, es8323_lin_selr);
+static const struct snd_kcontrol_new es8323_right_line_controls =
+ SOC_DAPM_ENUM("RLIN Mux", es8323_rlin_enum);
+
+/* Differential Mux */
+static const char *const es8323_diffmux_sel[] = { "Line 1", "Line 2" };
+static SOC_ENUM_SINGLE_DECL(es8323_diffmux_enum, ES8323_ADCCONTROL3, 7, es8323_diffmux_sel);
+static const struct snd_kcontrol_new es8323_diffmux_controls =
+ SOC_DAPM_ENUM("Route2", es8323_diffmux_enum);
+
+/* Mono ADC Mux */
+static const char *const es8323_mono_adc_mux[] = { "Stereo", "Mono (Left)", "Mono (Right)" };
+static SOC_ENUM_SINGLE_DECL(es8323_mono_adc_mux_enum, ES8323_ADCCONTROL3, 3, es8323_mono_adc_mux);
+static const struct snd_kcontrol_new es8323_mono_adc_mux_controls =
+ SOC_DAPM_ENUM("Mono Mux", es8323_mono_adc_mux_enum);
+
+/* Left Mixer */
+static const struct snd_kcontrol_new es8323_left_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left Playback Switch", SND_SOC_NOPM, 7, 1, 1),
+ SOC_DAPM_SINGLE("Left Bypass Switch", ES8323_DACCONTROL17, 6, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new es8323_right_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Right Playback Switch", SND_SOC_NOPM, 6, 1, 1),
+ SOC_DAPM_SINGLE("Right Bypass Switch", ES8323_DACCONTROL20, 6, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget es8323_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("LINPUT1"),
+ SND_SOC_DAPM_INPUT("LINPUT2"),
+ SND_SOC_DAPM_INPUT("RINPUT1"),
+ SND_SOC_DAPM_INPUT("RINPUT2"),
+
+ SND_SOC_DAPM_MICBIAS("Mic Bias", SND_SOC_NOPM, 3, 1),
+
+ /* Muxes */
+ SND_SOC_DAPM_MUX("Left PGA Mux", SND_SOC_NOPM, 0, 0, &es8323_left_dac_mux_controls),
+ SND_SOC_DAPM_MUX("Right PGA Mux", SND_SOC_NOPM, 0, 0, &es8323_right_dac_mux_controls),
+ SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, &es8323_diffmux_controls),
+ SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, &es8323_mono_adc_mux_controls),
+ SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, &es8323_mono_adc_mux_controls),
+ SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, &es8323_left_line_controls),
+ SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, &es8323_right_line_controls),
+
+ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", SND_SOC_NOPM, 4, 1),
+ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", SND_SOC_NOPM, 5, 1),
+ SND_SOC_DAPM_DAC("Right DAC", "Right Playback", SND_SOC_NOPM, 6, 1),
+ SND_SOC_DAPM_DAC("Left DAC", "Left Playback", SND_SOC_NOPM, 7, 1),
+
+ SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+ &es8323_left_mixer_controls[0],
+ ARRAY_SIZE(es8323_left_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+ &es8323_right_mixer_controls[0],
+ ARRAY_SIZE(es8323_right_mixer_controls)),
+
+ SND_SOC_DAPM_PGA("Right ADC Power", SND_SOC_NOPM, 6, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Left ADC Power", SND_SOC_NOPM, 7, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Out 2", SND_SOC_NOPM, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Left Out 2", SND_SOC_NOPM, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Out 1", SND_SOC_NOPM, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Left Out 1", SND_SOC_NOPM, 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("LAMP", ES8323_ADCCONTROL1, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("RAMP", ES8323_ADCCONTROL1, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_OUTPUT("LOUT1"),
+ SND_SOC_DAPM_OUTPUT("ROUT1"),
+ SND_SOC_DAPM_OUTPUT("LOUT2"),
+ SND_SOC_DAPM_OUTPUT("ROUT2"),
+ SND_SOC_DAPM_OUTPUT("VREF"),
+};
+
+static const struct snd_soc_dapm_route es8323_dapm_routes[] = {
+ /*12.22*/
+ {"Left PGA Mux", "Line 1L", "LINPUT1"},
+ {"Left PGA Mux", "Line 2L", "LINPUT2"},
+ {"Left PGA Mux", "DifferentialL", "Differential Mux"},
+
+ {"Right PGA Mux", "Line 1R", "RINPUT1"},
+ {"Right PGA Mux", "Line 2R", "RINPUT2"},
+ {"Right PGA Mux", "DifferentialR", "Differential Mux"},
+
+ {"Differential Mux", "Line 1", "LINPUT1"},
+ {"Differential Mux", "Line 1", "RINPUT1"},
+ {"Differential Mux", "Line 2", "LINPUT2"},
+ {"Differential Mux", "Line 2", "RINPUT2"},
+
+ {"Left ADC Mux", "Stereo", "Right PGA Mux"},
+ {"Left ADC Mux", "Stereo", "Left PGA Mux"},
+ {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
+
+ {"Right ADC Mux", "Stereo", "Left PGA Mux"},
+ {"Right ADC Mux", "Stereo", "Right PGA Mux"},
+ {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
+
+ {"Left ADC Power", NULL, "Left ADC Mux"},
+ {"Right ADC Power", NULL, "Right ADC Mux"},
+ {"Left ADC", NULL, "Left ADC Power"},
+ {"Right ADC", NULL, "Right ADC Power"},
+
+ {"Left Line Mux", "Line 1L", "LINPUT1"},
+ {"Left Line Mux", "Line 2L", "LINPUT2"},
+ {"Left Line Mux", "MicL", "Left PGA Mux"},
+
+ {"Right Line Mux", "Line 1R", "RINPUT1"},
+ {"Right Line Mux", "Line 2R", "RINPUT2"},
+ {"Right Line Mux", "MicR", "Right PGA Mux"},
+
+ {"Left Mixer", "Left Playback Switch", "Left DAC"},
+ {"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
+
+ {"Right Mixer", "Right Playback Switch", "Right DAC"},
+ {"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+ {"Left Out 1", NULL, "Left Mixer"},
+ {"LOUT1", NULL, "Left Out 1"},
+ {"Right Out 1", NULL, "Right Mixer"},
+ {"ROUT1", NULL, "Right Out 1"},
+
+ {"Left Out 2", NULL, "Left Mixer"},
+ {"LOUT2", NULL, "Left Out 2"},
+ {"Right Out 2", NULL, "Right Mixer"},
+ {"ROUT2", NULL, "Right Out 2"},
+};
+
+struct coeff_div {
+ u32 mclk;
+ u32 rate;
+ u16 fs;
+ u8 sr:4;
+ u8 usb:1;
+};
+
+/* codec hifi mclk clock divider coefficients */
+static const struct coeff_div es8323_coeff_div[] = {
+ /* 8k */
+ {12288000, 8000, 1536, 0xa, 0x0},
+ {11289600, 8000, 1408, 0x9, 0x0},
+ {18432000, 8000, 2304, 0xc, 0x0},
+ {16934400, 8000, 2112, 0xb, 0x0},
+ {12000000, 8000, 1500, 0xb, 0x1},
+
+ /* 11.025k */
+ {11289600, 11025, 1024, 0x7, 0x0},
+ {16934400, 11025, 1536, 0xa, 0x0},
+ {12000000, 11025, 1088, 0x9, 0x1},
+
+ /* 16k */
+ {12288000, 16000, 768, 0x6, 0x0},
+ {18432000, 16000, 1152, 0x8, 0x0},
+ {12000000, 16000, 750, 0x7, 0x1},
+
+ /* 22.05k */
+ {11289600, 22050, 512, 0x4, 0x0},
+ {16934400, 22050, 768, 0x6, 0x0},
+ {12000000, 22050, 544, 0x6, 0x1},
+
+ /* 32k */
+ {12288000, 32000, 384, 0x3, 0x0},
+ {18432000, 32000, 576, 0x5, 0x0},
+ {12000000, 32000, 375, 0x4, 0x1},
+
+ /* 44.1k */
+ {11289600, 44100, 256, 0x2, 0x0},
+ {16934400, 44100, 384, 0x3, 0x0},
+ {12000000, 44100, 272, 0x3, 0x1},
+
+ /* 48k */
+ {12288000, 48000, 256, 0x2, 0x0},
+ {18432000, 48000, 384, 0x3, 0x0},
+ {12000000, 48000, 250, 0x2, 0x1},
+
+ /* 88.2k */
+ {11289600, 88200, 128, 0x0, 0x0},
+ {16934400, 88200, 192, 0x1, 0x0},
+ {12000000, 88200, 136, 0x1, 0x1},
+
+ /* 96k */
+ {12288000, 96000, 128, 0x0, 0x0},
+ {18432000, 96000, 192, 0x1, 0x0},
+ {12000000, 96000, 125, 0x0, 0x1},
+};
+
+static unsigned int rates_12288[] = {
+ 8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12288 = {
+ .count = ARRAY_SIZE(rates_12288),
+ .list = rates_12288,
+};
+
+static unsigned int rates_112896[] = {
+ 8000, 11025, 22050, 44100,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_112896 = {
+ .count = ARRAY_SIZE(rates_112896),
+ .list = rates_112896,
+};
+
+static unsigned int rates_12[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000,
+ 32000, 44100, 48000, 48000, 88235, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12 = {
+ .count = ARRAY_SIZE(rates_12),
+ .list = rates_12,
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(es8323_coeff_div); i++) {
+ if (es8323_coeff_div[i].rate == rate &&
+ es8323_coeff_div[i].mclk == mclk)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int es8323_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+
+ switch (freq) {
+ case 11289600:
+ case 18432000:
+ case 22579200:
+ case 36864000:
+ es8323->sysclk_constraints = &constraints_112896;
+ break;
+ case 12288000:
+ case 16934400:
+ case 24576000:
+ case 33868800:
+ es8323->sysclk_constraints = &constraints_12288;
+ break;
+ case 12000000:
+ case 24000000:
+ es8323->sysclk_constraints = &constraints_12;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ es8323->sysclk = freq;
+ return 0;
+}
+
+static int es8323_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ u8 iface = snd_soc_component_read(component, ES8323_MASTERMODE);
+ u8 adciface = snd_soc_component_read(component, ES8323_ADC_IFACE);
+ u8 daciface = snd_soc_component_read(component, ES8323_DAC_IFACE);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_BC_FP:
+ iface |= 0x80;
+ break;
+ case SND_SOC_DAIFMT_BC_FC:
+ iface &= 0x7f;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ adciface &= 0xfc;
+ daciface &= 0xf8;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ adciface &= 0xfd;
+ daciface &= 0xf9;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ adciface &= 0xfe;
+ daciface &= 0xfa;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ adciface &= 0xff;
+ daciface &= 0xfb;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ iface &= 0xdf;
+ adciface &= 0xdf;
+ daciface &= 0xbf;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ iface |= 0x20;
+ adciface |= 0x20;
+ daciface |= 0x40;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ iface |= 0x20;
+ adciface &= 0xdf;
+ daciface &= 0xbf;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ iface &= 0xdf;
+ adciface |= 0x20;
+ daciface |= 0x40;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_write(component, ES8323_MASTERMODE, iface);
+ snd_soc_component_write(component, ES8323_ADC_IFACE, adciface);
+ snd_soc_component_write(component, ES8323_DAC_IFACE, daciface);
+
+ return 0;
+}
+
+static int es8323_pcm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+
+ if (es8323->sysclk) {
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ es8323->sysclk_constraints);
+ }
+
+ return 0;
+}
+
+static int es8323_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 es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+ u16 srate = snd_soc_component_read(component, ES8323_MASTERMODE) & 0x80;
+ u16 adciface = snd_soc_component_read(component, ES8323_ADC_IFACE) & 0xe3;
+ u16 daciface = snd_soc_component_read(component, ES8323_DAC_IFACE) & 0xc7;
+ int coeff;
+
+ coeff = get_coeff(es8323->sysclk, params_rate(params));
+ if (coeff < 0) {
+ coeff = get_coeff(es8323->sysclk / 2, params_rate(params));
+ srate |= 0x40;
+ }
+
+ if (coeff < 0) {
+ dev_err(component->dev,
+ "Unable to configure sample rate %dHz with %dHz MCLK\n",
+ params_rate(params), es8323->sysclk);
+ return coeff;
+ }
+
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ adciface |= 0xc;
+ daciface |= 0x18;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ adciface |= 0x4;
+ daciface |= 0x8;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ adciface |= 0x10;
+ daciface |= 0x20;
+ break;
+ }
+
+ snd_soc_component_write(component, ES8323_DAC_IFACE, daciface);
+ snd_soc_component_write(component, ES8323_ADC_IFACE, adciface);
+
+ snd_soc_component_write(component, ES8323_MASTERMODE, srate);
+ snd_soc_component_write(component, ES8323_ADCCONTROL5,
+ es8323_coeff_div[coeff].sr |
+ (es8323_coeff_div[coeff].usb) << 4);
+ snd_soc_component_write(component, ES8323_DACCONTROL2,
+ es8323_coeff_div[coeff].sr |
+ (es8323_coeff_div[coeff].usb) << 4);
+
+ snd_soc_component_write(component, ES8323_DACPOWER, 0x3c);
+
+ return 0;
+}
+
+static int es8323_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_component *component = dai->component;
+ u32 val = mute ? 0x6 : 0x2;
+
+ snd_soc_component_write(component, ES8323_DAC_MUTE, val);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops es8323_ops = {
+ .startup = es8323_pcm_startup,
+ .hw_params = es8323_pcm_hw_params,
+ .set_fmt = es8323_set_dai_fmt,
+ .set_sysclk = es8323_set_dai_sysclk,
+ .mute_stream = es8323_mute_stream,
+};
+
+#define ES8323_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver es8323_dai = {
+ .name = "ES8323 HiFi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = ES8323_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = ES8323_FORMATS,
+ },
+ .ops = &es8323_ops,
+ .symmetric_rate = 1,
+};
+
+static int es8323_probe(struct snd_soc_component *component)
+{
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ es8323->component = component;
+
+ es8323->mclk = devm_clk_get_optional(component->dev, "mclk");
+ if (IS_ERR(es8323->mclk)) {
+ dev_err(component->dev, "unable to get mclk\n");
+ return PTR_ERR(es8323->mclk);
+ }
+
+ if (!es8323->mclk)
+ dev_warn(component->dev, "assuming static mclk\n");
+
+ ret = clk_prepare_enable(es8323->mclk);
+ if (ret) {
+ dev_err(component->dev, "unable to enable mclk\n");
+ return ret;
+ }
+
+ snd_soc_component_write(component, ES8323_CONTROL2, 0x60);
+ snd_soc_component_write(component, ES8323_CHIPPOWER, 0x00);
+ snd_soc_component_write(component, ES8323_DACCONTROL17, 0xB8);
+
+ return 0;
+}
+
+static int es8323_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ ret = clk_prepare_enable(es8323->mclk);
+ if (ret)
+ return ret;
+
+ snd_soc_component_write(component, ES8323_CHIPPOWER, 0xf0);
+ usleep_range(18000, 20000);
+ snd_soc_component_write(component, ES8323_DACPOWER, 0x3c);
+ snd_soc_component_write(component, ES8323_ANAVOLMANAG, 0x7c);
+ snd_soc_component_write(component, ES8323_CHIPLOPOW1, 0x00);
+ snd_soc_component_write(component, ES8323_CHIPLOPOW2, 0x00);
+ snd_soc_component_write(component, ES8323_CHIPPOWER, 0x00);
+ snd_soc_component_write(component, ES8323_ADCPOWER, 0x09);
+ snd_soc_component_write(component, ES8323_ADCCONTROL14, 0x00);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ snd_soc_component_write(component, ES8323_ANAVOLMANAG, 0x7c);
+ snd_soc_component_write(component, ES8323_CHIPLOPOW1, 0x00);
+ snd_soc_component_write(component, ES8323_CHIPLOPOW2, 0x00);
+ snd_soc_component_write(component, ES8323_CHIPPOWER, 0x00);
+ snd_soc_component_write(component, ES8323_ADCPOWER, 0x59);
+ break;
+ case SND_SOC_BIAS_OFF:
+ clk_disable_unprepare(es8323->mclk);
+ snd_soc_component_write(component, ES8323_ADCPOWER, 0xff);
+ snd_soc_component_write(component, ES8323_DACPOWER, 0xC0);
+ snd_soc_component_write(component, ES8323_CHIPLOPOW1, 0xff);
+ snd_soc_component_write(component, ES8323_CHIPLOPOW2, 0xff);
+ snd_soc_component_write(component, ES8323_CHIPPOWER, 0xff);
+ snd_soc_component_write(component, ES8323_ANAVOLMANAG, 0x7b);
+ break;
+ }
+
+ return 0;
+}
+
+static void es8323_remove(struct snd_soc_component *component)
+{
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+
+ clk_disable_unprepare(es8323->mclk);
+ es8323_set_bias_level(component, SND_SOC_BIAS_OFF);
+}
+
+static int es8323_suspend(struct snd_soc_component *component)
+{
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(es8323->regmap, true);
+ regcache_mark_dirty(es8323->regmap);
+
+ return 0;
+}
+
+static int es8323_resume(struct snd_soc_component *component)
+{
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(es8323->regmap, false);
+ regcache_sync(es8323->regmap);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_es8323 = {
+ .probe = es8323_probe,
+ .remove = es8323_remove,
+ .suspend = es8323_suspend,
+ .resume = es8323_resume,
+ .set_bias_level = es8323_set_bias_level,
+ .controls = es8323_snd_controls,
+ .num_controls = ARRAY_SIZE(es8323_snd_controls),
+ .dapm_widgets = es8323_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(es8323_dapm_widgets),
+ .dapm_routes = es8323_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(es8323_dapm_routes),
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static const struct regmap_config es8323_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .use_single_read = true,
+ .use_single_write = true,
+ .max_register = 0x53,
+ .reg_defaults = es8323_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(es8323_reg_defaults),
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static int es8323_i2c_probe(struct i2c_client *i2c_client)
+{
+ struct es8323_priv *es8323;
+ struct device *dev = &i2c_client->dev;
+
+ es8323 = devm_kzalloc(dev, sizeof(*es8323), GFP_KERNEL);
+ if (!es8323)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c_client, es8323);
+
+ es8323->regmap = devm_regmap_init_i2c(i2c_client, &es8323_regmap);
+ if (IS_ERR(es8323->regmap))
+ return PTR_ERR(es8323->regmap);
+
+ return devm_snd_soc_register_component(dev,
+ &soc_component_dev_es8323,
+ &es8323_dai, 1);
+}
+
+static const struct i2c_device_id es8323_i2c_id[] = {
+ { "es8323", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, es8323_i2c_id);
+
+static const struct acpi_device_id es8323_acpi_match[] = {
+ { "ESSX8323", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, es8323_acpi_match);
+
+static const struct of_device_id es8323_of_match[] = {
+ { .compatible = "everest,es8323" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, es8323_of_match);
+
+static struct i2c_driver es8323_i2c_driver = {
+ .driver = {
+ .name = "ES8323",
+ .acpi_match_table = es8323_acpi_match,
+ .of_match_table = es8323_of_match,
+ },
+ .probe = es8323_i2c_probe,
+ .id_table = es8323_i2c_id,
+};
+module_i2c_driver(es8323_i2c_driver);
+
+MODULE_DESCRIPTION("Everest Semi ES8323 ALSA SoC Codec Driver");
+MODULE_AUTHOR("Mark Brown <[email protected]>");
+MODULE_AUTHOR("Binbin Zhou <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8323.h b/sound/soc/codecs/es8323.h
new file mode 100644
index 000000000000..f986c9301dc6
--- /dev/null
+++ b/sound/soc/codecs/es8323.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright Openedhand Ltd.
+ *
+ * Author: Richard Purdie <[email protected]>
+ * Binbin Zhou <[email protected]>
+ *
+ */
+
+#ifndef _ES8323_H
+#define _ES8323_H
+
+/* ES8323 register space */
+
+/* Chip Control and Power Management */
+#define ES8323_CONTROL1 0x00
+#define ES8323_CONTROL2 0x01
+#define ES8323_CHIPPOWER 0x02
+#define ES8323_ADCPOWER 0x03
+#define ES8323_DACPOWER 0x04
+#define ES8323_CHIPLOPOW1 0x05
+#define ES8323_CHIPLOPOW2 0x06
+#define ES8323_ANAVOLMANAG 0x07
+#define ES8323_MASTERMODE 0x08
+
+/* ADC Control */
+#define ES8323_ADCCONTROL1 0x09
+#define ES8323_ADCCONTROL2 0x0a
+#define ES8323_ADCCONTROL3 0x0b
+#define ES8323_ADCCONTROL4 0x0c
+#define ES8323_ADCCONTROL5 0x0d
+#define ES8323_ADCCONTROL6 0x0e
+#define ES8323_ADC_MUTE 0x0f
+#define ES8323_LADC_VOL 0x10
+#define ES8323_RADC_VOL 0x11
+#define ES8323_ADCCONTROL10 0x12
+#define ES8323_ADCCONTROL11 0x13
+#define ES8323_ADCCONTROL12 0x14
+#define ES8323_ADCCONTROL13 0x15
+#define ES8323_ADCCONTROL14 0x16
+
+/* DAC Control */
+#define ES8323_DACCONTROL1 0x17
+#define ES8323_DACCONTROL2 0x18
+#define ES8323_DAC_MUTE 0x19
+#define ES8323_LDAC_VOL 0x1a
+#define ES8323_RDAC_VOL 0x1b
+#define ES8323_DACCONTROL6 0x1c
+#define ES8323_DACCONTROL7 0x1d
+#define ES8323_DACCONTROL8 0x1e
+#define ES8323_DACCONTROL9 0x1f
+#define ES8323_DACCONTROL10 0x20
+#define ES8323_DACCONTROL11 0x21
+#define ES8323_DACCONTROL12 0x22
+#define ES8323_DACCONTROL13 0x23
+#define ES8323_DACCONTROL14 0x24
+#define ES8323_DACCONTROL15 0x25
+#define ES8323_DACCONTROL16 0x26
+#define ES8323_DACCONTROL17 0x27
+#define ES8323_DACCONTROL18 0x28
+#define ES8323_DACCONTROL19 0x29
+#define ES8323_DACCONTROL20 0x2a
+#define ES8323_DACCONTROL21 0x2b
+#define ES8323_DACCONTROL22 0x2c
+#define ES8323_DACCONTROL23 0x2d
+#define ES8323_LOUT1_VOL 0x2e
+#define ES8323_ROUT1_VOL 0x2f
+#define ES8323_LOUT2_VOL 0x30
+#define ES8323_ROUT2_VOL 0x31
+#define ES8323_DACCONTROL28 0x32
+#define ES8323_DACCONTROL29 0x33
+#define ES8323_DACCONTROL30 0x34
+
+#define ES8323_ADC_IFACE ES8323_ADCCONTROL4
+#define ES8323_ADC_SRATE ES8323_ADCCONTROL5
+#define ES8323_DAC_IFACE ES8323_DACCONTROL1
+#define ES8323_DAC_SRATE ES8323_DACCONTROL2
+#endif
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
index d5362b3be484..a5603b617688 100644
--- a/sound/soc/codecs/es8326.c
+++ b/sound/soc/codecs/es8326.c
@@ -614,6 +614,10 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction)
} else {
regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE,
0x0F, 0x0F);
+ if (es8326->version > ES8326_VERSION_B) {
+ regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x40);
+ regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x70, 0x10);
+ }
}
} else {
if (!es8326->calibrated) {
@@ -640,6 +644,10 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction)
ES8326_MUTE_MASK, ~(ES8326_MUTE));
} else {
msleep(300);
+ if (es8326->version > ES8326_VERSION_B) {
+ regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x70, 0x50);
+ regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x00);
+ }
regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE,
0x0F, 0x00);
}
@@ -821,7 +829,7 @@ static void es8326_jack_detect_handler(struct work_struct *work)
iface = snd_soc_component_read(comp, ES8326_HPDET_STA);
dev_dbg(comp->dev, "gpio flag %#04x", iface);
- if ((es8326->jack_remove_retry == 1) && (es8326->version != ES8326_VERSION_B)) {
+ if ((es8326->jack_remove_retry == 1) && (es8326->version < ES8326_VERSION_B)) {
if (iface & ES8326_HPINSERT_FLAG)
es8326->jack_remove_retry = 2;
else
@@ -859,7 +867,7 @@ static void es8326_jack_detect_handler(struct work_struct *work)
/*
* Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event
*/
- if ((es8326->jack_remove_retry == 0) && (es8326->version != ES8326_VERSION_B)) {
+ if ((es8326->jack_remove_retry == 0) && (es8326->version < ES8326_VERSION_B)) {
es8326->jack_remove_retry = 1;
dev_dbg(comp->dev, "remove event check, invert HPJACK_POL, cnt = %d\n",
es8326->jack_remove_retry);
@@ -954,7 +962,7 @@ static int es8326_calibrate(struct snd_soc_component *component)
regmap_read(es8326->regmap, ES8326_CHIP_VERSION, &reg);
es8326->version = reg;
- if ((es8326->version == ES8326_VERSION_B) && (es8326->calibrated == false)) {
+ if ((es8326->version >= ES8326_VERSION_B) && (es8326->calibrated == false)) {
dev_dbg(component->dev, "ES8326_VERSION_B, calibrating\n");
regmap_write(es8326->regmap, ES8326_CLK_INV, 0xc0);
regmap_write(es8326->regmap, ES8326_CLK_DIV1, 0x03);
@@ -1047,7 +1055,7 @@ static void es8326_init(struct snd_soc_component *component)
regmap_write(es8326->regmap, ES8326_DAC_VPPSCALE, 0x15);
regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x80 |
- ((es8326->version == ES8326_VERSION_B) ?
+ ((es8326->version >= ES8326_VERSION_B) ?
(ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) :
(ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04)));
usleep_range(5000, 10000);
@@ -1073,6 +1081,10 @@ static void es8326_init(struct snd_soc_component *component)
regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x44);
regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x66);
es8326_disable_micbias(es8326->component);
+ if (es8326->version > ES8326_VERSION_B) {
+ regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x73, 0x13);
+ regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x40);
+ }
msleep(200);
regmap_write(es8326->regmap, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9);
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 74caae52e127..d9df29a26f4f 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -185,84 +185,97 @@ static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = {
/*
* hdmi_codec_channel_alloc: speaker configuration available for CEA
*
- * This is an ordered list that must match with hdmi_codec_8ch_chmaps struct
+ * This is an ordered list where ca_id must exist in hdmi_codec_8ch_chmaps
* The preceding ones have better chances to be selected by
* hdmi_codec_get_ch_alloc_table_idx().
*/
static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = {
{ .ca_id = 0x00, .n_ch = 2,
- .mask = FL | FR},
- /* 2.1 */
- { .ca_id = 0x01, .n_ch = 4,
- .mask = FL | FR | LFE},
- /* Dolby Surround */
+ .mask = FL | FR },
+ { .ca_id = 0x03, .n_ch = 4,
+ .mask = FL | FR | LFE | FC },
{ .ca_id = 0x02, .n_ch = 4,
.mask = FL | FR | FC },
- /* surround51 */
+ { .ca_id = 0x01, .n_ch = 4,
+ .mask = FL | FR | LFE },
{ .ca_id = 0x0b, .n_ch = 6,
- .mask = FL | FR | LFE | FC | RL | RR},
- /* surround40 */
- { .ca_id = 0x08, .n_ch = 6,
- .mask = FL | FR | RL | RR },
- /* surround41 */
- { .ca_id = 0x09, .n_ch = 6,
- .mask = FL | FR | LFE | RL | RR },
- /* surround50 */
+ .mask = FL | FR | LFE | FC | RL | RR },
{ .ca_id = 0x0a, .n_ch = 6,
.mask = FL | FR | FC | RL | RR },
- /* 6.1 */
- { .ca_id = 0x0f, .n_ch = 8,
- .mask = FL | FR | LFE | FC | RL | RR | RC },
- /* surround71 */
+ { .ca_id = 0x09, .n_ch = 6,
+ .mask = FL | FR | LFE | RL | RR },
+ { .ca_id = 0x08, .n_ch = 6,
+ .mask = FL | FR | RL | RR },
+ { .ca_id = 0x07, .n_ch = 6,
+ .mask = FL | FR | LFE | FC | RC },
+ { .ca_id = 0x06, .n_ch = 6,
+ .mask = FL | FR | FC | RC },
+ { .ca_id = 0x05, .n_ch = 6,
+ .mask = FL | FR | LFE | RC },
+ { .ca_id = 0x04, .n_ch = 6,
+ .mask = FL | FR | RC },
{ .ca_id = 0x13, .n_ch = 8,
.mask = FL | FR | LFE | FC | RL | RR | RLC | RRC },
- /* others */
- { .ca_id = 0x03, .n_ch = 8,
- .mask = FL | FR | LFE | FC },
- { .ca_id = 0x04, .n_ch = 8,
- .mask = FL | FR | RC},
- { .ca_id = 0x05, .n_ch = 8,
- .mask = FL | FR | LFE | RC },
- { .ca_id = 0x06, .n_ch = 8,
- .mask = FL | FR | FC | RC },
- { .ca_id = 0x07, .n_ch = 8,
- .mask = FL | FR | LFE | FC | RC },
- { .ca_id = 0x0c, .n_ch = 8,
- .mask = FL | FR | RC | RL | RR },
- { .ca_id = 0x0d, .n_ch = 8,
- .mask = FL | FR | LFE | RL | RR | RC },
- { .ca_id = 0x0e, .n_ch = 8,
- .mask = FL | FR | FC | RL | RR | RC },
- { .ca_id = 0x10, .n_ch = 8,
- .mask = FL | FR | RL | RR | RLC | RRC },
- { .ca_id = 0x11, .n_ch = 8,
- .mask = FL | FR | LFE | RL | RR | RLC | RRC },
+ { .ca_id = 0x1f, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC },
{ .ca_id = 0x12, .n_ch = 8,
.mask = FL | FR | FC | RL | RR | RLC | RRC },
- { .ca_id = 0x14, .n_ch = 8,
- .mask = FL | FR | FLC | FRC },
- { .ca_id = 0x15, .n_ch = 8,
- .mask = FL | FR | LFE | FLC | FRC },
- { .ca_id = 0x16, .n_ch = 8,
- .mask = FL | FR | FC | FLC | FRC },
- { .ca_id = 0x17, .n_ch = 8,
- .mask = FL | FR | LFE | FC | FLC | FRC },
- { .ca_id = 0x18, .n_ch = 8,
- .mask = FL | FR | RC | FLC | FRC },
- { .ca_id = 0x19, .n_ch = 8,
- .mask = FL | FR | LFE | RC | FLC | FRC },
- { .ca_id = 0x1a, .n_ch = 8,
- .mask = FL | FR | RC | FC | FLC | FRC },
- { .ca_id = 0x1b, .n_ch = 8,
- .mask = FL | FR | LFE | RC | FC | FLC | FRC },
- { .ca_id = 0x1c, .n_ch = 8,
- .mask = FL | FR | RL | RR | FLC | FRC },
- { .ca_id = 0x1d, .n_ch = 8,
- .mask = FL | FR | LFE | RL | RR | FLC | FRC },
{ .ca_id = 0x1e, .n_ch = 8,
.mask = FL | FR | FC | RL | RR | FLC | FRC },
- { .ca_id = 0x1f, .n_ch = 8,
- .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC },
+ { .ca_id = 0x11, .n_ch = 8,
+ .mask = FL | FR | LFE | RL | RR | RLC | RRC },
+ { .ca_id = 0x1d, .n_ch = 8,
+ .mask = FL | FR | LFE | RL | RR | FLC | FRC },
+ { .ca_id = 0x10, .n_ch = 8,
+ .mask = FL | FR | RL | RR | RLC | RRC },
+ { .ca_id = 0x1c, .n_ch = 8,
+ .mask = FL | FR | RL | RR | FLC | FRC },
+ { .ca_id = 0x0f, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | RL | RR | RC },
+ { .ca_id = 0x1b, .n_ch = 8,
+ .mask = FL | FR | LFE | RC | FC | FLC | FRC },
+ { .ca_id = 0x0e, .n_ch = 8,
+ .mask = FL | FR | FC | RL | RR | RC },
+ { .ca_id = 0x1a, .n_ch = 8,
+ .mask = FL | FR | RC | FC | FLC | FRC },
+ { .ca_id = 0x0d, .n_ch = 8,
+ .mask = FL | FR | LFE | RL | RR | RC },
+ { .ca_id = 0x19, .n_ch = 8,
+ .mask = FL | FR | LFE | RC | FLC | FRC },
+ { .ca_id = 0x0c, .n_ch = 8,
+ .mask = FL | FR | RC | RL | RR },
+ { .ca_id = 0x18, .n_ch = 8,
+ .mask = FL | FR | RC | FLC | FRC },
+ { .ca_id = 0x17, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | FLC | FRC },
+ { .ca_id = 0x16, .n_ch = 8,
+ .mask = FL | FR | FC | FLC | FRC },
+ { .ca_id = 0x15, .n_ch = 8,
+ .mask = FL | FR | LFE | FLC | FRC },
+ { .ca_id = 0x14, .n_ch = 8,
+ .mask = FL | FR | FLC | FRC },
+ { .ca_id = 0x0b, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | RL | RR },
+ { .ca_id = 0x0a, .n_ch = 8,
+ .mask = FL | FR | FC | RL | RR },
+ { .ca_id = 0x09, .n_ch = 8,
+ .mask = FL | FR | LFE | RL | RR },
+ { .ca_id = 0x08, .n_ch = 8,
+ .mask = FL | FR | RL | RR },
+ { .ca_id = 0x07, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | RC },
+ { .ca_id = 0x06, .n_ch = 8,
+ .mask = FL | FR | FC | RC },
+ { .ca_id = 0x05, .n_ch = 8,
+ .mask = FL | FR | LFE | RC },
+ { .ca_id = 0x04, .n_ch = 8,
+ .mask = FL | FR | RC },
+ { .ca_id = 0x03, .n_ch = 8,
+ .mask = FL | FR | LFE | FC },
+ { .ca_id = 0x02, .n_ch = 8,
+ .mask = FL | FR | FC },
+ { .ca_id = 0x01, .n_ch = 8,
+ .mask = FL | FR | LFE },
};
struct hdmi_codec_priv {
@@ -371,7 +384,8 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
struct hdmi_codec_priv *hcp = info->private_data;
- map = info->chmap[hcp->chmap_idx].map;
+ if (hcp->chmap_idx != HDMI_CODEC_CHMAP_IDX_UNKNOWN)
+ map = info->chmap[hcp->chmap_idx].map;
for (i = 0; i < info->max_channels; i++) {
if (hcp->chmap_idx == HDMI_CODEC_CHMAP_IDX_UNKNOWN)
diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c
index e4793a5d179e..8af3c7e5317f 100644
--- a/sound/soc/codecs/max9768.c
+++ b/sound/soc/codecs/max9768.c
@@ -54,10 +54,17 @@ static int max9768_set_gpio(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
struct max9768 *max9768 = snd_soc_component_get_drvdata(c);
+ bool val = !ucontrol->value.integer.value[0];
+ int ret;
- gpiod_set_value_cansleep(max9768->mute, !ucontrol->value.integer.value[0]);
+ if (val != gpiod_get_value_cansleep(max9768->mute))
+ ret = 1;
+ else
+ ret = 0;
- return 0;
+ gpiod_set_value_cansleep(max9768->mute, val);
+
+ return ret;
}
static const DECLARE_TLV_DB_RANGE(volume_tlv,
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 8b0645c63462..8915f5250695 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -480,12 +480,18 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = {
SOC_SINGLE("INA Volume", M98088_REG_37_LVL_INA, 0, 7, 1),
SOC_SINGLE("INB Volume", M98088_REG_38_LVL_INB, 0, 7, 1),
+ SOC_SINGLE("DACL Volume", M98088_REG_2F_LVL_DAI1_PLAY, 0, 15, 1),
+ SOC_SINGLE("DACR Volume", M98088_REG_31_LVL_DAI2_PLAY, 0, 15, 1),
+
SOC_SINGLE("ADCL Volume", M98088_REG_33_LVL_ADC_L, 0, 15, 0),
SOC_SINGLE("ADCR Volume", M98088_REG_34_LVL_ADC_R, 0, 15, 0),
SOC_SINGLE("ADCL Boost Volume", M98088_REG_33_LVL_ADC_L, 4, 3, 0),
SOC_SINGLE("ADCR Boost Volume", M98088_REG_34_LVL_ADC_R, 4, 3, 0),
+ SOC_SINGLE("Left HP Output Mixer Switch", M98088_REG_27_MIX_HP_CNTL, 4, 1, 0),
+ SOC_SINGLE("Right HP Output Mixer Switch", M98088_REG_27_MIX_HP_CNTL, 5, 1, 0),
+
SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0),
SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0),
@@ -515,10 +521,8 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = {
/* Left speaker mixer switch */
static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
- SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
- SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
- SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
- SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0),
SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0),
SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0),
@@ -529,10 +533,8 @@ static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
/* Right speaker mixer switch */
static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = {
- SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
- SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
- SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
- SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 5, 1, 0),
SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 6, 1, 0),
SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 1, 1, 0),
@@ -543,10 +545,8 @@ static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = {
/* Left headphone mixer switch */
static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
- SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
- SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
- SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
- SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0),
SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0),
SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0),
@@ -557,10 +557,8 @@ static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
/* Right headphone mixer switch */
static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = {
- SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
- SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
- SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
- SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 5, 1, 0),
SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 6, 1, 0),
SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_26_MIX_HP_RIGHT, 1, 1, 0),
@@ -571,10 +569,8 @@ static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = {
/* Left earpiece/receiver mixer switch */
static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
- SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
- SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
- SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
- SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0),
SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0),
SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0),
@@ -585,10 +581,8 @@ static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
/* Right earpiece/receiver mixer switch */
static const struct snd_kcontrol_new max98088_right_rec_mixer_controls[] = {
- SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
- SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
- SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
- SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 5, 1, 0),
SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 6, 1, 0),
SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_29_MIX_REC_RIGHT, 1, 1, 0),
@@ -717,13 +711,9 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 1, 0),
SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 0, 0),
- SND_SOC_DAPM_DAC("DACL1", "HiFi Playback",
- M98088_REG_4D_PWR_EN_OUT, 1, 0),
- SND_SOC_DAPM_DAC("DACR1", "HiFi Playback",
- M98088_REG_4D_PWR_EN_OUT, 0, 0),
- SND_SOC_DAPM_DAC("DACL2", "Aux Playback",
+ SND_SOC_DAPM_DAC("DACL", "HiFi Playback",
M98088_REG_4D_PWR_EN_OUT, 1, 0),
- SND_SOC_DAPM_DAC("DACR2", "Aux Playback",
+ SND_SOC_DAPM_DAC("DACR", "HiFi Playback",
M98088_REG_4D_PWR_EN_OUT, 0, 0),
SND_SOC_DAPM_PGA("HP Left Out", M98088_REG_4D_PWR_EN_OUT,
@@ -819,10 +809,8 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
static const struct snd_soc_dapm_route max98088_audio_map[] = {
/* Left headphone output mixer */
- {"Left HP Mixer", "Left DAC1 Switch", "DACL1"},
- {"Left HP Mixer", "Left DAC2 Switch", "DACL2"},
- {"Left HP Mixer", "Right DAC1 Switch", "DACR1"},
- {"Left HP Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left HP Mixer", "Left DAC Switch", "DACL"},
+ {"Left HP Mixer", "Right DAC Switch", "DACR"},
{"Left HP Mixer", "MIC1 Switch", "MIC1 Input"},
{"Left HP Mixer", "MIC2 Switch", "MIC2 Input"},
{"Left HP Mixer", "INA1 Switch", "INA1 Input"},
@@ -831,10 +819,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = {
{"Left HP Mixer", "INB2 Switch", "INB2 Input"},
/* Right headphone output mixer */
- {"Right HP Mixer", "Left DAC1 Switch", "DACL1"},
- {"Right HP Mixer", "Left DAC2 Switch", "DACL2" },
- {"Right HP Mixer", "Right DAC1 Switch", "DACR1"},
- {"Right HP Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right HP Mixer", "Left DAC Switch", "DACL"},
+ {"Right HP Mixer", "Right DAC Switch", "DACR"},
{"Right HP Mixer", "MIC1 Switch", "MIC1 Input"},
{"Right HP Mixer", "MIC2 Switch", "MIC2 Input"},
{"Right HP Mixer", "INA1 Switch", "INA1 Input"},
@@ -843,10 +829,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = {
{"Right HP Mixer", "INB2 Switch", "INB2 Input"},
/* Left speaker output mixer */
- {"Left SPK Mixer", "Left DAC1 Switch", "DACL1"},
- {"Left SPK Mixer", "Left DAC2 Switch", "DACL2"},
- {"Left SPK Mixer", "Right DAC1 Switch", "DACR1"},
- {"Left SPK Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left SPK Mixer", "Left DAC Switch", "DACL"},
+ {"Left SPK Mixer", "Right DAC Switch", "DACR"},
{"Left SPK Mixer", "MIC1 Switch", "MIC1 Input"},
{"Left SPK Mixer", "MIC2 Switch", "MIC2 Input"},
{"Left SPK Mixer", "INA1 Switch", "INA1 Input"},
@@ -855,10 +839,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = {
{"Left SPK Mixer", "INB2 Switch", "INB2 Input"},
/* Right speaker output mixer */
- {"Right SPK Mixer", "Left DAC1 Switch", "DACL1"},
- {"Right SPK Mixer", "Left DAC2 Switch", "DACL2"},
- {"Right SPK Mixer", "Right DAC1 Switch", "DACR1"},
- {"Right SPK Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right SPK Mixer", "Left DAC Switch", "DACL"},
+ {"Right SPK Mixer", "Right DAC Switch", "DACR"},
{"Right SPK Mixer", "MIC1 Switch", "MIC1 Input"},
{"Right SPK Mixer", "MIC2 Switch", "MIC2 Input"},
{"Right SPK Mixer", "INA1 Switch", "INA1 Input"},
@@ -867,10 +849,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = {
{"Right SPK Mixer", "INB2 Switch", "INB2 Input"},
/* Earpiece/Receiver output mixer */
- {"Left REC Mixer", "Left DAC1 Switch", "DACL1"},
- {"Left REC Mixer", "Left DAC2 Switch", "DACL2"},
- {"Left REC Mixer", "Right DAC1 Switch", "DACR1"},
- {"Left REC Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left REC Mixer", "Left DAC Switch", "DACL"},
+ {"Left REC Mixer", "Right DAC Switch", "DACR"},
{"Left REC Mixer", "MIC1 Switch", "MIC1 Input"},
{"Left REC Mixer", "MIC2 Switch", "MIC2 Input"},
{"Left REC Mixer", "INA1 Switch", "INA1 Input"},
@@ -879,10 +859,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = {
{"Left REC Mixer", "INB2 Switch", "INB2 Input"},
/* Earpiece/Receiver output mixer */
- {"Right REC Mixer", "Left DAC1 Switch", "DACL1"},
- {"Right REC Mixer", "Left DAC2 Switch", "DACL2"},
- {"Right REC Mixer", "Right DAC1 Switch", "DACR1"},
- {"Right REC Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right REC Mixer", "Left DAC Switch", "DACL"},
+ {"Right REC Mixer", "Right DAC Switch", "DACR"},
{"Right REC Mixer", "MIC1 Switch", "MIC1 Input"},
{"Right REC Mixer", "MIC2 Switch", "MIC2 Input"},
{"Right REC Mixer", "INA1 Switch", "INA1 Input"},
diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c
index de5c4db05c8f..edb95f869a4a 100644
--- a/sound/soc/codecs/nau8821.c
+++ b/sound/soc/codecs/nau8821.c
@@ -287,10 +287,8 @@ static int nau8821_biq_coeff_get(struct snd_kcontrol *kcontrol,
if (!component->regmap)
return -EINVAL;
- regmap_raw_read(component->regmap, NAU8821_R21_BIQ0_COF1,
+ return regmap_raw_read(component->regmap, NAU8821_R21_BIQ0_COF1,
ucontrol->value.bytes.data, params->max);
-
- return 0;
}
static int nau8821_biq_coeff_put(struct snd_kcontrol *kcontrol,
@@ -299,6 +297,7 @@ static int nau8821_biq_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_bytes_ext *params = (void *)kcontrol->private_value;
void *data;
+ int ret;
if (!component->regmap)
return -EINVAL;
@@ -308,12 +307,12 @@ static int nau8821_biq_coeff_put(struct snd_kcontrol *kcontrol,
if (!data)
return -ENOMEM;
- regmap_raw_write(component->regmap, NAU8821_R21_BIQ0_COF1,
+ ret = regmap_raw_write(component->regmap, NAU8821_R21_BIQ0_COF1,
data, params->max);
kfree(data);
- return 0;
+ return ret;
}
static const char * const nau8821_adc_decimation[] = {
diff --git a/sound/soc/codecs/ntp8835.c b/sound/soc/codecs/ntp8835.c
new file mode 100644
index 000000000000..796e1410496f
--- /dev/null
+++ b/sound/soc/codecs/ntp8835.c
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for the NTP8835/NTP8835C Audio Amplifiers
+ *
+ * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
+ *
+ * Author: Igor Prusov <[email protected]>
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/bits.h>
+#include <linux/reset.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <sound/initval.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-component.h>
+#include <sound/tlv.h>
+
+#include "ntpfw.h"
+
+#define NTP8835_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define NTP8835_INPUT_FMT 0x0
+#define NTP8835_INPUT_FMT_MASTER_MODE BIT(0)
+#define NTP8835_INPUT_FMT_GSA_MODE BIT(1)
+#define NTP8835_GSA_FMT 0x1
+#define NTP8835_GSA_BS_MASK GENMASK(3, 2)
+#define NTP8835_GSA_BS(x) ((x) << 2)
+#define NTP8835_GSA_RIGHT_J BIT(0)
+#define NTP8835_GSA_LSB BIT(1)
+#define NTP8835_MCLK_FREQ_CTRL 0x2
+#define NTP8835_MCLK_FREQ_MCF GENMASK(1, 0)
+#define NTP8835_SOFT_MUTE 0x26
+#define NTP8835_SOFT_MUTE_SM1 BIT(0)
+#define NTP8835_SOFT_MUTE_SM2 BIT(1)
+#define NTP8835_SOFT_MUTE_SM3 BIT(2)
+#define NTP8835_PWM_SWITCH 0x27
+#define NTP8835_PWM_SWITCH_POF1 BIT(0)
+#define NTP8835_PWM_SWITCH_POF2 BIT(1)
+#define NTP8835_PWM_SWITCH_POF3 BIT(2)
+#define NTP8835_PWM_MASK_CTRL0 0x28
+#define NTP8835_PWM_MASK_CTRL0_OUT_LOW BIT(1)
+#define NTP8835_PWM_MASK_CTRL0_FPMLD BIT(2)
+#define NTP8835_MASTER_VOL 0x2e
+#define NTP8835_CHNL_A_VOL 0x2f
+#define NTP8835_CHNL_B_VOL 0x30
+#define NTP8835_CHNL_C_VOL 0x31
+#define REG_MAX NTP8835_CHNL_C_VOL
+
+#define NTP8835_FW_NAME "eq_8835.bin"
+#define NTP8835_FW_MAGIC 0x38383335 /* "8835" */
+
+struct ntp8835_priv {
+ struct i2c_client *i2c;
+ struct reset_control *reset;
+ unsigned int format;
+ struct clk *mclk;
+ unsigned int mclk_rate;
+};
+
+static const DECLARE_TLV_DB_RANGE(ntp8835_vol_scale,
+ 0, 1, TLV_DB_SCALE_ITEM(-15000, 0, 0),
+ 2, 6, TLV_DB_SCALE_ITEM(-15000, 1000, 0),
+ 7, 0xff, TLV_DB_SCALE_ITEM(-10000, 50, 0),
+);
+
+static int ntp8835_mute_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->access =
+ (SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE);
+ uinfo->count = 1;
+
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ uinfo->value.integer.step = 1;
+
+ return 0;
+}
+
+static int ntp8835_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ unsigned int val;
+
+ val = snd_soc_component_read(component, NTP8835_SOFT_MUTE);
+
+ ucontrol->value.integer.value[0] = val ? 0 : 1;
+ return 0;
+}
+
+static int ntp8835_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ unsigned int val;
+
+ val = ucontrol->value.integer.value[0] ? 0 : 7;
+
+ snd_soc_component_write(component, NTP8835_SOFT_MUTE, val);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new ntp8835_vol_control[] = {
+ SOC_SINGLE_TLV("Playback Volume", NTP8835_MASTER_VOL, 0,
+ 0xff, 0, ntp8835_vol_scale),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Playback Switch",
+ .info = ntp8835_mute_info,
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .get = ntp8835_mute_get,
+ .put = ntp8835_mute_put,
+ },
+};
+
+static void ntp8835_reset_gpio(struct ntp8835_priv *ntp8835)
+{
+ /*
+ * Proper initialization sequence for NTP835 amplifier requires driving
+ * /RESET signal low during power up for at least 0.1us. The sequence is,
+ * according to NTP8835 datasheet, 6.2 Timing Sequence (recommended):
+ * Deassert for T2 >= 1ms...
+ */
+ reset_control_deassert(ntp8835->reset);
+ fsleep(1000);
+
+ /* ...Assert for T3 >= 0.1us... */
+ reset_control_assert(ntp8835->reset);
+ fsleep(1);
+
+ /* ...Deassert, and wait for T4 >= 0.5ms before sound on sequence. */
+ reset_control_deassert(ntp8835->reset);
+ fsleep(500);
+}
+
+static const struct reg_sequence ntp8835_sound_on[] = {
+ { NTP8835_PWM_MASK_CTRL0, NTP8835_PWM_MASK_CTRL0_FPMLD },
+ { NTP8835_PWM_SWITCH, 0x00 },
+ { NTP8835_SOFT_MUTE, 0x00 },
+};
+
+static const struct reg_sequence ntp8835_sound_off[] = {
+ { NTP8835_SOFT_MUTE, NTP8835_SOFT_MUTE_SM1 |
+ NTP8835_SOFT_MUTE_SM2 |
+ NTP8835_SOFT_MUTE_SM3 },
+
+ { NTP8835_PWM_SWITCH, NTP8835_PWM_SWITCH_POF1 |
+ NTP8835_PWM_SWITCH_POF2 |
+ NTP8835_PWM_SWITCH_POF3 },
+
+ { NTP8835_PWM_MASK_CTRL0, NTP8835_PWM_MASK_CTRL0_OUT_LOW |
+ NTP8835_PWM_MASK_CTRL0_FPMLD },
+};
+
+static int ntp8835_load_firmware(struct ntp8835_priv *ntp8835)
+{
+ int ret;
+
+ ret = ntpfw_load(ntp8835->i2c, NTP8835_FW_NAME, NTP8835_FW_MAGIC);
+ if (ret == -ENOENT) {
+ dev_warn_once(&ntp8835->i2c->dev,
+ "Could not find firmware %s\n", NTP8835_FW_NAME);
+ return 0;
+ }
+
+ return ret;
+}
+
+static int ntp8835_snd_suspend(struct snd_soc_component *component)
+{
+ struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(component->regmap, true);
+
+ regmap_multi_reg_write_bypassed(component->regmap,
+ ntp8835_sound_off,
+ ARRAY_SIZE(ntp8835_sound_off));
+
+ /*
+ * According to NTP8835 datasheet, 6.2 Timing Sequence (recommended):
+ * wait after sound off for T6 >= 0.5ms
+ */
+ fsleep(500);
+ reset_control_assert(ntp8835->reset);
+
+ regcache_mark_dirty(component->regmap);
+ clk_disable_unprepare(ntp8835->mclk);
+
+ return 0;
+}
+
+static int ntp8835_snd_resume(struct snd_soc_component *component)
+{
+ struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ ntp8835_reset_gpio(ntp8835);
+ ret = clk_prepare_enable(ntp8835->mclk);
+ if (ret)
+ return ret;
+
+ regmap_multi_reg_write_bypassed(component->regmap,
+ ntp8835_sound_on,
+ ARRAY_SIZE(ntp8835_sound_on));
+
+ ret = ntp8835_load_firmware(ntp8835);
+ if (ret) {
+ dev_err(&ntp8835->i2c->dev, "Failed to load firmware\n");
+ return ret;
+ }
+
+ regcache_cache_only(component->regmap, false);
+ snd_soc_component_cache_sync(component);
+
+ return 0;
+}
+
+static int ntp8835_probe(struct snd_soc_component *component)
+{
+ int ret;
+ struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
+ struct device *dev = component->dev;
+
+ ret = snd_soc_add_component_controls(component, ntp8835_vol_control,
+ ARRAY_SIZE(ntp8835_vol_control));
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add controls\n");
+
+ ret = ntp8835_load_firmware(ntp8835);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to load firmware\n");
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget ntp8835_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("AIFIN", "Playback", SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_OUTPUT("OUT1"),
+ SND_SOC_DAPM_OUTPUT("OUT2"),
+ SND_SOC_DAPM_OUTPUT("OUT3"),
+};
+
+static const struct snd_soc_dapm_route ntp8835_dapm_routes[] = {
+ { "OUT1", NULL, "AIFIN" },
+ { "OUT2", NULL, "AIFIN" },
+ { "OUT3", NULL, "AIFIN" },
+};
+
+static int ntp8835_set_component_sysclk(struct snd_soc_component *component,
+ int clk_id, int source,
+ unsigned int freq, int dir)
+{
+ struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
+
+ switch (freq) {
+ case 12288000:
+ case 24576000:
+ case 18432000:
+ ntp8835->mclk_rate = freq;
+ break;
+ default:
+ ntp8835->mclk_rate = 0;
+ dev_err(component->dev, "Unsupported MCLK value: %u", freq);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_ntp8835 = {
+ .probe = ntp8835_probe,
+ .suspend = ntp8835_snd_suspend,
+ .resume = ntp8835_snd_resume,
+ .dapm_widgets = ntp8835_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ntp8835_dapm_widgets),
+ .dapm_routes = ntp8835_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(ntp8835_dapm_routes),
+ .set_sysclk = ntp8835_set_component_sysclk,
+};
+
+static int ntp8835_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 ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
+ unsigned int input_fmt = 0;
+ unsigned int gsa_fmt = 0;
+ unsigned int gsa_fmt_mask;
+ unsigned int mcf;
+ int ret;
+
+ switch (ntp8835->mclk_rate) {
+ case 12288000:
+ mcf = 0;
+ break;
+ case 24576000:
+ mcf = 1;
+ break;
+ case 18432000:
+ mcf = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = snd_soc_component_update_bits(component, NTP8835_MCLK_FREQ_CTRL,
+ NTP8835_MCLK_FREQ_MCF, mcf);
+ if (ret)
+ return ret;
+
+ switch (ntp8835->format) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ input_fmt |= NTP8835_INPUT_FMT_GSA_MODE;
+ gsa_fmt |= NTP8835_GSA_RIGHT_J;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ input_fmt |= NTP8835_INPUT_FMT_GSA_MODE;
+ break;
+ }
+
+ ret = snd_soc_component_update_bits(component, NTP8835_INPUT_FMT,
+ NTP8835_INPUT_FMT_MASTER_MODE |
+ NTP8835_INPUT_FMT_GSA_MODE,
+ input_fmt);
+
+ if (!(input_fmt & NTP8835_INPUT_FMT_GSA_MODE) || ret < 0)
+ return ret;
+
+ switch (params_width(params)) {
+ case 24:
+ gsa_fmt |= NTP8835_GSA_BS(0);
+ break;
+ case 20:
+ gsa_fmt |= NTP8835_GSA_BS(1);
+ break;
+ case 18:
+ gsa_fmt |= NTP8835_GSA_BS(2);
+ break;
+ case 16:
+ gsa_fmt |= NTP8835_GSA_BS(3);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ gsa_fmt_mask = NTP8835_GSA_BS_MASK |
+ NTP8835_GSA_RIGHT_J |
+ NTP8835_GSA_LSB;
+ return snd_soc_component_update_bits(component, NTP8835_GSA_FMT,
+ gsa_fmt_mask, gsa_fmt);
+}
+
+static int ntp8835_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ case SND_SOC_DAIFMT_LEFT_J:
+ ntp8835->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+};
+
+static const struct snd_soc_dai_ops ntp8835_dai_ops = {
+ .hw_params = ntp8835_hw_params,
+ .set_fmt = ntp8835_set_fmt,
+};
+
+static struct snd_soc_dai_driver ntp8835_dai = {
+ .name = "ntp8835-amplifier",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 3,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = NTP8835_FORMATS,
+ },
+ .ops = &ntp8835_dai_ops,
+};
+
+static const struct regmap_config ntp8835_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_MAX,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static int ntp8835_i2c_probe(struct i2c_client *i2c)
+{
+ struct ntp8835_priv *ntp8835;
+ struct regmap *regmap;
+ int ret;
+
+ ntp8835 = devm_kzalloc(&i2c->dev, sizeof(*ntp8835), GFP_KERNEL);
+ if (!ntp8835)
+ return -ENOMEM;
+
+ ntp8835->i2c = i2c;
+
+ ntp8835->reset = devm_reset_control_get_shared(&i2c->dev, NULL);
+ if (IS_ERR(ntp8835->reset))
+ return dev_err_probe(&i2c->dev, PTR_ERR(ntp8835->reset),
+ "Failed to get reset\n");
+
+ ret = reset_control_deassert(ntp8835->reset);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret,
+ "Failed to deassert reset\n");
+
+ dev_set_drvdata(&i2c->dev, ntp8835);
+
+ ntp8835_reset_gpio(ntp8835);
+
+ regmap = devm_regmap_init_i2c(i2c, &ntp8835_regmap);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(regmap),
+ "Failed to allocate regmap\n");
+
+ ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_ntp8835,
+ &ntp8835_dai, 1);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret,
+ "Failed to register component\n");
+
+ ntp8835->mclk = devm_clk_get_enabled(&i2c->dev, "mclk");
+ if (IS_ERR(ntp8835->mclk))
+ return dev_err_probe(&i2c->dev, PTR_ERR(ntp8835->mclk), "failed to get mclk\n");
+
+ return 0;
+}
+
+static const struct i2c_device_id ntp8835_i2c_id[] = {
+ { "ntp8835", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ntp8835_i2c_id);
+
+static const struct of_device_id ntp8835_of_match[] = {
+ {.compatible = "neofidelity,ntp8835",},
+ {}
+};
+MODULE_DEVICE_TABLE(of, ntp8835_of_match);
+
+static struct i2c_driver ntp8835_i2c_driver = {
+ .probe = ntp8835_i2c_probe,
+ .id_table = ntp8835_i2c_id,
+ .driver = {
+ .name = "ntp8835",
+ .of_match_table = ntp8835_of_match,
+ },
+};
+module_i2c_driver(ntp8835_i2c_driver);
+
+MODULE_AUTHOR("Igor Prusov <[email protected]>");
+MODULE_DESCRIPTION("NTP8835 Audio Amplifier Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ntp8918.c b/sound/soc/codecs/ntp8918.c
new file mode 100644
index 000000000000..0493ab6acbe4
--- /dev/null
+++ b/sound/soc/codecs/ntp8918.c
@@ -0,0 +1,397 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for the NTP8918 Audio Amplifier
+ *
+ * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
+ *
+ * Author: Igor Prusov <[email protected]>
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
+#include <sound/initval.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-component.h>
+#include <sound/tlv.h>
+
+#include "ntpfw.h"
+
+#define NTP8918_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+
+#define NTP8918_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define NTP8918_INPUT_FMT 0x0
+#define NTP8918_INPUT_FMT_MASTER_MODE BIT(0)
+#define NTP8918_INPUT_FMT_GSA_MODE BIT(1)
+#define NTP8918_GSA_FMT 0x1
+#define NTP8918_GSA_BS_MASK GENMASK(3, 2)
+#define NTP8918_GSA_BS(x) ((x) << 2)
+#define NTP8918_GSA_RIGHT_J BIT(0)
+#define NTP8918_GSA_LSB BIT(1)
+#define NTP8918_MCLK_FREQ_CTRL 0x2
+#define NTP8918_MCLK_FREQ_MCF GENMASK(1, 0)
+#define NTP8918_MASTER_VOL 0x0C
+#define NTP8918_CHNL_A_VOL 0x17
+#define NTP8918_CHNL_B_VOL 0x18
+#define NTP8918_SOFT_MUTE 0x33
+#define NTP8918_SOFT_MUTE_SM1 BIT(0)
+#define NTP8918_SOFT_MUTE_SM2 BIT(1)
+#define NTP8918_PWM_SWITCH 0x34
+#define NTP8918_PWM_MASK_CTRL0 0x35
+#define REG_MAX NTP8918_PWM_MASK_CTRL0
+
+#define NTP8918_FW_NAME "eq_8918.bin"
+#define NTP8918_FW_MAGIC 0x38393138 /* "8918" */
+
+struct ntp8918_priv {
+ struct i2c_client *i2c;
+ struct clk *bck;
+ struct reset_control *reset;
+ unsigned int format;
+};
+
+static const DECLARE_TLV_DB_SCALE(ntp8918_master_vol_scale, -12550, 50, 0);
+
+static const struct snd_kcontrol_new ntp8918_vol_control[] = {
+ SOC_SINGLE_RANGE_TLV("Playback Volume", NTP8918_MASTER_VOL, 0,
+ 0x04, 0xff, 0, ntp8918_master_vol_scale),
+ SOC_SINGLE("Playback Switch", NTP8918_PWM_MASK_CTRL0, 1, 1, 1),
+};
+
+static void ntp8918_reset_gpio(struct ntp8918_priv *ntp8918)
+{
+ /*
+ * Proper initialization sequence for NTP8918 amplifier requires driving
+ * /RESET signal low during power up for at least 0.1us. The sequence is,
+ * according to NTP8918 datasheet, 6.2 Timing Sequence 1:
+ * Deassert for T2 >= 1ms...
+ */
+ reset_control_deassert(ntp8918->reset);
+ fsleep(1000);
+
+ /* ...Assert for T3 >= 0.1us... */
+ reset_control_assert(ntp8918->reset);
+ fsleep(1);
+
+ /* ...Deassert, and wait for T4 >= 0.5ms before sound on sequence. */
+ reset_control_deassert(ntp8918->reset);
+ fsleep(500);
+}
+
+static const struct reg_sequence ntp8918_sound_off[] = {
+ { NTP8918_MASTER_VOL, 0 },
+};
+
+static const struct reg_sequence ntp8918_sound_on[] = {
+ { NTP8918_MASTER_VOL, 0b11 },
+};
+
+static int ntp8918_load_firmware(struct ntp8918_priv *ntp8918)
+{
+ int ret;
+
+ ret = ntpfw_load(ntp8918->i2c, NTP8918_FW_NAME, NTP8918_FW_MAGIC);
+ if (ret == -ENOENT) {
+ dev_warn_once(&ntp8918->i2c->dev, "Could not find firmware %s\n",
+ NTP8918_FW_NAME);
+ return 0;
+ }
+
+ return ret;
+}
+
+static int ntp8918_snd_suspend(struct snd_soc_component *component)
+{
+ struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(component->regmap, true);
+
+ regmap_multi_reg_write_bypassed(component->regmap,
+ ntp8918_sound_off,
+ ARRAY_SIZE(ntp8918_sound_off));
+
+ /*
+ * According to NTP8918 datasheet, 6.2 Timing Sequence 1:
+ * wait after sound off for T6 >= 0.5ms
+ */
+ fsleep(500);
+ reset_control_assert(ntp8918->reset);
+
+ regcache_mark_dirty(component->regmap);
+ clk_disable_unprepare(ntp8918->bck);
+
+ return 0;
+}
+
+static int ntp8918_snd_resume(struct snd_soc_component *component)
+{
+ struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ ret = clk_prepare_enable(ntp8918->bck);
+ if (ret)
+ return ret;
+
+ ntp8918_reset_gpio(ntp8918);
+
+ regmap_multi_reg_write_bypassed(component->regmap,
+ ntp8918_sound_on,
+ ARRAY_SIZE(ntp8918_sound_on));
+
+ ret = ntp8918_load_firmware(ntp8918);
+ if (ret) {
+ dev_err(&ntp8918->i2c->dev, "Failed to load firmware\n");
+ return ret;
+ }
+
+ regcache_cache_only(component->regmap, false);
+ snd_soc_component_cache_sync(component);
+
+ return 0;
+}
+
+static int ntp8918_probe(struct snd_soc_component *component)
+{
+ int ret;
+ struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component);
+ struct device *dev = component->dev;
+
+ ret = snd_soc_add_component_controls(component, ntp8918_vol_control,
+ ARRAY_SIZE(ntp8918_vol_control));
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add controls\n");
+
+ ret = ntp8918_load_firmware(ntp8918);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to load firmware\n");
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget ntp8918_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("AIFIN", "Playback", SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_OUTPUT("OUT1"),
+ SND_SOC_DAPM_OUTPUT("OUT2"),
+};
+
+static const struct snd_soc_dapm_route ntp8918_dapm_routes[] = {
+ { "OUT1", NULL, "AIFIN" },
+ { "OUT2", NULL, "AIFIN" },
+};
+
+static const struct snd_soc_component_driver soc_component_ntp8918 = {
+ .probe = ntp8918_probe,
+ .suspend = ntp8918_snd_suspend,
+ .resume = ntp8918_snd_resume,
+ .dapm_widgets = ntp8918_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ntp8918_dapm_widgets),
+ .dapm_routes = ntp8918_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(ntp8918_dapm_routes),
+};
+
+static int ntp8918_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 ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component);
+ unsigned int input_fmt = 0;
+ unsigned int gsa_fmt = 0;
+ unsigned int gsa_fmt_mask;
+ unsigned int mcf;
+ int bclk;
+ int ret;
+
+ bclk = snd_soc_params_to_bclk(params);
+ switch (bclk) {
+ case 3072000:
+ case 2822400:
+ mcf = 0;
+ break;
+ case 6144000:
+ mcf = 1;
+ break;
+ case 2048000:
+ mcf = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = snd_soc_component_update_bits(component, NTP8918_MCLK_FREQ_CTRL,
+ NTP8918_MCLK_FREQ_MCF, mcf);
+ if (ret)
+ return ret;
+
+ switch (ntp8918->format) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ input_fmt |= NTP8918_INPUT_FMT_GSA_MODE;
+ gsa_fmt |= NTP8918_GSA_RIGHT_J;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ input_fmt |= NTP8918_INPUT_FMT_GSA_MODE;
+ break;
+ }
+
+ ret = snd_soc_component_update_bits(component, NTP8918_INPUT_FMT,
+ NTP8918_INPUT_FMT_MASTER_MODE |
+ NTP8918_INPUT_FMT_GSA_MODE,
+ input_fmt);
+
+ if (!(input_fmt & NTP8918_INPUT_FMT_GSA_MODE) || ret < 0)
+ return ret;
+
+ switch (params_width(params)) {
+ case 24:
+ gsa_fmt |= NTP8918_GSA_BS(0);
+ break;
+ case 20:
+ gsa_fmt |= NTP8918_GSA_BS(1);
+ break;
+ case 18:
+ gsa_fmt |= NTP8918_GSA_BS(2);
+ break;
+ case 16:
+ gsa_fmt |= NTP8918_GSA_BS(3);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ gsa_fmt_mask = NTP8918_GSA_BS_MASK |
+ NTP8918_GSA_RIGHT_J |
+ NTP8918_GSA_LSB;
+ return snd_soc_component_update_bits(component, NTP8918_GSA_FMT,
+ gsa_fmt_mask, gsa_fmt);
+}
+
+static int ntp8918_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ case SND_SOC_DAIFMT_LEFT_J:
+ ntp8918->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int ntp8918_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+ unsigned int mute_mask = NTP8918_SOFT_MUTE_SM1 |
+ NTP8918_SOFT_MUTE_SM2;
+
+ return snd_soc_component_update_bits(dai->component, NTP8918_SOFT_MUTE,
+ mute_mask, mute ? mute_mask : 0);
+}
+
+static const struct snd_soc_dai_ops ntp8918_dai_ops = {
+ .hw_params = ntp8918_hw_params,
+ .set_fmt = ntp8918_set_fmt,
+ .mute_stream = ntp8918_digital_mute,
+};
+
+static struct snd_soc_dai_driver ntp8918_dai = {
+ .name = "ntp8918-amplifier",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = NTP8918_RATES,
+ .formats = NTP8918_FORMATS,
+ },
+ .ops = &ntp8918_dai_ops,
+};
+
+static const struct regmap_config ntp8918_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_MAX,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static int ntp8918_i2c_probe(struct i2c_client *i2c)
+{
+ struct ntp8918_priv *ntp8918;
+ int ret;
+ struct regmap *regmap;
+
+ ntp8918 = devm_kzalloc(&i2c->dev, sizeof(*ntp8918), GFP_KERNEL);
+ if (!ntp8918)
+ return -ENOMEM;
+
+ ntp8918->i2c = i2c;
+
+ ntp8918->reset = devm_reset_control_get_shared(&i2c->dev, NULL);
+ if (IS_ERR(ntp8918->reset))
+ return dev_err_probe(&i2c->dev, PTR_ERR(ntp8918->reset), "Failed to get reset\n");
+
+ dev_set_drvdata(&i2c->dev, ntp8918);
+
+ ntp8918_reset_gpio(ntp8918);
+
+ regmap = devm_regmap_init_i2c(i2c, &ntp8918_regmap);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(regmap),
+ "Failed to allocate regmap\n");
+
+ ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_ntp8918,
+ &ntp8918_dai, 1);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret,
+ "Failed to register component\n");
+
+ ntp8918->bck = devm_clk_get_enabled(&i2c->dev, "bck");
+ if (IS_ERR(ntp8918->bck))
+ return dev_err_probe(&i2c->dev, PTR_ERR(ntp8918->bck), "failed to get bck clock\n");
+
+ return 0;
+}
+
+static const struct i2c_device_id ntp8918_i2c_id[] = {
+ { "ntp8918", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ntp8918_i2c_id);
+
+static const struct of_device_id ntp8918_of_match[] = {
+ {.compatible = "neofidelity,ntp8918"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, ntp8918_of_match);
+
+static struct i2c_driver ntp8918_i2c_driver = {
+ .probe = ntp8918_i2c_probe,
+ .id_table = ntp8918_i2c_id,
+ .driver = {
+ .name = "ntp8918",
+ .of_match_table = ntp8918_of_match,
+ },
+};
+module_i2c_driver(ntp8918_i2c_driver);
+
+MODULE_AUTHOR("Igor Prusov <[email protected]>");
+MODULE_DESCRIPTION("NTP8918 Audio Amplifier Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ntpfw.c b/sound/soc/codecs/ntpfw.c
new file mode 100644
index 000000000000..5ced2e966ab7
--- /dev/null
+++ b/sound/soc/codecs/ntpfw.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ntpfw.c - Firmware helper functions for Neofidelity codecs
+ *
+ * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
+ */
+
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+
+#include "ntpfw.h"
+
+struct ntpfw_chunk {
+ __be16 length;
+ u8 step;
+ u8 data[];
+} __packed;
+
+struct ntpfw_header {
+ __be32 magic;
+} __packed;
+
+static bool ntpfw_verify(struct device *dev, const u8 *buf, size_t buf_size, u32 magic)
+{
+ const struct ntpfw_header *header = (struct ntpfw_header *)buf;
+ u32 buf_magic;
+
+ if (buf_size <= sizeof(*header)) {
+ dev_err(dev, "Failed to load firmware: image too small\n");
+ return false;
+ }
+
+ buf_magic = be32_to_cpu(header->magic);
+ if (buf_magic != magic) {
+ dev_err(dev, "Failed to load firmware: invalid magic 0x%x:\n", buf_magic);
+ return false;
+ }
+
+ return true;
+}
+
+static bool ntpfw_verify_chunk(struct device *dev, const struct ntpfw_chunk *chunk, size_t buf_size)
+{
+ size_t chunk_size;
+
+ if (buf_size <= sizeof(*chunk)) {
+ dev_err(dev, "Failed to load firmware: chunk size too big\n");
+ return false;
+ }
+
+ if (chunk->step != 2 && chunk->step != 5) {
+ dev_err(dev, "Failed to load firmware: invalid chunk step: %d\n", chunk->step);
+ return false;
+ }
+
+ chunk_size = be16_to_cpu(chunk->length);
+ if (chunk_size > buf_size) {
+ dev_err(dev, "Failed to load firmware: invalid chunk length\n");
+ return false;
+ }
+
+ if (chunk_size % chunk->step) {
+ dev_err(dev, "Failed to load firmware: chunk length and step mismatch\n");
+ return false;
+ }
+
+ return true;
+}
+
+static int ntpfw_send_chunk(struct i2c_client *i2c, const struct ntpfw_chunk *chunk)
+{
+ int ret;
+ size_t i;
+ size_t length = be16_to_cpu(chunk->length);
+
+ for (i = 0; i < length; i += chunk->step) {
+ ret = i2c_master_send(i2c, &chunk->data[i], chunk->step);
+ if (ret != chunk->step) {
+ dev_err(&i2c->dev, "I2C send failed: %d\n", ret);
+ return ret < 0 ? ret : -EIO;
+ }
+ }
+
+ return 0;
+}
+
+int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic)
+{
+ struct device *dev = &i2c->dev;
+ const struct ntpfw_chunk *chunk;
+ const struct firmware *fw;
+ const u8 *data;
+ size_t leftover;
+ int ret;
+
+ ret = request_firmware(&fw, name, dev);
+ if (ret) {
+ dev_warn(dev, "request_firmware '%s' failed with %d\n",
+ name, ret);
+ return ret;
+ }
+
+ if (!ntpfw_verify(dev, fw->data, fw->size, magic)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ data = fw->data + sizeof(struct ntpfw_header);
+ leftover = fw->size - sizeof(struct ntpfw_header);
+
+ while (leftover) {
+ chunk = (struct ntpfw_chunk *)data;
+
+ if (!ntpfw_verify_chunk(dev, chunk, leftover)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = ntpfw_send_chunk(i2c, chunk);
+ if (ret)
+ goto done;
+
+ data += be16_to_cpu(chunk->length) + sizeof(*chunk);
+ leftover -= be16_to_cpu(chunk->length) + sizeof(*chunk);
+ }
+
+done:
+ release_firmware(fw);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ntpfw_load);
+
+MODULE_AUTHOR("Igor Prusov <[email protected]>");
+MODULE_DESCRIPTION("Helper for loading Neofidelity amplifiers firmware");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ntpfw.h b/sound/soc/codecs/ntpfw.h
new file mode 100644
index 000000000000..1cf10d5480ee
--- /dev/null
+++ b/sound/soc/codecs/ntpfw.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/**
+ * ntpfw.h - Firmware helper functions for Neofidelity codecs
+ *
+ * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
+ */
+
+#ifndef __NTPFW_H__
+#define __NTPFW_H__
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+
+/**
+ * ntpfw_load - load firmware to amplifier over i2c interface.
+ *
+ * @i2c Pointer to amplifier's I2C client.
+ * @name Firmware file name.
+ * @magic Magic number to validate firmware.
+ * @return 0 or error code upon error.
+ */
+int ntpfw_load(struct i2c_client *i2c, const char *name, const u32 magic);
+
+#endif /* __NTPFW_H__ */
diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c
index 451a8fd8fac5..13443f569ddb 100644
--- a/sound/soc/codecs/pcm186x.c
+++ b/sound/soc/codecs/pcm186x.c
@@ -566,7 +566,7 @@ static int pcm186x_set_bias_level(struct snd_soc_component *component,
return 0;
}
-static struct snd_soc_component_driver soc_codec_dev_pcm1863 = {
+static const struct snd_soc_component_driver soc_codec_dev_pcm1863 = {
.set_bias_level = pcm186x_set_bias_level,
.controls = pcm1863_snd_controls,
.num_controls = ARRAY_SIZE(pcm1863_snd_controls),
@@ -579,7 +579,7 @@ static struct snd_soc_component_driver soc_codec_dev_pcm1863 = {
.endianness = 1,
};
-static struct snd_soc_component_driver soc_codec_dev_pcm1865 = {
+static const struct snd_soc_component_driver soc_codec_dev_pcm1865 = {
.set_bias_level = pcm186x_set_bias_level,
.controls = pcm1865_snd_controls,
.num_controls = ARRAY_SIZE(pcm1865_snd_controls),
diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c
index 3401a25341e6..9bca53de2475 100644
--- a/sound/soc/codecs/pcm5102a.c
+++ b/sound/soc/codecs/pcm5102a.c
@@ -24,7 +24,7 @@ static struct snd_soc_dai_driver pcm5102a_dai = {
},
};
-static struct snd_soc_component_driver soc_component_dev_pcm5102a = {
+static const struct snd_soc_component_driver soc_component_dev_pcm5102a = {
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
diff --git a/sound/soc/codecs/rt-sdw-common.c b/sound/soc/codecs/rt-sdw-common.c
new file mode 100644
index 000000000000..ad61943ce75f
--- /dev/null
+++ b/sound/soc/codecs/rt-sdw-common.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt-sdw-common.c
+//
+// Copyright(c) 2024 Realtek Semiconductor Corp.
+//
+
+/*
+ * This file defines common functions used with Realtek soundwire codecs.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/bitops.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/jack.h>
+
+#include "rt-sdw-common.h"
+
+/**
+ * rt_sdca_index_write - Write a value to Realtek defined register.
+ *
+ * @map: map for setting.
+ * @nid: Realtek-defined ID.
+ * @reg: register.
+ * @value: value.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int rt_sdca_index_write(struct regmap *map, unsigned int nid,
+ unsigned int reg, unsigned int value)
+{
+ unsigned int addr = (nid << 20) | reg;
+ int ret;
+
+ ret = regmap_write(map, addr, value);
+ if (ret < 0)
+ pr_err("Failed to set value: %06x <= %04x ret=%d\n",
+ addr, value, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_index_write);
+
+/**
+ * rt_sdca_index_read - Read value from Realtek defined register.
+ *
+ * @map: map for setting.
+ * @nid: Realtek-defined ID.
+ * @reg: register.
+ * @value: value.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int rt_sdca_index_read(struct regmap *map, unsigned int nid,
+ unsigned int reg, unsigned int *value)
+{
+ unsigned int addr = (nid << 20) | reg;
+ int ret;
+
+ ret = regmap_read(map, addr, value);
+ if (ret < 0)
+ pr_err("Failed to get value: %06x => %04x ret=%d\n",
+ addr, *value, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_index_read);
+
+/**
+ * rt_sdca_index_update_bits - Update value on Realtek defined register.
+ *
+ * @map: map for setting.
+ * @nid: Realtek-defined ID.
+ * @reg: register.
+ * @mask: Bitmask to change
+ * @val: New value for bitmask
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+
+int rt_sdca_index_update_bits(struct regmap *map,
+ unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val)
+{
+ unsigned int tmp;
+ int ret;
+
+ ret = rt_sdca_index_read(map, nid, reg, &tmp);
+ if (ret < 0)
+ return ret;
+
+ set_mask_bits(&tmp, mask, val);
+ return rt_sdca_index_write(map, nid, reg, tmp);
+}
+EXPORT_SYMBOL_GPL(rt_sdca_index_update_bits);
+
+/**
+ * rt_sdca_btn_type - Decision of button type.
+ *
+ * @buffer: UMP message buffer.
+ *
+ * A button type will be returned regarding to buffer,
+ * it returns zero if buffer cannot be recognized.
+ */
+int rt_sdca_btn_type(unsigned char *buffer)
+{
+ u8 btn_type = 0;
+ int ret = 0;
+
+ btn_type |= buffer[0] & 0xf;
+ btn_type |= (buffer[0] >> 4) & 0xf;
+ btn_type |= buffer[1] & 0xf;
+ btn_type |= (buffer[1] >> 4) & 0xf;
+
+ if (btn_type & BIT(0))
+ ret |= SND_JACK_BTN_2;
+ if (btn_type & BIT(1))
+ ret |= SND_JACK_BTN_3;
+ if (btn_type & BIT(2))
+ ret |= SND_JACK_BTN_0;
+ if (btn_type & BIT(3))
+ ret |= SND_JACK_BTN_1;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_btn_type);
+
+/**
+ * rt_sdca_headset_detect - Headset jack type detection.
+ *
+ * @map: map for setting.
+ * @entity_id: SDCA entity ID.
+ *
+ * A headset jack type will be returned, a negative errno will
+ * be returned in error cases.
+ */
+int rt_sdca_headset_detect(struct regmap *map, unsigned int entity_id)
+{
+ unsigned int det_mode, jack_type;
+ int ret;
+
+ /* get detected_mode */
+ ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id,
+ RT_SDCA_CTL_DETECTED_MODE, 0), &det_mode);
+
+ if (ret < 0)
+ goto io_error;
+
+ switch (det_mode) {
+ case 0x03:
+ jack_type = SND_JACK_HEADPHONE;
+ break;
+ case 0x05:
+ jack_type = SND_JACK_HEADSET;
+ break;
+ default:
+ jack_type = 0;
+ break;
+ }
+
+ /* write selected_mode */
+ if (det_mode) {
+ ret = regmap_write(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id,
+ RT_SDCA_CTL_SELECTED_MODE, 0), det_mode);
+ if (ret < 0)
+ goto io_error;
+ }
+
+ return jack_type;
+
+io_error:
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_headset_detect);
+
+/**
+ * rt_sdca_button_detect - Read UMP message and decide button type.
+ *
+ * @map: map for setting.
+ * @entity_id: SDCA entity ID.
+ * @hid_buf_addr: HID buffer address.
+ * @hid_id: Report ID for HID.
+ *
+ * A button type will be returned regarding to buffer,
+ * it returns zero if buffer cannot be recognized.
+ */
+int rt_sdca_button_detect(struct regmap *map, unsigned int entity_id,
+ unsigned int hid_buf_addr, unsigned int hid_id)
+{
+ unsigned int btn_type = 0, offset, idx, val, owner;
+ unsigned char buf[3];
+ int ret;
+
+ /* get current UMP message owner */
+ ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_HID, entity_id,
+ RT_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(map, SDW_SDCA_CTL(SDCA_NUM_HID, entity_id,
+ RT_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset);
+ if (ret < 0)
+ goto _end_btn_det_;
+
+ for (idx = 0; idx < sizeof(buf); idx++) {
+ ret = regmap_read(map, hid_buf_addr + offset + idx, &val);
+ if (ret < 0)
+ goto _end_btn_det_;
+ buf[idx] = val & 0xff;
+ }
+ /* Report ID for HID */
+ if (buf[0] == hid_id)
+ btn_type = rt_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(map,
+ SDW_SDCA_CTL(SDCA_NUM_HID, entity_id,
+ RT_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01);
+
+ return btn_type;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_button_detect);
+
+MODULE_DESCRIPTION("Realtek soundwire common functions");
+MODULE_AUTHOR("jack yu <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt-sdw-common.h b/sound/soc/codecs/rt-sdw-common.h
new file mode 100644
index 000000000000..4759516feb38
--- /dev/null
+++ b/sound/soc/codecs/rt-sdw-common.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+//
+// rt-sdw-common.h
+//
+// Copyright(c) 2024 Realtek Semiconductor Corp.
+//
+
+/*
+ * This file defines common functions used with Realtek soundwire codecs.
+ */
+
+#ifndef __RT_SDW_COMMON_H__
+#define __RT_SDW_COMMON_H__
+
+#define SDCA_NUM_JACK_CODEC 0x01
+#define SDCA_NUM_MIC_ARRAY 0x02
+#define SDCA_NUM_HID 0x03
+#define SDCA_NUM_AMP 0x04
+#define RT_SDCA_CTL_SELECTED_MODE 0x01
+#define RT_SDCA_CTL_DETECTED_MODE 0x02
+#define RT_SDCA_CTL_HIDTX_CURRENT_OWNER 0x10
+#define RT_SDCA_CTL_HIDTX_MESSAGE_OFFSET 0x12
+
+struct rt_sdca_dmic_kctrl_priv {
+ unsigned int reg_base;
+ unsigned int count;
+ unsigned int max;
+ unsigned int invert;
+};
+
+#define RT_SDCA_PR_VALUE(xreg_base, xcount, xmax, xinvert) \
+ ((unsigned long)&(struct rt_sdca_dmic_kctrl_priv) \
+ {.reg_base = xreg_base, .count = xcount, .max = xmax, \
+ .invert = xinvert})
+
+#define RT_SDCA_FU_CTRL(xname, reg_base, xmax, xinvert, xcount, \
+ xinfo, xget, xput) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .info = xinfo, \
+ .get = xget, \
+ .put = xput, \
+ .private_value = RT_SDCA_PR_VALUE(reg_base, xcount, xmax, xinvert)}
+
+#define RT_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\
+ xhandler_put, xcount, xmax, tlv_array, xinfo) \
+{ .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 = xinfo, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = RT_SDCA_PR_VALUE(reg_base, xcount, xmax, 0) }
+
+
+int rt_sdca_index_write(struct regmap *map, unsigned int nid,
+ unsigned int reg, unsigned int value);
+int rt_sdca_index_read(struct regmap *map, unsigned int nid,
+ unsigned int reg, unsigned int *value);
+int rt_sdca_index_update_bits(struct regmap *map,
+ unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val);
+int rt_sdca_btn_type(unsigned char *buffer);
+int rt_sdca_headset_detect(struct regmap *map, unsigned int entity_id);
+int rt_sdca_button_detect(struct regmap *map, unsigned int entity_id,
+ unsigned int hid_buf_addr, unsigned int hid_id);
+
+#endif /* __RT_SDW_COMMON_H__ */
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index f4e1ea29c265..3510c3819074 100644
--- a/sound/soc/codecs/rt1320-sdw.c
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -21,6 +21,7 @@
#include <sound/tlv.h>
#include <sound/sdw.h>
#include "rt1320-sdw.h"
+#include "rt-sdw-common.h"
/*
* The 'blind writes' is an SDCA term to deal with platform-specific initialization.
@@ -89,6 +90,25 @@ static const struct reg_sequence rt1320_blind_write[] = {
{ 0xc019, 0x10 },
{ 0xd487, 0x3f },
{ 0xd486, 0xc3 },
+ { 0x3fc2bfc7, 0x00 },
+ { 0x3fc2bfc6, 0x00 },
+ { 0x3fc2bfc5, 0x00 },
+ { 0x3fc2bfc4, 0x01 },
+ { 0x0000d486, 0x43 },
+ { 0x1000db00, 0x02 },
+ { 0x1000db01, 0x00 },
+ { 0x1000db02, 0x11 },
+ { 0x1000db03, 0x00 },
+ { 0x1000db04, 0x00 },
+ { 0x1000db05, 0x82 },
+ { 0x1000db06, 0x04 },
+ { 0x1000db07, 0xf1 },
+ { 0x1000db08, 0x00 },
+ { 0x1000db09, 0x00 },
+ { 0x1000db0a, 0x40 },
+ { 0x0000d540, 0x01 },
+ { 0xd172, 0x2a },
+ { 0xc5d6, 0x01 },
};
static const struct reg_sequence rt1320_vc_blind_write[] = {
@@ -148,6 +168,12 @@ static const struct reg_sequence rt1320_vc_blind_write[] = {
{ 0xd487, 0x3b },
{ 0xd486, 0xc3 },
{ 0xc598, 0x04 },
+ { 0xdb03, 0xf0 },
+ { 0xdb09, 0x00 },
+ { 0xdb08, 0x7a },
+ { 0xdb19, 0x02 },
+ { 0xdb07, 0x5a },
+ { 0xdb05, 0x45 },
{ 0xd500, 0x00 },
{ 0xd500, 0x17 },
{ 0xd600, 0x01 },
@@ -164,1913 +190,6 @@ static const struct reg_sequence rt1320_vc_blind_write[] = {
{ 0xd610, 0x01 },
{ 0xd608, 0x03 },
{ 0xd609, 0x00 },
-};
-
-static const struct reg_sequence rt1320_vc_patch_code_write[] = {
- { 0x10007000, 0x37 },
- { 0x10007001, 0x77 },
- { 0x10007002, 0x00 },
- { 0x10007003, 0x10 },
- { 0x10007004, 0xb7 },
- { 0x10007005, 0xe7 },
- { 0x10007006, 0x00 },
- { 0x10007007, 0x10 },
- { 0x10007008, 0x13 },
- { 0x10007009, 0x07 },
- { 0x1000700a, 0x87 },
- { 0x1000700b, 0x48 },
- { 0x1000700c, 0x23 },
- { 0x1000700d, 0xa6 },
- { 0x1000700e, 0xe7 },
- { 0x1000700f, 0xee },
- { 0x10007010, 0x37 },
- { 0x10007011, 0x77 },
- { 0x10007012, 0x00 },
- { 0x10007013, 0x10 },
- { 0x10007014, 0x13 },
- { 0x10007015, 0x07 },
- { 0x10007016, 0x87 },
- { 0x10007017, 0x56 },
- { 0x10007018, 0x23 },
- { 0x10007019, 0xac },
- { 0x1000701a, 0xe7 },
- { 0x1000701b, 0xde },
- { 0x1000701c, 0x37 },
- { 0x1000701d, 0x77 },
- { 0x1000701e, 0x00 },
- { 0x1000701f, 0x10 },
- { 0x10007020, 0x13 },
- { 0x10007021, 0x07 },
- { 0x10007022, 0xc7 },
- { 0x10007023, 0x5f },
- { 0x10007024, 0x23 },
- { 0x10007025, 0xae },
- { 0x10007026, 0xe7 },
- { 0x10007027, 0xdc },
- { 0x10007028, 0x37 },
- { 0x10007029, 0x87 },
- { 0x1000702a, 0x00 },
- { 0x1000702b, 0x10 },
- { 0x1000702c, 0x13 },
- { 0x1000702d, 0x07 },
- { 0x1000702e, 0xc7 },
- { 0x1000702f, 0x86 },
- { 0x10007030, 0x23 },
- { 0x10007031, 0xae },
- { 0x10007032, 0xe7 },
- { 0x10007033, 0xe6 },
- { 0x10007034, 0x37 },
- { 0x10007035, 0x77 },
- { 0x10007036, 0x00 },
- { 0x10007037, 0x10 },
- { 0x10007038, 0x13 },
- { 0x10007039, 0x07 },
- { 0x1000703a, 0x07 },
- { 0x1000703b, 0x40 },
- { 0x1000703c, 0x23 },
- { 0x1000703d, 0xa6 },
- { 0x1000703e, 0xe7 },
- { 0x1000703f, 0xe8 },
- { 0x10007040, 0x37 },
- { 0x10007041, 0x77 },
- { 0x10007042, 0x00 },
- { 0x10007043, 0x10 },
- { 0x10007044, 0x13 },
- { 0x10007045, 0x07 },
- { 0x10007046, 0xc7 },
- { 0x10007047, 0x63 },
- { 0x10007048, 0x23 },
- { 0x10007049, 0xa2 },
- { 0x1000704a, 0xe7 },
- { 0x1000704b, 0xec },
- { 0x1000704c, 0x37 },
- { 0x1000704d, 0x77 },
- { 0x1000704e, 0x00 },
- { 0x1000704f, 0x10 },
- { 0x10007050, 0x13 },
- { 0x10007051, 0x07 },
- { 0x10007052, 0x47 },
- { 0x10007053, 0x6f },
- { 0x10007054, 0x23 },
- { 0x10007055, 0xa6 },
- { 0x10007056, 0xe7 },
- { 0x10007057, 0xec },
- { 0x10007058, 0x37 },
- { 0x10007059, 0x77 },
- { 0x1000705a, 0x00 },
- { 0x1000705b, 0x10 },
- { 0x1000705c, 0x13 },
- { 0x1000705d, 0x07 },
- { 0x1000705e, 0x07 },
- { 0x1000705f, 0x44 },
- { 0x10007060, 0x23 },
- { 0x10007061, 0xa8 },
- { 0x10007062, 0xe7 },
- { 0x10007063, 0xec },
- { 0x10007064, 0x37 },
- { 0x10007065, 0x87 },
- { 0x10007066, 0x00 },
- { 0x10007067, 0x10 },
- { 0x10007068, 0x13 },
- { 0x10007069, 0x07 },
- { 0x1000706a, 0x87 },
- { 0x1000706b, 0x84 },
- { 0x1000706c, 0x23 },
- { 0x1000706d, 0xa8 },
- { 0x1000706e, 0xe7 },
- { 0x1000706f, 0xee },
- { 0x10007070, 0x37 },
- { 0x10007071, 0x87 },
- { 0x10007072, 0x00 },
- { 0x10007073, 0x10 },
- { 0x10007074, 0x13 },
- { 0x10007075, 0x07 },
- { 0x10007076, 0x47 },
- { 0x10007077, 0x97 },
- { 0x10007078, 0x23 },
- { 0x10007079, 0xaa },
- { 0x1000707a, 0xe7 },
- { 0x1000707b, 0xee },
- { 0x1000707c, 0x67 },
- { 0x1000707d, 0x80 },
- { 0x1000707e, 0x00 },
- { 0x1000707f, 0x00 },
- { 0x10007400, 0xb7 },
- { 0x10007401, 0xd6 },
- { 0x10007402, 0x00 },
- { 0x10007403, 0x00 },
- { 0x10007404, 0x83 },
- { 0x10007405, 0xc7 },
- { 0x10007406, 0x06 },
- { 0x10007407, 0x47 },
- { 0x10007408, 0x93 },
- { 0x10007409, 0xf7 },
- { 0x1000740a, 0x87 },
- { 0x1000740b, 0x00 },
- { 0x1000740c, 0x63 },
- { 0x1000740d, 0x88 },
- { 0x1000740e, 0x07 },
- { 0x1000740f, 0x02 },
- { 0x10007410, 0x03 },
- { 0x10007411, 0xc7 },
- { 0x10007412, 0x31 },
- { 0x10007413, 0x43 },
- { 0x10007414, 0x63 },
- { 0x10007415, 0x14 },
- { 0x10007416, 0x07 },
- { 0x10007417, 0x02 },
- { 0x10007418, 0x13 },
- { 0x10007419, 0x07 },
- { 0x1000741a, 0x10 },
- { 0x1000741b, 0x00 },
- { 0x1000741c, 0xa3 },
- { 0x1000741d, 0x89 },
- { 0x1000741e, 0xe1 },
- { 0x1000741f, 0x42 },
- { 0x10007420, 0x37 },
- { 0x10007421, 0xc7 },
- { 0x10007422, 0x00 },
- { 0x10007423, 0x00 },
- { 0x10007424, 0x03 },
- { 0x10007425, 0x46 },
- { 0x10007426, 0x07 },
- { 0x10007427, 0x06 },
- { 0x10007428, 0x23 },
- { 0x10007429, 0x8a },
- { 0x1000742a, 0xc1 },
- { 0x1000742b, 0x42 },
- { 0x1000742c, 0x83 },
- { 0x1000742d, 0xc7 },
- { 0x1000742e, 0x46 },
- { 0x1000742f, 0x47 },
- { 0x10007430, 0x93 },
- { 0x10007431, 0xf7 },
- { 0x10007432, 0xf7 },
- { 0x10007433, 0x0f },
- { 0x10007434, 0x23 },
- { 0x10007435, 0x00 },
- { 0x10007436, 0xf7 },
- { 0x10007437, 0x06 },
- { 0x10007438, 0x23 },
- { 0x10007439, 0x89 },
- { 0x1000743a, 0x01 },
- { 0x1000743b, 0x42 },
- { 0x1000743c, 0x67 },
- { 0x1000743d, 0x80 },
- { 0x1000743e, 0x00 },
- { 0x1000743f, 0x00 },
- { 0x10007440, 0x37 },
- { 0x10007441, 0xc7 },
- { 0x10007442, 0x00 },
- { 0x10007443, 0x00 },
- { 0x10007444, 0x83 },
- { 0x10007445, 0x27 },
- { 0x10007446, 0xc7 },
- { 0x10007447, 0x5f },
- { 0x10007448, 0x13 },
- { 0x10007449, 0x05 },
- { 0x1000744a, 0x00 },
- { 0x1000744b, 0x00 },
- { 0x1000744c, 0x23 },
- { 0x1000744d, 0xa2 },
- { 0x1000744e, 0xf1 },
- { 0x1000744f, 0x42 },
- { 0x10007450, 0xb7 },
- { 0x10007451, 0x06 },
- { 0x10007452, 0x00 },
- { 0x10007453, 0x10 },
- { 0x10007454, 0xb3 },
- { 0x10007455, 0xf7 },
- { 0x10007456, 0xd7 },
- { 0x10007457, 0x00 },
- { 0x10007458, 0x63 },
- { 0x10007459, 0x86 },
- { 0x1000745a, 0x07 },
- { 0x1000745b, 0x02 },
- { 0x1000745c, 0x83 },
- { 0x1000745d, 0x47 },
- { 0x1000745e, 0x07 },
- { 0x1000745f, 0x56 },
- { 0x10007460, 0x93 },
- { 0x10007461, 0xf7 },
- { 0x10007462, 0x87 },
- { 0x10007463, 0x01 },
- { 0x10007464, 0x63 },
- { 0x10007465, 0x80 },
- { 0x10007466, 0x07 },
- { 0x10007467, 0x02 },
- { 0x10007468, 0x83 },
- { 0x10007469, 0x47 },
- { 0x1000746a, 0x17 },
- { 0x1000746b, 0x08 },
- { 0x1000746c, 0x93 },
- { 0x1000746d, 0xf7 },
- { 0x1000746e, 0x47 },
- { 0x1000746f, 0x00 },
- { 0x10007470, 0x63 },
- { 0x10007471, 0x8a },
- { 0x10007472, 0x07 },
- { 0x10007473, 0x00 },
- { 0x10007474, 0xb7 },
- { 0x10007475, 0xc7 },
- { 0x10007476, 0xc2 },
- { 0x10007477, 0x3f },
- { 0x10007478, 0x03 },
- { 0x10007479, 0xa5 },
- { 0x1000747a, 0x47 },
- { 0x1000747b, 0xfc },
- { 0x1000747c, 0x13 },
- { 0x1000747d, 0x55 },
- { 0x1000747e, 0x25 },
- { 0x1000747f, 0x00 },
- { 0x10007480, 0x13 },
- { 0x10007481, 0x75 },
- { 0x10007482, 0x15 },
- { 0x10007483, 0x00 },
- { 0x10007484, 0x67 },
- { 0x10007485, 0x80 },
- { 0x10007486, 0x00 },
- { 0x10007487, 0x00 },
- { 0x10007488, 0x03 },
- { 0x10007489, 0xa7 },
- { 0x1000748a, 0x81 },
- { 0x1000748b, 0x57 },
- { 0x1000748c, 0x13 },
- { 0x1000748d, 0x01 },
- { 0x1000748e, 0x01 },
- { 0x1000748f, 0xff },
- { 0x10007490, 0x23 },
- { 0x10007491, 0x26 },
- { 0x10007492, 0x11 },
- { 0x10007493, 0x00 },
- { 0x10007494, 0x23 },
- { 0x10007495, 0x24 },
- { 0x10007496, 0x81 },
- { 0x10007497, 0x00 },
- { 0x10007498, 0x23 },
- { 0x10007499, 0x22 },
- { 0x1000749a, 0x91 },
- { 0x1000749b, 0x00 },
- { 0x1000749c, 0x93 },
- { 0x1000749d, 0x07 },
- { 0x1000749e, 0xa0 },
- { 0x1000749f, 0x05 },
- { 0x100074a0, 0x63 },
- { 0x100074a1, 0x14 },
- { 0x100074a2, 0xf7 },
- { 0x100074a3, 0x04 },
- { 0x100074a4, 0x37 },
- { 0x100074a5, 0x07 },
- { 0x100074a6, 0x00 },
- { 0x100074a7, 0x11 },
- { 0x100074a8, 0x83 },
- { 0x100074a9, 0x47 },
- { 0x100074aa, 0x07 },
- { 0x100074ab, 0x01 },
- { 0x100074ac, 0x13 },
- { 0x100074ad, 0x06 },
- { 0x100074ae, 0x30 },
- { 0x100074af, 0x00 },
- { 0x100074b0, 0x93 },
- { 0x100074b1, 0xf7 },
- { 0x100074b2, 0xf7 },
- { 0x100074b3, 0x0f },
- { 0x100074b4, 0x63 },
- { 0x100074b5, 0x9a },
- { 0x100074b6, 0xc7 },
- { 0x100074b7, 0x02 },
- { 0x100074b8, 0x03 },
- { 0x100074b9, 0x47 },
- { 0x100074ba, 0x87 },
- { 0x100074bb, 0x01 },
- { 0x100074bc, 0x13 },
- { 0x100074bd, 0x77 },
- { 0x100074be, 0xf7 },
- { 0x100074bf, 0x0f },
- { 0x100074c0, 0x63 },
- { 0x100074c1, 0x14 },
- { 0x100074c2, 0xf7 },
- { 0x100074c3, 0x02 },
- { 0x100074c4, 0x37 },
- { 0x100074c5, 0xd7 },
- { 0x100074c6, 0x00 },
- { 0x100074c7, 0x00 },
- { 0x100074c8, 0x83 },
- { 0x100074c9, 0x47 },
- { 0x100074ca, 0x37 },
- { 0x100074cb, 0x54 },
- { 0x100074cc, 0x93 },
- { 0x100074cd, 0xf7 },
- { 0x100074ce, 0xf7 },
- { 0x100074cf, 0x0f },
- { 0x100074d0, 0x93 },
- { 0x100074d1, 0xe7 },
- { 0x100074d2, 0x07 },
- { 0x100074d3, 0x02 },
- { 0x100074d4, 0xa3 },
- { 0x100074d5, 0x01 },
- { 0x100074d6, 0xf7 },
- { 0x100074d7, 0x54 },
- { 0x100074d8, 0x83 },
- { 0x100074d9, 0x47 },
- { 0x100074da, 0x37 },
- { 0x100074db, 0x54 },
- { 0x100074dc, 0x93 },
- { 0x100074dd, 0xf7 },
- { 0x100074de, 0xf7 },
- { 0x100074df, 0x0d },
- { 0x100074e0, 0xa3 },
- { 0x100074e1, 0x01 },
- { 0x100074e2, 0xf7 },
- { 0x100074e3, 0x54 },
- { 0x100074e4, 0x23 },
- { 0x100074e5, 0xac },
- { 0x100074e6, 0x01 },
- { 0x100074e7, 0x56 },
- { 0x100074e8, 0x37 },
- { 0x100074e9, 0xd4 },
- { 0x100074ea, 0x00 },
- { 0x100074eb, 0x00 },
- { 0x100074ec, 0x83 },
- { 0x100074ed, 0x47 },
- { 0x100074ee, 0xd4 },
- { 0x100074ef, 0x47 },
- { 0x100074f0, 0x93 },
- { 0x100074f1, 0xf7 },
- { 0x100074f2, 0x17 },
- { 0x100074f3, 0x00 },
- { 0x100074f4, 0x63 },
- { 0x100074f5, 0x80 },
- { 0x100074f6, 0x07 },
- { 0x100074f7, 0x06 },
- { 0x100074f8, 0x37 },
- { 0x100074f9, 0xd7 },
- { 0x100074fa, 0x00 },
- { 0x100074fb, 0x10 },
- { 0x100074fc, 0x83 },
- { 0x100074fd, 0x47 },
- { 0x100074fe, 0x77 },
- { 0x100074ff, 0xd9 },
- { 0x10007500, 0x93 },
- { 0x10007501, 0x87 },
- { 0x10007502, 0x17 },
- { 0x10007503, 0x00 },
- { 0x10007504, 0x93 },
- { 0x10007505, 0xf7 },
- { 0x10007506, 0xf7 },
- { 0x10007507, 0x0f },
- { 0x10007508, 0xa3 },
- { 0x10007509, 0x0b },
- { 0x1000750a, 0xf7 },
- { 0x1000750b, 0xd8 },
- { 0x1000750c, 0x03 },
- { 0x1000750d, 0x47 },
- { 0x1000750e, 0x77 },
- { 0x1000750f, 0xd9 },
- { 0x10007510, 0x83 },
- { 0x10007511, 0x47 },
- { 0x10007512, 0xc4 },
- { 0x10007513, 0x47 },
- { 0x10007514, 0x13 },
- { 0x10007515, 0x77 },
- { 0x10007516, 0xf7 },
- { 0x10007517, 0x0f },
- { 0x10007518, 0x93 },
- { 0x10007519, 0xf7 },
- { 0x1000751a, 0xf7 },
- { 0x1000751b, 0x0f },
- { 0x1000751c, 0x63 },
- { 0x1000751d, 0x6c },
- { 0x1000751e, 0xf7 },
- { 0x1000751f, 0x02 },
- { 0x10007520, 0xb7 },
- { 0x10007521, 0xf4 },
- { 0x10007522, 0x00 },
- { 0x10007523, 0x00 },
- { 0x10007524, 0x93 },
- { 0x10007525, 0x05 },
- { 0x10007526, 0x00 },
- { 0x10007527, 0x01 },
- { 0x10007528, 0x13 },
- { 0x10007529, 0x85 },
- { 0x1000752a, 0x34 },
- { 0x1000752b, 0x52 },
- { 0x1000752c, 0xef },
- { 0x1000752d, 0xa0 },
- { 0x1000752e, 0x8f },
- { 0x1000752f, 0xc6 },
- { 0x10007530, 0x93 },
- { 0x10007531, 0x05 },
- { 0x10007532, 0x00 },
- { 0x10007533, 0x00 },
- { 0x10007534, 0x13 },
- { 0x10007535, 0x85 },
- { 0x10007536, 0x54 },
- { 0x10007537, 0x10 },
- { 0x10007538, 0xef },
- { 0x10007539, 0xa0 },
- { 0x1000753a, 0xcf },
- { 0x1000753b, 0xc5 },
- { 0x1000753c, 0x93 },
- { 0x1000753d, 0x05 },
- { 0x1000753e, 0x00 },
- { 0x1000753f, 0x00 },
- { 0x10007540, 0x13 },
- { 0x10007541, 0x85 },
- { 0x10007542, 0x74 },
- { 0x10007543, 0x10 },
- { 0x10007544, 0xef },
- { 0x10007545, 0xa0 },
- { 0x10007546, 0x0f },
- { 0x10007547, 0xc5 },
- { 0x10007548, 0x83 },
- { 0x10007549, 0x47 },
- { 0x1000754a, 0xd4 },
- { 0x1000754b, 0x47 },
- { 0x1000754c, 0x93 },
- { 0x1000754d, 0xf7 },
- { 0x1000754e, 0xe7 },
- { 0x1000754f, 0x0f },
- { 0x10007550, 0xa3 },
- { 0x10007551, 0x0e },
- { 0x10007552, 0xf4 },
- { 0x10007553, 0x46 },
- { 0x10007554, 0x83 },
- { 0x10007555, 0x20 },
- { 0x10007556, 0xc1 },
- { 0x10007557, 0x00 },
- { 0x10007558, 0x03 },
- { 0x10007559, 0x24 },
- { 0x1000755a, 0x81 },
- { 0x1000755b, 0x00 },
- { 0x1000755c, 0x83 },
- { 0x1000755d, 0x24 },
- { 0x1000755e, 0x41 },
- { 0x1000755f, 0x00 },
- { 0x10007560, 0x13 },
- { 0x10007561, 0x01 },
- { 0x10007562, 0x01 },
- { 0x10007563, 0x01 },
- { 0x10007564, 0x67 },
- { 0x10007565, 0x80 },
- { 0x10007566, 0x00 },
- { 0x10007567, 0x00 },
- { 0x10007568, 0x13 },
- { 0x10007569, 0x01 },
- { 0x1000756a, 0x01 },
- { 0x1000756b, 0xff },
- { 0x1000756c, 0x23 },
- { 0x1000756d, 0x24 },
- { 0x1000756e, 0x81 },
- { 0x1000756f, 0x00 },
- { 0x10007570, 0x23 },
- { 0x10007571, 0x26 },
- { 0x10007572, 0x11 },
- { 0x10007573, 0x00 },
- { 0x10007574, 0x23 },
- { 0x10007575, 0x22 },
- { 0x10007576, 0x91 },
- { 0x10007577, 0x00 },
- { 0x10007578, 0x37 },
- { 0x10007579, 0xd4 },
- { 0x1000757a, 0x00 },
- { 0x1000757b, 0x00 },
- { 0x1000757c, 0x83 },
- { 0x1000757d, 0x47 },
- { 0x1000757e, 0x04 },
- { 0x1000757f, 0x54 },
- { 0x10007580, 0x93 },
- { 0x10007581, 0x97 },
- { 0x10007582, 0x87 },
- { 0x10007583, 0x01 },
- { 0x10007584, 0x93 },
- { 0x10007585, 0xd7 },
- { 0x10007586, 0x87 },
- { 0x10007587, 0x41 },
- { 0x10007588, 0x63 },
- { 0x10007589, 0xd0 },
- { 0x1000758a, 0x07 },
- { 0x1000758b, 0x06 },
- { 0x1000758c, 0xb7 },
- { 0x1000758d, 0xf4 },
- { 0x1000758e, 0x00 },
- { 0x1000758f, 0x00 },
- { 0x10007590, 0x93 },
- { 0x10007591, 0x05 },
- { 0x10007592, 0x60 },
- { 0x10007593, 0x01 },
- { 0x10007594, 0x13 },
- { 0x10007595, 0x85 },
- { 0x10007596, 0x34 },
- { 0x10007597, 0x52 },
- { 0x10007598, 0xef },
- { 0x10007599, 0xa0 },
- { 0x1000759a, 0xcf },
- { 0x1000759b, 0xbf },
- { 0x1000759c, 0x93 },
- { 0x1000759d, 0x05 },
- { 0x1000759e, 0x00 },
- { 0x1000759f, 0x04 },
- { 0x100075a0, 0x13 },
- { 0x100075a1, 0x85 },
- { 0x100075a2, 0x54 },
- { 0x100075a3, 0x10 },
- { 0x100075a4, 0xef },
- { 0x100075a5, 0xa0 },
- { 0x100075a6, 0x0f },
- { 0x100075a7, 0xbf },
- { 0x100075a8, 0x93 },
- { 0x100075a9, 0x05 },
- { 0x100075aa, 0x00 },
- { 0x100075ab, 0x04 },
- { 0x100075ac, 0x13 },
- { 0x100075ad, 0x85 },
- { 0x100075ae, 0x74 },
- { 0x100075af, 0x10 },
- { 0x100075b0, 0xef },
- { 0x100075b1, 0xa0 },
- { 0x100075b2, 0x4f },
- { 0x100075b3, 0xbe },
- { 0x100075b4, 0x83 },
- { 0x100075b5, 0x47 },
- { 0x100075b6, 0xd4 },
- { 0x100075b7, 0x47 },
- { 0x100075b8, 0x37 },
- { 0x100075b9, 0xd7 },
- { 0x100075ba, 0x00 },
- { 0x100075bb, 0x10 },
- { 0x100075bc, 0x93 },
- { 0x100075bd, 0xf7 },
- { 0x100075be, 0xf7 },
- { 0x100075bf, 0x0f },
- { 0x100075c0, 0x93 },
- { 0x100075c1, 0xe7 },
- { 0x100075c2, 0x17 },
- { 0x100075c3, 0x00 },
- { 0x100075c4, 0xa3 },
- { 0x100075c5, 0x0e },
- { 0x100075c6, 0xf4 },
- { 0x100075c7, 0x46 },
- { 0x100075c8, 0xa3 },
- { 0x100075c9, 0x0b },
- { 0x100075ca, 0x07 },
- { 0x100075cb, 0xd8 },
- { 0x100075cc, 0x83 },
- { 0x100075cd, 0x47 },
- { 0x100075ce, 0x87 },
- { 0x100075cf, 0xd9 },
- { 0x100075d0, 0x93 },
- { 0x100075d1, 0x87 },
- { 0x100075d2, 0x17 },
- { 0x100075d3, 0x00 },
- { 0x100075d4, 0x93 },
- { 0x100075d5, 0xf7 },
- { 0x100075d6, 0xf7 },
- { 0x100075d7, 0x0f },
- { 0x100075d8, 0x23 },
- { 0x100075d9, 0x0c },
- { 0x100075da, 0xf7 },
- { 0x100075db, 0xd8 },
- { 0x100075dc, 0x83 },
- { 0x100075dd, 0x47 },
- { 0x100075de, 0x04 },
- { 0x100075df, 0x54 },
- { 0x100075e0, 0x93 },
- { 0x100075e1, 0xf7 },
- { 0x100075e2, 0xf7 },
- { 0x100075e3, 0x07 },
- { 0x100075e4, 0x23 },
- { 0x100075e5, 0x00 },
- { 0x100075e6, 0xf4 },
- { 0x100075e7, 0x54 },
- { 0x100075e8, 0x83 },
- { 0x100075e9, 0x20 },
- { 0x100075ea, 0xc1 },
- { 0x100075eb, 0x00 },
- { 0x100075ec, 0x03 },
- { 0x100075ed, 0x24 },
- { 0x100075ee, 0x81 },
- { 0x100075ef, 0x00 },
- { 0x100075f0, 0x83 },
- { 0x100075f1, 0x24 },
- { 0x100075f2, 0x41 },
- { 0x100075f3, 0x00 },
- { 0x100075f4, 0x13 },
- { 0x100075f5, 0x01 },
- { 0x100075f6, 0x01 },
- { 0x100075f7, 0x01 },
- { 0x100075f8, 0x67 },
- { 0x100075f9, 0x80 },
- { 0x100075fa, 0x00 },
- { 0x100075fb, 0x00 },
- { 0x100075fc, 0x13 },
- { 0x100075fd, 0x01 },
- { 0x100075fe, 0x01 },
- { 0x100075ff, 0xff },
- { 0x10007600, 0x23 },
- { 0x10007601, 0x24 },
- { 0x10007602, 0x81 },
- { 0x10007603, 0x00 },
- { 0x10007604, 0x37 },
- { 0x10007605, 0xd4 },
- { 0x10007606, 0x00 },
- { 0x10007607, 0x00 },
- { 0x10007608, 0x83 },
- { 0x10007609, 0x27 },
- { 0x1000760a, 0x04 },
- { 0x1000760b, 0x53 },
- { 0x1000760c, 0x23 },
- { 0x1000760d, 0x22 },
- { 0x1000760e, 0x91 },
- { 0x1000760f, 0x00 },
- { 0x10007610, 0xb7 },
- { 0x10007611, 0x04 },
- { 0x10007612, 0x00 },
- { 0x10007613, 0x40 },
- { 0x10007614, 0x23 },
- { 0x10007615, 0x26 },
- { 0x10007616, 0x11 },
- { 0x10007617, 0x00 },
- { 0x10007618, 0xb3 },
- { 0x10007619, 0xf7 },
- { 0x1000761a, 0x97 },
- { 0x1000761b, 0x00 },
- { 0x1000761c, 0x63 },
- { 0x1000761d, 0x86 },
- { 0x1000761e, 0x07 },
- { 0x1000761f, 0x00 },
- { 0x10007620, 0xef },
- { 0x10007621, 0xd0 },
- { 0x10007622, 0x5f },
- { 0x10007623, 0xc2 },
- { 0x10007624, 0x23 },
- { 0x10007625, 0x28 },
- { 0x10007626, 0x94 },
- { 0x10007627, 0x52 },
- { 0x10007628, 0x83 },
- { 0x10007629, 0x20 },
- { 0x1000762a, 0xc1 },
- { 0x1000762b, 0x00 },
- { 0x1000762c, 0x03 },
- { 0x1000762d, 0x24 },
- { 0x1000762e, 0x81 },
- { 0x1000762f, 0x00 },
- { 0x10007630, 0x83 },
- { 0x10007631, 0x24 },
- { 0x10007632, 0x41 },
- { 0x10007633, 0x00 },
- { 0x10007634, 0x13 },
- { 0x10007635, 0x01 },
- { 0x10007636, 0x01 },
- { 0x10007637, 0x01 },
- { 0x10007638, 0x67 },
- { 0x10007639, 0x80 },
- { 0x1000763a, 0x00 },
- { 0x1000763b, 0x00 },
- { 0x1000763c, 0x37 },
- { 0x1000763d, 0xc7 },
- { 0x1000763e, 0x00 },
- { 0x1000763f, 0x00 },
- { 0x10007640, 0x83 },
- { 0x10007641, 0x27 },
- { 0x10007642, 0xc7 },
- { 0x10007643, 0x5f },
- { 0x10007644, 0x23 },
- { 0x10007645, 0xa2 },
- { 0x10007646, 0xf1 },
- { 0x10007647, 0x42 },
- { 0x10007648, 0xb7 },
- { 0x10007649, 0x06 },
- { 0x1000764a, 0x00 },
- { 0x1000764b, 0x10 },
- { 0x1000764c, 0xb3 },
- { 0x1000764d, 0xf7 },
- { 0x1000764e, 0xd7 },
- { 0x1000764f, 0x00 },
- { 0x10007650, 0x63 },
- { 0x10007651, 0x80 },
- { 0x10007652, 0x07 },
- { 0x10007653, 0x0a },
- { 0x10007654, 0x83 },
- { 0x10007655, 0x47 },
- { 0x10007656, 0x07 },
- { 0x10007657, 0x56 },
- { 0x10007658, 0x93 },
- { 0x10007659, 0xf7 },
- { 0x1000765a, 0x87 },
- { 0x1000765b, 0x01 },
- { 0x1000765c, 0x63 },
- { 0x1000765d, 0x8a },
- { 0x1000765e, 0x07 },
- { 0x1000765f, 0x08 },
- { 0x10007660, 0x83 },
- { 0x10007661, 0x47 },
- { 0x10007662, 0x17 },
- { 0x10007663, 0x08 },
- { 0x10007664, 0x93 },
- { 0x10007665, 0xf7 },
- { 0x10007666, 0x47 },
- { 0x10007667, 0x00 },
- { 0x10007668, 0x63 },
- { 0x10007669, 0x84 },
- { 0x1000766a, 0x07 },
- { 0x1000766b, 0x08 },
- { 0x1000766c, 0x13 },
- { 0x1000766d, 0x01 },
- { 0x1000766e, 0x01 },
- { 0x1000766f, 0xff },
- { 0x10007670, 0x23 },
- { 0x10007671, 0x26 },
- { 0x10007672, 0x11 },
- { 0x10007673, 0x00 },
- { 0x10007674, 0xb7 },
- { 0x10007675, 0xc7 },
- { 0x10007676, 0xc2 },
- { 0x10007677, 0x3f },
- { 0x10007678, 0x03 },
- { 0x10007679, 0xa7 },
- { 0x1000767a, 0x07 },
- { 0x1000767b, 0xfc },
- { 0x1000767c, 0x63 },
- { 0x1000767d, 0x10 },
- { 0x1000767e, 0x05 },
- { 0x1000767f, 0x06 },
- { 0x10007680, 0x13 },
- { 0x10007681, 0x67 },
- { 0x10007682, 0x07 },
- { 0x10007683, 0x20 },
- { 0x10007684, 0x23 },
- { 0x10007685, 0xa0 },
- { 0x10007686, 0xe7 },
- { 0x10007687, 0xfc },
- { 0x10007688, 0x03 },
- { 0x10007689, 0xa7 },
- { 0x1000768a, 0x07 },
- { 0x1000768b, 0xfc },
- { 0x1000768c, 0x13 },
- { 0x1000768d, 0x67 },
- { 0x1000768e, 0x07 },
- { 0x1000768f, 0x40 },
- { 0x10007690, 0x23 },
- { 0x10007691, 0xa0 },
- { 0x10007692, 0xe7 },
- { 0x10007693, 0xfc },
- { 0x10007694, 0x37 },
- { 0x10007695, 0xc7 },
- { 0x10007696, 0xc2 },
- { 0x10007697, 0x3f },
- { 0x10007698, 0x83 },
- { 0x10007699, 0x27 },
- { 0x1000769a, 0x07 },
- { 0x1000769b, 0xfc },
- { 0x1000769c, 0x13 },
- { 0x1000769d, 0x75 },
- { 0x1000769e, 0x15 },
- { 0x1000769f, 0x00 },
- { 0x100076a0, 0x13 },
- { 0x100076a1, 0x15 },
- { 0x100076a2, 0x85 },
- { 0x100076a3, 0x00 },
- { 0x100076a4, 0x93 },
- { 0x100076a5, 0xf7 },
- { 0x100076a6, 0xf7 },
- { 0x100076a7, 0xef },
- { 0x100076a8, 0x33 },
- { 0x100076a9, 0xe5 },
- { 0x100076aa, 0xa7 },
- { 0x100076ab, 0x00 },
- { 0x100076ac, 0x23 },
- { 0x100076ad, 0x20 },
- { 0x100076ae, 0xa7 },
- { 0x100076af, 0xfc },
- { 0x100076b0, 0x93 },
- { 0x100076b1, 0x05 },
- { 0x100076b2, 0x00 },
- { 0x100076b3, 0x00 },
- { 0x100076b4, 0x13 },
- { 0x100076b5, 0x05 },
- { 0x100076b6, 0xa0 },
- { 0x100076b7, 0x00 },
- { 0x100076b8, 0xef },
- { 0x100076b9, 0xe0 },
- { 0x100076ba, 0xcf },
- { 0x100076bb, 0xb6 },
- { 0x100076bc, 0x37 },
- { 0x100076bd, 0xf7 },
- { 0x100076be, 0x00 },
- { 0x100076bf, 0x00 },
- { 0x100076c0, 0x83 },
- { 0x100076c1, 0x47 },
- { 0x100076c2, 0x57 },
- { 0x100076c3, 0x01 },
- { 0x100076c4, 0x93 },
- { 0x100076c5, 0xf7 },
- { 0x100076c6, 0xf7 },
- { 0x100076c7, 0x0f },
- { 0x100076c8, 0x93 },
- { 0x100076c9, 0xe7 },
- { 0x100076ca, 0x47 },
- { 0x100076cb, 0x00 },
- { 0x100076cc, 0xa3 },
- { 0x100076cd, 0x0a },
- { 0x100076ce, 0xf7 },
- { 0x100076cf, 0x00 },
- { 0x100076d0, 0x83 },
- { 0x100076d1, 0x20 },
- { 0x100076d2, 0xc1 },
- { 0x100076d3, 0x00 },
- { 0x100076d4, 0x13 },
- { 0x100076d5, 0x01 },
- { 0x100076d6, 0x01 },
- { 0x100076d7, 0x01 },
- { 0x100076d8, 0x67 },
- { 0x100076d9, 0x80 },
- { 0x100076da, 0x00 },
- { 0x100076db, 0x00 },
- { 0x100076dc, 0x13 },
- { 0x100076dd, 0x77 },
- { 0x100076de, 0xf7 },
- { 0x100076df, 0xdf },
- { 0x100076e0, 0x23 },
- { 0x100076e1, 0xa0 },
- { 0x100076e2, 0xe7 },
- { 0x100076e3, 0xfc },
- { 0x100076e4, 0x03 },
- { 0x100076e5, 0xa7 },
- { 0x100076e6, 0x07 },
- { 0x100076e7, 0xfc },
- { 0x100076e8, 0x13 },
- { 0x100076e9, 0x77 },
- { 0x100076ea, 0xf7 },
- { 0x100076eb, 0xbf },
- { 0x100076ec, 0x6f },
- { 0x100076ed, 0xf0 },
- { 0x100076ee, 0x5f },
- { 0x100076ef, 0xfa },
- { 0x100076f0, 0x67 },
- { 0x100076f1, 0x80 },
- { 0x100076f2, 0x00 },
- { 0x100076f3, 0x00 },
- { 0x100076f4, 0xb7 },
- { 0x100076f5, 0xc7 },
- { 0x100076f6, 0x00 },
- { 0x100076f7, 0x00 },
- { 0x100076f8, 0x03 },
- { 0x100076f9, 0xc7 },
- { 0x100076fa, 0x87 },
- { 0x100076fb, 0x59 },
- { 0x100076fc, 0x13 },
- { 0x100076fd, 0x77 },
- { 0x100076fe, 0xf7 },
- { 0x100076ff, 0x0f },
- { 0x10007700, 0x13 },
- { 0x10007701, 0x67 },
- { 0x10007702, 0x17 },
- { 0x10007703, 0x00 },
- { 0x10007704, 0x23 },
- { 0x10007705, 0x8c },
- { 0x10007706, 0xe7 },
- { 0x10007707, 0x58 },
- { 0x10007708, 0x03 },
- { 0x10007709, 0xc7 },
- { 0x1000770a, 0x77 },
- { 0x1000770b, 0x04 },
- { 0x1000770c, 0x13 },
- { 0x1000770d, 0x17 },
- { 0x1000770e, 0x87 },
- { 0x1000770f, 0x01 },
- { 0x10007710, 0x13 },
- { 0x10007711, 0x57 },
- { 0x10007712, 0x87 },
- { 0x10007713, 0x41 },
- { 0x10007714, 0x63 },
- { 0x10007715, 0x58 },
- { 0x10007716, 0x07 },
- { 0x10007717, 0x12 },
- { 0x10007718, 0x37 },
- { 0x10007719, 0xd7 },
- { 0x1000771a, 0x00 },
- { 0x1000771b, 0x00 },
- { 0x1000771c, 0x83 },
- { 0x1000771d, 0x26 },
- { 0x1000771e, 0x87 },
- { 0x1000771f, 0x53 },
- { 0x10007720, 0x37 },
- { 0x10007721, 0x06 },
- { 0x10007722, 0x00 },
- { 0x10007723, 0x40 },
- { 0x10007724, 0x93 },
- { 0x10007725, 0x05 },
- { 0x10007726, 0x80 },
- { 0x10007727, 0x01 },
- { 0x10007728, 0xb3 },
- { 0x10007729, 0xe6 },
- { 0x1000772a, 0xc6 },
- { 0x1000772b, 0x00 },
- { 0x1000772c, 0x23 },
- { 0x1000772d, 0x2c },
- { 0x1000772e, 0xd7 },
- { 0x1000772f, 0x52 },
- { 0x10007730, 0x83 },
- { 0x10007731, 0xc6 },
- { 0x10007732, 0x07 },
- { 0x10007733, 0x56 },
- { 0x10007734, 0x93 },
- { 0x10007735, 0xf6 },
- { 0x10007736, 0xf6 },
- { 0x10007737, 0x0f },
- { 0x10007738, 0x63 },
- { 0x10007739, 0x9c },
- { 0x1000773a, 0xb6 },
- { 0x1000773b, 0x0e },
- { 0x1000773c, 0x83 },
- { 0x1000773d, 0x27 },
- { 0x1000773e, 0x87 },
- { 0x1000773f, 0x53 },
- { 0x10007740, 0xb3 },
- { 0x10007741, 0xf7 },
- { 0x10007742, 0xc7 },
- { 0x10007743, 0x00 },
- { 0x10007744, 0x63 },
- { 0x10007745, 0x80 },
- { 0x10007746, 0x07 },
- { 0x10007747, 0x10 },
- { 0x10007748, 0x13 },
- { 0x10007749, 0x01 },
- { 0x1000774a, 0x01 },
- { 0x1000774b, 0xff },
- { 0x1000774c, 0x23 },
- { 0x1000774d, 0x24 },
- { 0x1000774e, 0x81 },
- { 0x1000774f, 0x00 },
- { 0x10007750, 0x83 },
- { 0x10007751, 0xa7 },
- { 0x10007752, 0x41 },
- { 0x10007753, 0x58 },
- { 0x10007754, 0x23 },
- { 0x10007755, 0x26 },
- { 0x10007756, 0x11 },
- { 0x10007757, 0x00 },
- { 0x10007758, 0x63 },
- { 0x10007759, 0x94 },
- { 0x1000775a, 0x07 },
- { 0x1000775b, 0x0c },
- { 0x1000775c, 0x83 },
- { 0x1000775d, 0x27 },
- { 0x1000775e, 0x07 },
- { 0x1000775f, 0x53 },
- { 0x10007760, 0x03 },
- { 0x10007761, 0xc6 },
- { 0x10007762, 0xb1 },
- { 0x10007763, 0x42 },
- { 0x10007764, 0x93 },
- { 0x10007765, 0xd7 },
- { 0x10007766, 0xe7 },
- { 0x10007767, 0x01 },
- { 0x10007768, 0x93 },
- { 0x10007769, 0xf7 },
- { 0x1000776a, 0x17 },
- { 0x1000776b, 0x00 },
- { 0x1000776c, 0x93 },
- { 0x1000776d, 0x06 },
- { 0x1000776e, 0x10 },
- { 0x1000776f, 0x00 },
- { 0x10007770, 0x63 },
- { 0x10007771, 0x14 },
- { 0x10007772, 0x06 },
- { 0x10007773, 0x00 },
- { 0x10007774, 0xb3 },
- { 0x10007775, 0x86 },
- { 0x10007776, 0xf6 },
- { 0x10007777, 0x40 },
- { 0x10007778, 0xa3 },
- { 0x10007779, 0x85 },
- { 0x1000777a, 0xd1 },
- { 0x1000777b, 0x42 },
- { 0x1000777c, 0x03 },
- { 0x1000777d, 0xc6 },
- { 0x1000777e, 0xa1 },
- { 0x1000777f, 0x42 },
- { 0x10007780, 0x93 },
- { 0x10007781, 0x06 },
- { 0x10007782, 0x10 },
- { 0x10007783, 0x00 },
- { 0x10007784, 0x63 },
- { 0x10007785, 0x14 },
- { 0x10007786, 0x06 },
- { 0x10007787, 0x00 },
- { 0x10007788, 0xb3 },
- { 0x10007789, 0x86 },
- { 0x1000778a, 0xf6 },
- { 0x1000778b, 0x40 },
- { 0x1000778c, 0x23 },
- { 0x1000778d, 0x85 },
- { 0x1000778e, 0xd1 },
- { 0x1000778f, 0x42 },
- { 0x10007790, 0x03 },
- { 0x10007791, 0xc6 },
- { 0x10007792, 0x91 },
- { 0x10007793, 0x42 },
- { 0x10007794, 0x93 },
- { 0x10007795, 0x06 },
- { 0x10007796, 0x10 },
- { 0x10007797, 0x00 },
- { 0x10007798, 0x63 },
- { 0x10007799, 0x14 },
- { 0x1000779a, 0x06 },
- { 0x1000779b, 0x00 },
- { 0x1000779c, 0xb3 },
- { 0x1000779d, 0x86 },
- { 0x1000779e, 0xf6 },
- { 0x1000779f, 0x40 },
- { 0x100077a0, 0xa3 },
- { 0x100077a1, 0x84 },
- { 0x100077a2, 0xd1 },
- { 0x100077a3, 0x42 },
- { 0x100077a4, 0x03 },
- { 0x100077a5, 0xc6 },
- { 0x100077a6, 0x81 },
- { 0x100077a7, 0x42 },
- { 0x100077a8, 0x93 },
- { 0x100077a9, 0x06 },
- { 0x100077aa, 0x10 },
- { 0x100077ab, 0x00 },
- { 0x100077ac, 0x63 },
- { 0x100077ad, 0x14 },
- { 0x100077ae, 0x06 },
- { 0x100077af, 0x00 },
- { 0x100077b0, 0xb3 },
- { 0x100077b1, 0x86 },
- { 0x100077b2, 0xf6 },
- { 0x100077b3, 0x40 },
- { 0x100077b4, 0x23 },
- { 0x100077b5, 0x84 },
- { 0x100077b6, 0xd1 },
- { 0x100077b7, 0x42 },
- { 0x100077b8, 0xb7 },
- { 0x100077b9, 0xd7 },
- { 0x100077ba, 0x00 },
- { 0x100077bb, 0x00 },
- { 0x100077bc, 0x83 },
- { 0x100077bd, 0xa7 },
- { 0x100077be, 0x07 },
- { 0x100077bf, 0x53 },
- { 0x100077c0, 0x37 },
- { 0x100077c1, 0x07 },
- { 0x100077c2, 0x00 },
- { 0x100077c3, 0x40 },
- { 0x100077c4, 0xb3 },
- { 0x100077c5, 0xf7 },
- { 0x100077c6, 0xe7 },
- { 0x100077c7, 0x00 },
- { 0x100077c8, 0x63 },
- { 0x100077c9, 0x8c },
- { 0x100077ca, 0x07 },
- { 0x100077cb, 0x04 },
- { 0x100077cc, 0xb7 },
- { 0x100077cd, 0x47 },
- { 0x100077ce, 0x0f },
- { 0x100077cf, 0x00 },
- { 0x100077d0, 0x93 },
- { 0x100077d1, 0x87 },
- { 0x100077d2, 0x17 },
- { 0x100077d3, 0x24 },
- { 0x100077d4, 0xb7 },
- { 0x100077d5, 0xf6 },
- { 0x100077d6, 0x00 },
- { 0x100077d7, 0x00 },
- { 0x100077d8, 0x03 },
- { 0x100077d9, 0xc7 },
- { 0x100077da, 0xf6 },
- { 0x100077db, 0x83 },
- { 0x100077dc, 0x13 },
- { 0x100077dd, 0x77 },
- { 0x100077de, 0x07 },
- { 0x100077df, 0x04 },
- { 0x100077e0, 0x63 },
- { 0x100077e1, 0x16 },
- { 0x100077e2, 0x07 },
- { 0x100077e3, 0x00 },
- { 0x100077e4, 0x93 },
- { 0x100077e5, 0x87 },
- { 0x100077e6, 0xf7 },
- { 0x100077e7, 0xff },
- { 0x100077e8, 0xe3 },
- { 0x100077e9, 0x98 },
- { 0x100077ea, 0x07 },
- { 0x100077eb, 0xfe },
- { 0x100077ec, 0x13 },
- { 0x100077ed, 0x05 },
- { 0x100077ee, 0x80 },
- { 0x100077ef, 0x3e },
- { 0x100077f0, 0x93 },
- { 0x100077f1, 0x05 },
- { 0x100077f2, 0x00 },
- { 0x100077f3, 0x00 },
- { 0x100077f4, 0xef },
- { 0x100077f5, 0xe0 },
- { 0x100077f6, 0x0f },
- { 0x100077f7, 0xa3 },
- { 0x100077f8, 0x37 },
- { 0x100077f9, 0xf7 },
- { 0x100077fa, 0x00 },
- { 0x100077fb, 0x00 },
- { 0x100077fc, 0x83 },
- { 0x100077fd, 0x47 },
- { 0x100077fe, 0xb7 },
- { 0x100077ff, 0x80 },
- { 0x10007800, 0x93 },
- { 0x10007801, 0xe7 },
- { 0x10007802, 0x07 },
- { 0x10007803, 0xf8 },
- { 0x10007804, 0x93 },
- { 0x10007805, 0xf7 },
- { 0x10007806, 0xf7 },
- { 0x10007807, 0x0f },
- { 0x10007808, 0xa3 },
- { 0x10007809, 0x05 },
- { 0x1000780a, 0xf7 },
- { 0x1000780b, 0x80 },
- { 0x1000780c, 0xb7 },
- { 0x1000780d, 0xd7 },
- { 0x1000780e, 0x00 },
- { 0x1000780f, 0x00 },
- { 0x10007810, 0x37 },
- { 0x10007811, 0x07 },
- { 0x10007812, 0x00 },
- { 0x10007813, 0x40 },
- { 0x10007814, 0x23 },
- { 0x10007815, 0xa8 },
- { 0x10007816, 0xe7 },
- { 0x10007817, 0x52 },
- { 0x10007818, 0x93 },
- { 0x10007819, 0x07 },
- { 0x1000781a, 0x10 },
- { 0x1000781b, 0x00 },
- { 0x1000781c, 0x23 },
- { 0x1000781d, 0xa2 },
- { 0x1000781e, 0xf1 },
- { 0x1000781f, 0x58 },
- { 0x10007820, 0x83 },
- { 0x10007821, 0x20 },
- { 0x10007822, 0xc1 },
- { 0x10007823, 0x00 },
- { 0x10007824, 0x03 },
- { 0x10007825, 0x24 },
- { 0x10007826, 0x81 },
- { 0x10007827, 0x00 },
- { 0x10007828, 0x13 },
- { 0x10007829, 0x01 },
- { 0x1000782a, 0x01 },
- { 0x1000782b, 0x01 },
- { 0x1000782c, 0x67 },
- { 0x1000782d, 0x80 },
- { 0x1000782e, 0x00 },
- { 0x1000782f, 0x00 },
- { 0x10007830, 0x83 },
- { 0x10007831, 0xc7 },
- { 0x10007832, 0x07 },
- { 0x10007833, 0x56 },
- { 0x10007834, 0x93 },
- { 0x10007835, 0xf7 },
- { 0x10007836, 0xf7 },
- { 0x10007837, 0x0f },
- { 0x10007838, 0x63 },
- { 0x10007839, 0x96 },
- { 0x1000783a, 0x07 },
- { 0x1000783b, 0x00 },
- { 0x1000783c, 0x23 },
- { 0x1000783d, 0xa2 },
- { 0x1000783e, 0x01 },
- { 0x1000783f, 0x58 },
- { 0x10007840, 0x67 },
- { 0x10007841, 0x80 },
- { 0x10007842, 0x00 },
- { 0x10007843, 0x00 },
- { 0x10007844, 0x67 },
- { 0x10007845, 0x80 },
- { 0x10007846, 0x00 },
- { 0x10007847, 0x00 },
- { 0x10007848, 0xb7 },
- { 0x10007849, 0xc7 },
- { 0x1000784a, 0x00 },
- { 0x1000784b, 0x00 },
- { 0x1000784c, 0x83 },
- { 0x1000784d, 0xc7 },
- { 0x1000784e, 0x07 },
- { 0x1000784f, 0x56 },
- { 0x10007850, 0x13 },
- { 0x10007851, 0x07 },
- { 0x10007852, 0x80 },
- { 0x10007853, 0x01 },
- { 0x10007854, 0x93 },
- { 0x10007855, 0xf7 },
- { 0x10007856, 0xf7 },
- { 0x10007857, 0x0f },
- { 0x10007858, 0x63 },
- { 0x10007859, 0x98 },
- { 0x1000785a, 0xe7 },
- { 0x1000785b, 0x00 },
- { 0x1000785c, 0x13 },
- { 0x1000785d, 0x05 },
- { 0x1000785e, 0x00 },
- { 0x1000785f, 0x7d },
- { 0x10007860, 0x93 },
- { 0x10007861, 0x05 },
- { 0x10007862, 0x00 },
- { 0x10007863, 0x00 },
- { 0x10007864, 0x6f },
- { 0x10007865, 0xe0 },
- { 0x10007866, 0x0f },
- { 0x10007867, 0x9c },
- { 0x10007868, 0x67 },
- { 0x10007869, 0x80 },
- { 0x1000786a, 0x00 },
- { 0x1000786b, 0x00 },
- { 0x1000786c, 0x13 },
- { 0x1000786d, 0x01 },
- { 0x1000786e, 0x01 },
- { 0x1000786f, 0xff },
- { 0x10007870, 0x23 },
- { 0x10007871, 0x26 },
- { 0x10007872, 0x11 },
- { 0x10007873, 0x00 },
- { 0x10007874, 0x23 },
- { 0x10007875, 0x24 },
- { 0x10007876, 0x81 },
- { 0x10007877, 0x00 },
- { 0x10007878, 0xef },
- { 0x10007879, 0xd0 },
- { 0x1000787a, 0x4f },
- { 0x1000787b, 0x91 },
- { 0x1000787c, 0x83 },
- { 0x1000787d, 0xc7 },
- { 0x1000787e, 0x81 },
- { 0x1000787f, 0x41 },
- { 0x10007880, 0x63 },
- { 0x10007881, 0x84 },
- { 0x10007882, 0x07 },
- { 0x10007883, 0x08 },
- { 0x10007884, 0xb7 },
- { 0x10007885, 0xd7 },
- { 0x10007886, 0x00 },
- { 0x10007887, 0x00 },
- { 0x10007888, 0x83 },
- { 0x10007889, 0xc7 },
- { 0x1000788a, 0x07 },
- { 0x1000788b, 0x47 },
- { 0x1000788c, 0x93 },
- { 0x1000788d, 0xf7 },
- { 0x1000788e, 0x07 },
- { 0x1000788f, 0x02 },
- { 0x10007890, 0x63 },
- { 0x10007891, 0x8a },
- { 0x10007892, 0x07 },
- { 0x10007893, 0x04 },
- { 0x10007894, 0x83 },
- { 0x10007895, 0xc7 },
- { 0x10007896, 0x11 },
- { 0x10007897, 0x44 },
- { 0x10007898, 0x93 },
- { 0x10007899, 0xf7 },
- { 0x1000789a, 0xd7 },
- { 0x1000789b, 0x0f },
- { 0x1000789c, 0x63 },
- { 0x1000789d, 0x90 },
- { 0x1000789e, 0x07 },
- { 0x1000789f, 0x02 },
- { 0x100078a0, 0x03 },
- { 0x100078a1, 0xc7 },
- { 0x100078a2, 0xd1 },
- { 0x100078a3, 0x58 },
- { 0x100078a4, 0xb7 },
- { 0x100078a5, 0x07 },
- { 0x100078a6, 0x00 },
- { 0x100078a7, 0x11 },
- { 0x100078a8, 0x23 },
- { 0x100078a9, 0x88 },
- { 0x100078aa, 0xe7 },
- { 0x100078ab, 0x00 },
- { 0x100078ac, 0x23 },
- { 0x100078ad, 0x88 },
- { 0x100078ae, 0xe7 },
- { 0x100078af, 0x20 },
- { 0x100078b0, 0x03 },
- { 0x100078b1, 0xc7 },
- { 0x100078b2, 0xc1 },
- { 0x100078b3, 0x58 },
- { 0x100078b4, 0x23 },
- { 0x100078b5, 0x8c },
- { 0x100078b6, 0xe7 },
- { 0x100078b7, 0x00 },
- { 0x100078b8, 0x6f },
- { 0x100078b9, 0x00 },
- { 0x100078ba, 0x80 },
- { 0x100078bb, 0x04 },
- { 0x100078bc, 0xb7 },
- { 0x100078bd, 0x07 },
- { 0x100078be, 0x00 },
- { 0x100078bf, 0x11 },
- { 0x100078c0, 0x23 },
- { 0x100078c1, 0x88 },
- { 0x100078c2, 0x07 },
- { 0x100078c3, 0x00 },
- { 0x100078c4, 0x23 },
- { 0x100078c5, 0x88 },
- { 0x100078c6, 0x07 },
- { 0x100078c7, 0x20 },
- { 0x100078c8, 0x23 },
- { 0x100078c9, 0x8c },
- { 0x100078ca, 0x07 },
- { 0x100078cb, 0x00 },
- { 0x100078cc, 0x23 },
- { 0x100078cd, 0x8c },
- { 0x100078ce, 0x07 },
- { 0x100078cf, 0x20 },
- { 0x100078d0, 0xef },
- { 0x100078d1, 0xb0 },
- { 0x100078d2, 0xcf },
- { 0x100078d3, 0xc4 },
- { 0x100078d4, 0x03 },
- { 0x100078d5, 0x24 },
- { 0x100078d6, 0x81 },
- { 0x100078d7, 0x00 },
- { 0x100078d8, 0x83 },
- { 0x100078d9, 0x20 },
- { 0x100078da, 0xc1 },
- { 0x100078db, 0x00 },
- { 0x100078dc, 0x13 },
- { 0x100078dd, 0x01 },
- { 0x100078de, 0x01 },
- { 0x100078df, 0x01 },
- { 0x100078e0, 0x6f },
- { 0x100078e1, 0xb0 },
- { 0x100078e2, 0xcf },
- { 0x100078e3, 0xcd },
- { 0x100078e4, 0x03 },
- { 0x100078e5, 0xc7 },
- { 0x100078e6, 0xd1 },
- { 0x100078e7, 0x58 },
- { 0x100078e8, 0xb7 },
- { 0x100078e9, 0x07 },
- { 0x100078ea, 0x00 },
- { 0x100078eb, 0x11 },
- { 0x100078ec, 0x23 },
- { 0x100078ed, 0x88 },
- { 0x100078ee, 0xe7 },
- { 0x100078ef, 0x00 },
- { 0x100078f0, 0x83 },
- { 0x100078f1, 0xc6 },
- { 0x100078f2, 0xc1 },
- { 0x100078f3, 0x58 },
- { 0x100078f4, 0x23 },
- { 0x100078f5, 0x88 },
- { 0x100078f6, 0xd7 },
- { 0x100078f7, 0x20 },
- { 0x100078f8, 0x23 },
- { 0x100078f9, 0x8c },
- { 0x100078fa, 0xd7 },
- { 0x100078fb, 0x00 },
- { 0x100078fc, 0x03 },
- { 0x100078fd, 0xc7 },
- { 0x100078fe, 0xc1 },
- { 0x100078ff, 0x58 },
- { 0x10007900, 0x23 },
- { 0x10007901, 0x8c },
- { 0x10007902, 0xe7 },
- { 0x10007903, 0x20 },
- { 0x10007904, 0x6f },
- { 0x10007905, 0xf0 },
- { 0x10007906, 0xdf },
- { 0x10007907, 0xfc },
- { 0x10007908, 0xb7 },
- { 0x10007909, 0x06 },
- { 0x1000790a, 0x00 },
- { 0x1000790b, 0x11 },
- { 0x1000790c, 0x03 },
- { 0x1000790d, 0xc7 },
- { 0x1000790e, 0x06 },
- { 0x1000790f, 0x21 },
- { 0x10007910, 0x03 },
- { 0x10007911, 0xc6 },
- { 0x10007912, 0xd1 },
- { 0x10007913, 0x58 },
- { 0x10007914, 0x13 },
- { 0x10007915, 0x84 },
- { 0x10007916, 0x07 },
- { 0x10007917, 0x00 },
- { 0x10007918, 0x13 },
- { 0x10007919, 0x77 },
- { 0x1000791a, 0xf7 },
- { 0x1000791b, 0x0f },
- { 0x1000791c, 0x63 },
- { 0x1000791d, 0x1a },
- { 0x1000791e, 0xe6 },
- { 0x1000791f, 0x00 },
- { 0x10007920, 0x83 },
- { 0x10007921, 0xc7 },
- { 0x10007922, 0x86 },
- { 0x10007923, 0x21 },
- { 0x10007924, 0x03 },
- { 0x10007925, 0xc7 },
- { 0x10007926, 0xc1 },
- { 0x10007927, 0x58 },
- { 0x10007928, 0x93 },
- { 0x10007929, 0xf7 },
- { 0x1000792a, 0xf7 },
- { 0x1000792b, 0x0f },
- { 0x1000792c, 0xe3 },
- { 0x1000792d, 0x02 },
- { 0x1000792e, 0xf7 },
- { 0x1000792f, 0xfa },
- { 0x10007930, 0xb7 },
- { 0x10007931, 0xc7 },
- { 0x10007932, 0x00 },
- { 0x10007933, 0x00 },
- { 0x10007934, 0x83 },
- { 0x10007935, 0xc7 },
- { 0x10007936, 0x07 },
- { 0x10007937, 0x56 },
- { 0x10007938, 0x13 },
- { 0x10007939, 0x07 },
- { 0x1000793a, 0xf0 },
- { 0x1000793b, 0x00 },
- { 0x1000793c, 0x93 },
- { 0x1000793d, 0xf7 },
- { 0x1000793e, 0xf7 },
- { 0x1000793f, 0x0f },
- { 0x10007940, 0xe3 },
- { 0x10007941, 0x78 },
- { 0x10007942, 0xf7 },
- { 0x10007943, 0xf8 },
- { 0x10007944, 0xb7 },
- { 0x10007945, 0xd7 },
- { 0x10007946, 0x00 },
- { 0x10007947, 0x00 },
- { 0x10007948, 0x83 },
- { 0x10007949, 0xc5 },
- { 0x1000794a, 0xa7 },
- { 0x1000794b, 0x47 },
- { 0x1000794c, 0x93 },
- { 0x1000794d, 0xf7 },
- { 0x1000794e, 0xf5 },
- { 0x1000794f, 0x0f },
- { 0x10007950, 0x93 },
- { 0x10007951, 0x95 },
- { 0x10007952, 0x57 },
- { 0x10007953, 0x00 },
- { 0x10007954, 0xb3 },
- { 0x10007955, 0x85 },
- { 0x10007956, 0xf5 },
- { 0x10007957, 0x40 },
- { 0x10007958, 0x93 },
- { 0x10007959, 0x95 },
- { 0x1000795a, 0x25 },
- { 0x1000795b, 0x00 },
- { 0x1000795c, 0xb3 },
- { 0x1000795d, 0x85 },
- { 0x1000795e, 0xf5 },
- { 0x1000795f, 0x00 },
- { 0x10007960, 0x13 },
- { 0x10007961, 0x95 },
- { 0x10007962, 0x35 },
- { 0x10007963, 0x00 },
- { 0x10007964, 0x93 },
- { 0x10007965, 0xd5 },
- { 0x10007966, 0xf5 },
- { 0x10007967, 0x41 },
- { 0x10007968, 0xef },
- { 0x10007969, 0xe0 },
- { 0x1000796a, 0xcf },
- { 0x1000796b, 0x8b },
- { 0x1000796c, 0x03 },
- { 0x1000796d, 0xc7 },
- { 0x1000796e, 0xd1 },
- { 0x1000796f, 0x58 },
- { 0x10007970, 0x6f },
- { 0x10007971, 0xf0 },
- { 0x10007972, 0x5f },
- { 0x10007973, 0xf3 },
- { 0x10007974, 0x13 },
- { 0x10007975, 0x01 },
- { 0x10007976, 0x01 },
- { 0x10007977, 0xfe },
- { 0x10007978, 0x23 },
- { 0x10007979, 0x2c },
- { 0x1000797a, 0x81 },
- { 0x1000797b, 0x00 },
- { 0x1000797c, 0x83 },
- { 0x1000797d, 0xc7 },
- { 0x1000797e, 0x21 },
- { 0x1000797f, 0x41 },
- { 0x10007980, 0x23 },
- { 0x10007981, 0x2e },
- { 0x10007982, 0x11 },
- { 0x10007983, 0x00 },
- { 0x10007984, 0x23 },
- { 0x10007985, 0x2a },
- { 0x10007986, 0x91 },
- { 0x10007987, 0x00 },
- { 0x10007988, 0x23 },
- { 0x10007989, 0x28 },
- { 0x1000798a, 0x21 },
- { 0x1000798b, 0x01 },
- { 0x1000798c, 0x23 },
- { 0x1000798d, 0x26 },
- { 0x1000798e, 0x31 },
- { 0x1000798f, 0x01 },
- { 0x10007990, 0x13 },
- { 0x10007991, 0x07 },
- { 0x10007992, 0x10 },
- { 0x10007993, 0x00 },
- { 0x10007994, 0x63 },
- { 0x10007995, 0x92 },
- { 0x10007996, 0xe7 },
- { 0x10007997, 0x02 },
- { 0x10007998, 0xa3 },
- { 0x10007999, 0x81 },
- { 0x1000799a, 0xf1 },
- { 0x1000799b, 0x40 },
- { 0x1000799c, 0x83 },
- { 0x1000799d, 0x20 },
- { 0x1000799e, 0xc1 },
- { 0x1000799f, 0x01 },
- { 0x100079a0, 0x03 },
- { 0x100079a1, 0x24 },
- { 0x100079a2, 0x81 },
- { 0x100079a3, 0x01 },
- { 0x100079a4, 0x83 },
- { 0x100079a5, 0x24 },
- { 0x100079a6, 0x41 },
- { 0x100079a7, 0x01 },
- { 0x100079a8, 0x03 },
- { 0x100079a9, 0x29 },
- { 0x100079aa, 0x01 },
- { 0x100079ab, 0x01 },
- { 0x100079ac, 0x83 },
- { 0x100079ad, 0x29 },
- { 0x100079ae, 0xc1 },
- { 0x100079af, 0x00 },
- { 0x100079b0, 0x13 },
- { 0x100079b1, 0x01 },
- { 0x100079b2, 0x01 },
- { 0x100079b3, 0x02 },
- { 0x100079b4, 0x67 },
- { 0x100079b5, 0x80 },
- { 0x100079b6, 0x00 },
- { 0x100079b7, 0x00 },
- { 0x100079b8, 0xe3 },
- { 0x100079b9, 0x92 },
- { 0x100079ba, 0x07 },
- { 0x100079bb, 0xfe },
- { 0x100079bc, 0x37 },
- { 0x100079bd, 0xc9 },
- { 0x100079be, 0x00 },
- { 0x100079bf, 0x00 },
- { 0x100079c0, 0x83 },
- { 0x100079c1, 0x47 },
- { 0x100079c2, 0x09 },
- { 0x100079c3, 0x56 },
- { 0x100079c4, 0x13 },
- { 0x100079c5, 0x07 },
- { 0x100079c6, 0x80 },
- { 0x100079c7, 0x01 },
- { 0x100079c8, 0x93 },
- { 0x100079c9, 0xf7 },
- { 0x100079ca, 0xf7 },
- { 0x100079cb, 0x0f },
- { 0x100079cc, 0xe3 },
- { 0x100079cd, 0x78 },
- { 0x100079ce, 0xf7 },
- { 0x100079cf, 0xfc },
- { 0x100079d0, 0x83 },
- { 0x100079d1, 0xc7 },
- { 0x100079d2, 0x31 },
- { 0x100079d3, 0x40 },
- { 0x100079d4, 0xe3 },
- { 0x100079d5, 0x84 },
- { 0x100079d6, 0x07 },
- { 0x100079d7, 0xfc },
- { 0x100079d8, 0xb7 },
- { 0x100079d9, 0xd4 },
- { 0x100079da, 0x00 },
- { 0x100079db, 0x00 },
- { 0x100079dc, 0x03 },
- { 0x100079dd, 0xc5 },
- { 0x100079de, 0x94 },
- { 0x100079df, 0x47 },
- { 0x100079e0, 0xb7 },
- { 0x100079e1, 0x15 },
- { 0x100079e2, 0x00 },
- { 0x100079e3, 0x00 },
- { 0x100079e4, 0x93 },
- { 0x100079e5, 0x85 },
- { 0x100079e6, 0x85 },
- { 0x100079e7, 0x38 },
- { 0x100079e8, 0x13 },
- { 0x100079e9, 0x75 },
- { 0x100079ea, 0xf5 },
- { 0x100079eb, 0x0f },
- { 0x100079ec, 0xef },
- { 0x100079ed, 0xe0 },
- { 0x100079ee, 0x5f },
- { 0x100079ef, 0xe0 },
- { 0x100079f0, 0x93 },
- { 0x100079f1, 0x55 },
- { 0x100079f2, 0xf5 },
- { 0x100079f3, 0x41 },
- { 0x100079f4, 0xef },
- { 0x100079f5, 0xe0 },
- { 0x100079f6, 0x0f },
- { 0x100079f7, 0x83 },
- { 0x100079f8, 0xa3 },
- { 0x100079f9, 0x81 },
- { 0x100079fa, 0x01 },
- { 0x100079fb, 0x40 },
- { 0x100079fc, 0x83 },
- { 0x100079fd, 0x27 },
- { 0x100079fe, 0xc9 },
- { 0x100079ff, 0x5f },
- { 0x10007a00, 0x37 },
- { 0x10007a01, 0x07 },
- { 0x10007a02, 0x00 },
- { 0x10007a03, 0x02 },
- { 0x10007a04, 0xb3 },
- { 0x10007a05, 0xf7 },
- { 0x10007a06, 0xe7 },
- { 0x10007a07, 0x00 },
- { 0x10007a08, 0xe3 },
- { 0x10007a09, 0x8a },
- { 0x10007a0a, 0x07 },
- { 0x10007a0b, 0xf8 },
- { 0x10007a0c, 0x03 },
- { 0x10007a0d, 0xc7 },
- { 0x10007a0e, 0x04 },
- { 0x10007a0f, 0x90 },
- { 0x10007a10, 0x93 },
- { 0x10007a11, 0x07 },
- { 0x10007a12, 0x10 },
- { 0x10007a13, 0x00 },
- { 0x10007a14, 0x13 },
- { 0x10007a15, 0x77 },
- { 0x10007a16, 0x17 },
- { 0x10007a17, 0x00 },
- { 0x10007a18, 0x63 },
- { 0x10007a19, 0x1c },
- { 0x10007a1a, 0x07 },
- { 0x10007a1b, 0x00 },
- { 0x10007a1c, 0x83 },
- { 0x10007a1d, 0xc7 },
- { 0x10007a1e, 0x34 },
- { 0x10007a1f, 0x54 },
- { 0x10007a20, 0x93 },
- { 0x10007a21, 0xf7 },
- { 0x10007a22, 0xf7 },
- { 0x10007a23, 0x0f },
- { 0x10007a24, 0x93 },
- { 0x10007a25, 0xd7 },
- { 0x10007a26, 0x17 },
- { 0x10007a27, 0x00 },
- { 0x10007a28, 0x93 },
- { 0x10007a29, 0xc7 },
- { 0x10007a2a, 0x17 },
- { 0x10007a2b, 0x00 },
- { 0x10007a2c, 0x93 },
- { 0x10007a2d, 0xf7 },
- { 0x10007a2e, 0x17 },
- { 0x10007a2f, 0x00 },
- { 0x10007a30, 0xa3 },
- { 0x10007a31, 0x85 },
- { 0x10007a32, 0xf1 },
- { 0x10007a33, 0x42 },
- { 0x10007a34, 0x37 },
- { 0x10007a35, 0xd6 },
- { 0x10007a36, 0x00 },
- { 0x10007a37, 0x00 },
- { 0x10007a38, 0x03 },
- { 0x10007a39, 0x47 },
- { 0x10007a3a, 0x06 },
- { 0x10007a3b, 0x90 },
- { 0x10007a3c, 0x93 },
- { 0x10007a3d, 0x06 },
- { 0x10007a3e, 0x10 },
- { 0x10007a3f, 0x00 },
- { 0x10007a40, 0x13 },
- { 0x10007a41, 0x77 },
- { 0x10007a42, 0x27 },
- { 0x10007a43, 0x00 },
- { 0x10007a44, 0x63 },
- { 0x10007a45, 0x18 },
- { 0x10007a46, 0x07 },
- { 0x10007a47, 0x00 },
- { 0x10007a48, 0x03 },
- { 0x10007a49, 0x47 },
- { 0x10007a4a, 0x36 },
- { 0x10007a4b, 0x54 },
- { 0x10007a4c, 0x13 },
- { 0x10007a4d, 0x77 },
- { 0x10007a4e, 0x17 },
- { 0x10007a4f, 0x00 },
- { 0x10007a50, 0xb3 },
- { 0x10007a51, 0x86 },
- { 0x10007a52, 0xe6 },
- { 0x10007a53, 0x40 },
- { 0x10007a54, 0x23 },
- { 0x10007a55, 0x85 },
- { 0x10007a56, 0xd1 },
- { 0x10007a57, 0x42 },
- { 0x10007a58, 0xb7 },
- { 0x10007a59, 0xd5 },
- { 0x10007a5a, 0x00 },
- { 0x10007a5b, 0x00 },
- { 0x10007a5c, 0x03 },
- { 0x10007a5d, 0xc6 },
- { 0x10007a5e, 0x05 },
- { 0x10007a5f, 0x92 },
- { 0x10007a60, 0x13 },
- { 0x10007a61, 0x07 },
- { 0x10007a62, 0x10 },
- { 0x10007a63, 0x00 },
- { 0x10007a64, 0x13 },
- { 0x10007a65, 0x76 },
- { 0x10007a66, 0x16 },
- { 0x10007a67, 0x00 },
- { 0x10007a68, 0x63 },
- { 0x10007a69, 0x1c },
- { 0x10007a6a, 0x06 },
- { 0x10007a6b, 0x00 },
- { 0x10007a6c, 0x03 },
- { 0x10007a6d, 0xc7 },
- { 0x10007a6e, 0x35 },
- { 0x10007a6f, 0x54 },
- { 0x10007a70, 0x13 },
- { 0x10007a71, 0x77 },
- { 0x10007a72, 0xf7 },
- { 0x10007a73, 0x0f },
- { 0x10007a74, 0x13 },
- { 0x10007a75, 0x57 },
- { 0x10007a76, 0x37 },
- { 0x10007a77, 0x00 },
- { 0x10007a78, 0x13 },
- { 0x10007a79, 0x47 },
- { 0x10007a7a, 0x17 },
- { 0x10007a7b, 0x00 },
- { 0x10007a7c, 0x13 },
- { 0x10007a7d, 0x77 },
- { 0x10007a7e, 0x17 },
- { 0x10007a7f, 0x00 },
- { 0x10007a80, 0xa3 },
- { 0x10007a81, 0x84 },
- { 0x10007a82, 0xe1 },
- { 0x10007a83, 0x42 },
- { 0x10007a84, 0xb7 },
- { 0x10007a85, 0xd5 },
- { 0x10007a86, 0x00 },
- { 0x10007a87, 0x00 },
- { 0x10007a88, 0x03 },
- { 0x10007a89, 0xc6 },
- { 0x10007a8a, 0x05 },
- { 0x10007a8b, 0x92 },
- { 0x10007a8c, 0x13 },
- { 0x10007a8d, 0x07 },
- { 0x10007a8e, 0x10 },
- { 0x10007a8f, 0x00 },
- { 0x10007a90, 0x13 },
- { 0x10007a91, 0x76 },
- { 0x10007a92, 0x26 },
- { 0x10007a93, 0x00 },
- { 0x10007a94, 0x63 },
- { 0x10007a95, 0x1c },
- { 0x10007a96, 0x06 },
- { 0x10007a97, 0x00 },
- { 0x10007a98, 0x03 },
- { 0x10007a99, 0xc7 },
- { 0x10007a9a, 0x35 },
- { 0x10007a9b, 0x54 },
- { 0x10007a9c, 0x13 },
- { 0x10007a9d, 0x77 },
- { 0x10007a9e, 0xf7 },
- { 0x10007a9f, 0x0f },
- { 0x10007aa0, 0x13 },
- { 0x10007aa1, 0x57 },
- { 0x10007aa2, 0x27 },
- { 0x10007aa3, 0x00 },
- { 0x10007aa4, 0x13 },
- { 0x10007aa5, 0x47 },
- { 0x10007aa6, 0x17 },
- { 0x10007aa7, 0x00 },
- { 0x10007aa8, 0x13 },
- { 0x10007aa9, 0x77 },
- { 0x10007aaa, 0x17 },
- { 0x10007aab, 0x00 },
- { 0x10007aac, 0x23 },
- { 0x10007aad, 0x84 },
- { 0x10007aae, 0xe1 },
- { 0x10007aaf, 0x42 },
- { 0x10007ab0, 0x63 },
- { 0x10007ab1, 0x84 },
- { 0x10007ab2, 0x07 },
- { 0x10007ab3, 0x00 },
- { 0x10007ab4, 0xe3 },
- { 0x10007ab5, 0x94 },
- { 0x10007ab6, 0x06 },
- { 0x10007ab7, 0xee },
- { 0x10007ab8, 0xef },
- { 0x10007ab9, 0x90 },
- { 0x10007aba, 0x0f },
- { 0x10007abb, 0x86 },
- { 0x10007abc, 0xef },
- { 0x10007abd, 0xd0 },
- { 0x10007abe, 0x0f },
- { 0x10007abf, 0x97 },
- { 0x10007ac0, 0x37 },
- { 0x10007ac1, 0x15 },
- { 0x10007ac2, 0x00 },
- { 0x10007ac3, 0x00 },
- { 0x10007ac4, 0x13 },
- { 0x10007ac5, 0x05 },
- { 0x10007ac6, 0x85 },
- { 0x10007ac7, 0xbb },
- { 0x10007ac8, 0x93 },
- { 0x10007ac9, 0x05 },
- { 0x10007aca, 0x00 },
- { 0x10007acb, 0x00 },
- { 0x10007acc, 0xef },
- { 0x10007acd, 0xd0 },
- { 0x10007ace, 0x9f },
- { 0x10007acf, 0xf5 },
- { 0x10007ad0, 0xb7 },
- { 0x10007ad1, 0xd7 },
- { 0x10007ad2, 0x00 },
- { 0x10007ad3, 0x00 },
- { 0x10007ad4, 0x83 },
- { 0x10007ad5, 0xc7 },
- { 0x10007ad6, 0x07 },
- { 0x10007ad7, 0x47 },
- { 0x10007ad8, 0x93 },
- { 0x10007ad9, 0xf7 },
- { 0x10007ada, 0x47 },
- { 0x10007adb, 0x00 },
- { 0x10007adc, 0xe3 },
- { 0x10007add, 0x80 },
- { 0x10007ade, 0x07 },
- { 0x10007adf, 0xec },
- { 0x10007ae0, 0xef },
- { 0x10007ae1, 0x80 },
- { 0x10007ae2, 0xdf },
- { 0x10007ae3, 0xf4 },
- { 0x10007ae4, 0x23 },
- { 0x10007ae5, 0x89 },
- { 0x10007ae6, 0xa1 },
- { 0x10007ae7, 0x40 },
- { 0x10007ae8, 0x6f },
- { 0x10007ae9, 0xf0 },
- { 0x10007aea, 0x5f },
- { 0x10007aeb, 0xeb },
- { 0x10007aec, 0x00 },
- { 0x10007aed, 0x00 },
- { 0x10007aee, 0x00 },
- { 0x10007aef, 0x00 },
{ 0x3fc2bf83, 0x00 },
{ 0x3fc2bf82, 0x00 },
{ 0x3fc2bf81, 0x00 },
@@ -2109,1346 +228,41 @@ static const struct reg_sequence rt1320_vc_patch_code_write[] = {
{ 0x0000d540, 0x01 },
{ 0x0000c081, 0xfc },
{ 0x0000f01e, 0x80 },
+ { 0xc01b, 0xfc },
+ { 0xc5d1, 0x89 },
+ { 0xc5d8, 0x0a },
+ { 0xc5f7, 0x22 },
+ { 0xc5f6, 0x22 },
+ { 0xc065, 0xa5 },
+ { 0xc06b, 0x0a },
+ { 0xd172, 0x2a },
+ { 0xc5d6, 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
};
-/*
- * The 'patch code' is written to the patch code area.
- * The patch code area is used for SDCA register expansion flexibility.
- */
-static const struct reg_sequence rt1320_patch_code_write[] = {
- { 0x10007000, 0x37 },
- { 0x10007001, 0x77 },
- { 0x10007002, 0x00 },
- { 0x10007003, 0x10 },
- { 0x10007004, 0xb7 },
- { 0x10007005, 0xe7 },
- { 0x10007006, 0x00 },
- { 0x10007007, 0x10 },
- { 0x10007008, 0x13 },
- { 0x10007009, 0x07 },
- { 0x1000700a, 0x07 },
- { 0x1000700b, 0x40 },
- { 0x1000700c, 0x23 },
- { 0x1000700d, 0xae },
- { 0x1000700e, 0xe7 },
- { 0x1000700f, 0xda },
- { 0x10007010, 0x37 },
- { 0x10007011, 0x77 },
- { 0x10007012, 0x00 },
- { 0x10007013, 0x10 },
- { 0x10007014, 0x13 },
- { 0x10007015, 0x07 },
- { 0x10007016, 0x47 },
- { 0x10007017, 0x61 },
- { 0x10007018, 0x23 },
- { 0x10007019, 0xa4 },
- { 0x1000701a, 0xe7 },
- { 0x1000701b, 0xde },
- { 0x1000701c, 0x37 },
- { 0x1000701d, 0x77 },
- { 0x1000701e, 0x00 },
- { 0x1000701f, 0x10 },
- { 0x10007020, 0x13 },
- { 0x10007021, 0x07 },
- { 0x10007022, 0x07 },
- { 0x10007023, 0x52 },
- { 0x10007024, 0x23 },
- { 0x10007025, 0xae },
- { 0x10007026, 0xe7 },
- { 0x10007027, 0xde },
- { 0x10007028, 0x37 },
- { 0x10007029, 0x77 },
- { 0x1000702a, 0x00 },
- { 0x1000702b, 0x10 },
- { 0x1000702c, 0x13 },
- { 0x1000702d, 0x07 },
- { 0x1000702e, 0x47 },
- { 0x1000702f, 0x54 },
- { 0x10007030, 0x23 },
- { 0x10007031, 0xaa },
- { 0x10007032, 0xe7 },
- { 0x10007033, 0xe4 },
- { 0x10007034, 0x37 },
- { 0x10007035, 0x87 },
- { 0x10007036, 0x00 },
- { 0x10007037, 0x10 },
- { 0x10007038, 0x13 },
- { 0x10007039, 0x07 },
- { 0x1000703a, 0x47 },
- { 0x1000703b, 0x81 },
- { 0x1000703c, 0x23 },
- { 0x1000703d, 0xa2 },
- { 0x1000703e, 0xe7 },
- { 0x1000703f, 0xe8 },
- { 0x10007040, 0x23 },
- { 0x10007041, 0xa4 },
- { 0x10007042, 0xe7 },
- { 0x10007043, 0xe8 },
- { 0x10007044, 0x37 },
- { 0x10007045, 0x77 },
- { 0x10007046, 0x00 },
- { 0x10007047, 0x10 },
- { 0x10007048, 0x13 },
- { 0x10007049, 0x07 },
- { 0x1000704a, 0x07 },
- { 0x1000704b, 0x59 },
- { 0x1000704c, 0x23 },
- { 0x1000704d, 0xa8 },
- { 0x1000704e, 0xe7 },
- { 0x1000704f, 0xea },
- { 0x10007050, 0x37 },
- { 0x10007051, 0x77 },
- { 0x10007052, 0x00 },
- { 0x10007053, 0x10 },
- { 0x10007054, 0x13 },
- { 0x10007055, 0x07 },
- { 0x10007056, 0x07 },
- { 0x10007057, 0x78 },
- { 0x10007058, 0x23 },
- { 0x10007059, 0xa6 },
- { 0x1000705a, 0xe7 },
- { 0x1000705b, 0xec },
- { 0x1000705c, 0x67 },
- { 0x1000705d, 0x80 },
- { 0x1000705e, 0x00 },
- { 0x1000705f, 0x00 },
- { 0x10007400, 0x37 },
- { 0x10007401, 0xd7 },
- { 0x10007402, 0x00 },
- { 0x10007403, 0x00 },
- { 0x10007404, 0x83 },
- { 0x10007405, 0x27 },
- { 0x10007406, 0x47 },
- { 0x10007407, 0x56 },
- { 0x10007408, 0xb7 },
- { 0x10007409, 0x06 },
- { 0x1000740a, 0x00 },
- { 0x1000740b, 0x02 },
- { 0x1000740c, 0xb3 },
- { 0x1000740d, 0xf7 },
- { 0x1000740e, 0xd7 },
- { 0x1000740f, 0x00 },
- { 0x10007410, 0x63 },
- { 0x10007411, 0x8a },
- { 0x10007412, 0x07 },
- { 0x10007413, 0x00 },
- { 0x10007414, 0x93 },
- { 0x10007415, 0x06 },
- { 0x10007416, 0x10 },
- { 0x10007417, 0x00 },
- { 0x10007418, 0x23 },
- { 0x10007419, 0x83 },
- { 0x1000741a, 0xd1 },
- { 0x1000741b, 0x44 },
- { 0x1000741c, 0x93 },
- { 0x1000741d, 0x07 },
- { 0x1000741e, 0xf0 },
- { 0x1000741f, 0xff },
- { 0x10007420, 0x23 },
- { 0x10007421, 0x22 },
- { 0x10007422, 0xf7 },
- { 0x10007423, 0x56 },
- { 0x10007424, 0x37 },
- { 0x10007425, 0xd7 },
- { 0x10007426, 0x00 },
- { 0x10007427, 0x00 },
- { 0x10007428, 0x83 },
- { 0x10007429, 0x27 },
- { 0x1000742a, 0x47 },
- { 0x1000742b, 0x58 },
- { 0x1000742c, 0x93 },
- { 0x1000742d, 0xf7 },
- { 0x1000742e, 0x17 },
- { 0x1000742f, 0x00 },
- { 0x10007430, 0x63 },
- { 0x10007431, 0x86 },
- { 0x10007432, 0x07 },
- { 0x10007433, 0x00 },
- { 0x10007434, 0x93 },
- { 0x10007435, 0x07 },
- { 0x10007436, 0x10 },
- { 0x10007437, 0x00 },
- { 0x10007438, 0x23 },
- { 0x10007439, 0x22 },
- { 0x1000743a, 0xf7 },
- { 0x1000743b, 0x58 },
- { 0x1000743c, 0xb7 },
- { 0x1000743d, 0xd7 },
- { 0x1000743e, 0x00 },
- { 0x1000743f, 0x00 },
- { 0x10007440, 0x03 },
- { 0x10007441, 0xa7 },
- { 0x10007442, 0x47 },
- { 0x10007443, 0x58 },
- { 0x10007444, 0xb7 },
- { 0x10007445, 0x07 },
- { 0x10007446, 0x00 },
- { 0x10007447, 0x04 },
- { 0x10007448, 0x33 },
- { 0x10007449, 0x77 },
- { 0x1000744a, 0xf7 },
- { 0x1000744b, 0x00 },
- { 0x1000744c, 0x93 },
- { 0x1000744d, 0x07 },
- { 0x1000744e, 0x00 },
- { 0x1000744f, 0x00 },
- { 0x10007450, 0x63 },
- { 0x10007451, 0x0e },
- { 0x10007452, 0x07 },
- { 0x10007453, 0x04 },
- { 0x10007454, 0x37 },
- { 0x10007455, 0x07 },
- { 0x10007456, 0x00 },
- { 0x10007457, 0x11 },
- { 0x10007458, 0x03 },
- { 0x10007459, 0x47 },
- { 0x1000745a, 0x87 },
- { 0x1000745b, 0x0e },
- { 0x1000745c, 0x93 },
- { 0x1000745d, 0x06 },
- { 0x1000745e, 0x40 },
- { 0x1000745f, 0x00 },
- { 0x10007460, 0x13 },
- { 0x10007461, 0x77 },
- { 0x10007462, 0xf7 },
- { 0x10007463, 0x0f },
- { 0x10007464, 0x63 },
- { 0x10007465, 0x02 },
- { 0x10007466, 0xd7 },
- { 0x10007467, 0x0a },
- { 0x10007468, 0x93 },
- { 0x10007469, 0x06 },
- { 0x1000746a, 0x70 },
- { 0x1000746b, 0x00 },
- { 0x1000746c, 0x63 },
- { 0x1000746d, 0x10 },
- { 0x1000746e, 0xd7 },
- { 0x1000746f, 0x04 },
- { 0x10007470, 0x93 },
- { 0x10007471, 0x07 },
- { 0x10007472, 0x60 },
- { 0x10007473, 0x06 },
- { 0x10007474, 0x37 },
- { 0x10007475, 0xd7 },
- { 0x10007476, 0x00 },
- { 0x10007477, 0x00 },
- { 0x10007478, 0x83 },
- { 0x10007479, 0x46 },
- { 0x1000747a, 0x77 },
- { 0x1000747b, 0xa6 },
- { 0x1000747c, 0x93 },
- { 0x1000747d, 0xe6 },
- { 0x1000747e, 0x06 },
- { 0x1000747f, 0xf8 },
- { 0x10007480, 0x93 },
- { 0x10007481, 0xf6 },
- { 0x10007482, 0xf6 },
- { 0x10007483, 0x0f },
- { 0x10007484, 0xa3 },
- { 0x10007485, 0x03 },
- { 0x10007486, 0xd7 },
- { 0x10007487, 0xa6 },
- { 0x10007488, 0x83 },
- { 0x10007489, 0x46 },
- { 0x1000748a, 0x77 },
- { 0x1000748b, 0xa8 },
- { 0x1000748c, 0x93 },
- { 0x1000748d, 0xe6 },
- { 0x1000748e, 0x06 },
- { 0x1000748f, 0xf8 },
- { 0x10007490, 0x93 },
- { 0x10007491, 0xf6 },
- { 0x10007492, 0xf6 },
- { 0x10007493, 0x0f },
- { 0x10007494, 0xa3 },
- { 0x10007495, 0x03 },
- { 0x10007496, 0xd7 },
- { 0x10007497, 0xa8 },
- { 0x10007498, 0xb7 },
- { 0x10007499, 0xc6 },
- { 0x1000749a, 0x00 },
- { 0x1000749b, 0x00 },
- { 0x1000749c, 0x23 },
- { 0x1000749d, 0x84 },
- { 0x1000749e, 0xf6 },
- { 0x1000749f, 0x06 },
- { 0x100074a0, 0xa3 },
- { 0x100074a1, 0x84 },
- { 0x100074a2, 0xf6 },
- { 0x100074a3, 0x06 },
- { 0x100074a4, 0xb7 },
- { 0x100074a5, 0x06 },
- { 0x100074a6, 0x00 },
- { 0x100074a7, 0x04 },
- { 0x100074a8, 0x23 },
- { 0x100074a9, 0x22 },
- { 0x100074aa, 0xd7 },
- { 0x100074ab, 0x58 },
- { 0x100074ac, 0x37 },
- { 0x100074ad, 0xd7 },
- { 0x100074ae, 0x00 },
- { 0x100074af, 0x00 },
- { 0x100074b0, 0x03 },
- { 0x100074b1, 0x27 },
- { 0x100074b2, 0x47 },
- { 0x100074b3, 0x58 },
- { 0x100074b4, 0xb7 },
- { 0x100074b5, 0x06 },
- { 0x100074b6, 0x00 },
- { 0x100074b7, 0x08 },
- { 0x100074b8, 0x33 },
- { 0x100074b9, 0x77 },
- { 0x100074ba, 0xd7 },
- { 0x100074bb, 0x00 },
- { 0x100074bc, 0x63 },
- { 0x100074bd, 0x04 },
- { 0x100074be, 0x07 },
- { 0x100074bf, 0x04 },
- { 0x100074c0, 0x37 },
- { 0x100074c1, 0x07 },
- { 0x100074c2, 0x00 },
- { 0x100074c3, 0x11 },
- { 0x100074c4, 0x03 },
- { 0x100074c5, 0x47 },
- { 0x100074c6, 0xc7 },
- { 0x100074c7, 0x0e },
- { 0x100074c8, 0x93 },
- { 0x100074c9, 0x06 },
- { 0x100074ca, 0x40 },
- { 0x100074cb, 0x00 },
- { 0x100074cc, 0x13 },
- { 0x100074cd, 0x77 },
- { 0x100074ce, 0xf7 },
- { 0x100074cf, 0x0f },
- { 0x100074d0, 0x63 },
- { 0x100074d1, 0x00 },
- { 0x100074d2, 0xd7 },
- { 0x100074d3, 0x04 },
- { 0x100074d4, 0x93 },
- { 0x100074d5, 0x06 },
- { 0x100074d6, 0x70 },
- { 0x100074d7, 0x00 },
- { 0x100074d8, 0x63 },
- { 0x100074d9, 0x00 },
- { 0x100074da, 0xd7 },
- { 0x100074db, 0x04 },
- { 0x100074dc, 0x63 },
- { 0x100074dd, 0x84 },
- { 0x100074de, 0x07 },
- { 0x100074df, 0x02 },
- { 0x100074e0, 0xb7 },
- { 0x100074e1, 0xd6 },
- { 0x100074e2, 0x00 },
- { 0x100074e3, 0x00 },
- { 0x100074e4, 0x03 },
- { 0x100074e5, 0xc7 },
- { 0x100074e6, 0x56 },
- { 0x100074e7, 0xa4 },
- { 0x100074e8, 0x13 },
- { 0x100074e9, 0x67 },
- { 0x100074ea, 0x07 },
- { 0x100074eb, 0xf8 },
- { 0x100074ec, 0x13 },
- { 0x100074ed, 0x77 },
- { 0x100074ee, 0xf7 },
- { 0x100074ef, 0x0f },
- { 0x100074f0, 0xa3 },
- { 0x100074f1, 0x82 },
- { 0x100074f2, 0xe6 },
- { 0x100074f3, 0xa4 },
- { 0x100074f4, 0x37 },
- { 0x100074f5, 0xc7 },
- { 0x100074f6, 0x00 },
- { 0x100074f7, 0x00 },
- { 0x100074f8, 0x23 },
- { 0x100074f9, 0x02 },
- { 0x100074fa, 0xf7 },
- { 0x100074fb, 0x06 },
- { 0x100074fc, 0xb7 },
- { 0x100074fd, 0x07 },
- { 0x100074fe, 0x00 },
- { 0x100074ff, 0x08 },
- { 0x10007500, 0x23 },
- { 0x10007501, 0xa2 },
- { 0x10007502, 0xf6 },
- { 0x10007503, 0x58 },
- { 0x10007504, 0x67 },
- { 0x10007505, 0x80 },
- { 0x10007506, 0x00 },
- { 0x10007507, 0x00 },
- { 0x10007508, 0x93 },
- { 0x10007509, 0x07 },
- { 0x1000750a, 0x80 },
- { 0x1000750b, 0x08 },
- { 0x1000750c, 0x6f },
- { 0x1000750d, 0xf0 },
- { 0x1000750e, 0x9f },
- { 0x1000750f, 0xf6 },
- { 0x10007510, 0x93 },
- { 0x10007511, 0x07 },
- { 0x10007512, 0x80 },
- { 0x10007513, 0x08 },
- { 0x10007514, 0x6f },
- { 0x10007515, 0xf0 },
- { 0x10007516, 0xdf },
- { 0x10007517, 0xfc },
- { 0x10007518, 0x93 },
- { 0x10007519, 0x07 },
- { 0x1000751a, 0x60 },
- { 0x1000751b, 0x06 },
- { 0x1000751c, 0x6f },
- { 0x1000751d, 0xf0 },
- { 0x1000751e, 0x5f },
- { 0x1000751f, 0xfc },
- { 0x10007520, 0x37 },
- { 0x10007521, 0xd7 },
- { 0x10007522, 0x00 },
- { 0x10007523, 0x00 },
- { 0x10007524, 0x83 },
- { 0x10007525, 0x27 },
- { 0x10007526, 0x07 },
- { 0x10007527, 0x53 },
- { 0x10007528, 0xb7 },
- { 0x10007529, 0x06 },
- { 0x1000752a, 0x02 },
- { 0x1000752b, 0x00 },
- { 0x1000752c, 0xb3 },
- { 0x1000752d, 0xf7 },
- { 0x1000752e, 0xd7 },
- { 0x1000752f, 0x00 },
- { 0x10007530, 0x63 },
- { 0x10007531, 0x88 },
- { 0x10007532, 0x07 },
- { 0x10007533, 0x00 },
- { 0x10007534, 0x13 },
- { 0x10007535, 0x06 },
- { 0x10007536, 0xa0 },
- { 0x10007537, 0x05 },
- { 0x10007538, 0x23 },
- { 0x10007539, 0xa8 },
- { 0x1000753a, 0xc1 },
- { 0x1000753b, 0x56 },
- { 0x1000753c, 0x23 },
- { 0x1000753d, 0x28 },
- { 0x1000753e, 0xd7 },
- { 0x1000753f, 0x52 },
- { 0x10007540, 0x67 },
- { 0x10007541, 0x80 },
- { 0x10007542, 0x00 },
- { 0x10007543, 0x00 },
- { 0x10007544, 0x37 },
- { 0x10007545, 0xd7 },
- { 0x10007546, 0x00 },
- { 0x10007547, 0x10 },
- { 0x10007548, 0x83 },
- { 0x10007549, 0x47 },
- { 0x1000754a, 0x07 },
- { 0x1000754b, 0xd9 },
- { 0x1000754c, 0x93 },
- { 0x1000754d, 0x06 },
- { 0x1000754e, 0x20 },
- { 0x1000754f, 0x00 },
- { 0x10007550, 0x93 },
- { 0x10007551, 0xf7 },
- { 0x10007552, 0xf7 },
- { 0x10007553, 0x0f },
- { 0x10007554, 0x63 },
- { 0x10007555, 0x9c },
- { 0x10007556, 0xd7 },
- { 0x10007557, 0x02 },
- { 0x10007558, 0xb7 },
- { 0x10007559, 0xc6 },
- { 0x1000755a, 0x00 },
- { 0x1000755b, 0x00 },
- { 0x1000755c, 0x83 },
- { 0x1000755d, 0xc7 },
- { 0x1000755e, 0x26 },
- { 0x1000755f, 0x04 },
- { 0x10007560, 0x93 },
- { 0x10007561, 0xf7 },
- { 0x10007562, 0xf7 },
- { 0x10007563, 0x07 },
- { 0x10007564, 0x23 },
- { 0x10007565, 0x81 },
- { 0x10007566, 0xf6 },
- { 0x10007567, 0x04 },
- { 0x10007568, 0xb7 },
- { 0x10007569, 0xd6 },
- { 0x1000756a, 0x00 },
- { 0x1000756b, 0x00 },
- { 0x1000756c, 0x83 },
- { 0x1000756d, 0xc7 },
- { 0x1000756e, 0xa6 },
- { 0x1000756f, 0xe1 },
- { 0x10007570, 0x93 },
- { 0x10007571, 0xf7 },
- { 0x10007572, 0xf7 },
- { 0x10007573, 0x07 },
- { 0x10007574, 0x23 },
- { 0x10007575, 0x8d },
- { 0x10007576, 0xf6 },
- { 0x10007577, 0xe0 },
- { 0x10007578, 0x23 },
- { 0x10007579, 0x08 },
- { 0x1000757a, 0x07 },
- { 0x1000757b, 0xd8 },
- { 0x1000757c, 0x83 },
- { 0x1000757d, 0x47 },
- { 0x1000757e, 0x47 },
- { 0x1000757f, 0xd9 },
- { 0x10007580, 0x93 },
- { 0x10007581, 0x87 },
- { 0x10007582, 0x17 },
- { 0x10007583, 0x00 },
- { 0x10007584, 0x93 },
- { 0x10007585, 0xf7 },
- { 0x10007586, 0xf7 },
- { 0x10007587, 0x0f },
- { 0x10007588, 0x23 },
- { 0x10007589, 0x0a },
- { 0x1000758a, 0xf7 },
- { 0x1000758b, 0xd8 },
- { 0x1000758c, 0x67 },
- { 0x1000758d, 0x80 },
- { 0x1000758e, 0x00 },
- { 0x1000758f, 0x00 },
- { 0x10007590, 0xb7 },
- { 0x10007591, 0xd7 },
- { 0x10007592, 0x00 },
- { 0x10007593, 0x00 },
- { 0x10007594, 0x83 },
- { 0x10007595, 0xc7 },
- { 0x10007596, 0x07 },
- { 0x10007597, 0x47 },
- { 0x10007598, 0x93 },
- { 0x10007599, 0xf7 },
- { 0x1000759a, 0x07 },
- { 0x1000759b, 0x01 },
- { 0x1000759c, 0x63 },
- { 0x1000759d, 0x8a },
- { 0x1000759e, 0x07 },
- { 0x1000759f, 0x06 },
- { 0x100075a0, 0x63 },
- { 0x100075a1, 0x02 },
- { 0x100075a2, 0x05 },
- { 0x100075a3, 0x06 },
- { 0x100075a4, 0x37 },
- { 0x100075a5, 0xc7 },
- { 0x100075a6, 0x00 },
- { 0x100075a7, 0x00 },
- { 0x100075a8, 0x83 },
- { 0x100075a9, 0x27 },
- { 0x100075aa, 0xc7 },
- { 0x100075ab, 0x5f },
- { 0x100075ac, 0x23 },
- { 0x100075ad, 0xae },
- { 0x100075ae, 0xf1 },
- { 0x100075af, 0x40 },
- { 0x100075b0, 0xb7 },
- { 0x100075b1, 0x06 },
- { 0x100075b2, 0x00 },
- { 0x100075b3, 0x10 },
- { 0x100075b4, 0xb3 },
- { 0x100075b5, 0xf7 },
- { 0x100075b6, 0xd7 },
- { 0x100075b7, 0x00 },
- { 0x100075b8, 0x63 },
- { 0x100075b9, 0x8c },
- { 0x100075ba, 0x07 },
- { 0x100075bb, 0x04 },
- { 0x100075bc, 0x83 },
- { 0x100075bd, 0x47 },
- { 0x100075be, 0x07 },
- { 0x100075bf, 0x56 },
- { 0x100075c0, 0x93 },
- { 0x100075c1, 0xf7 },
- { 0x100075c2, 0x87 },
- { 0x100075c3, 0x01 },
- { 0x100075c4, 0x63 },
- { 0x100075c5, 0x86 },
- { 0x100075c6, 0x07 },
- { 0x100075c7, 0x04 },
- { 0x100075c8, 0x83 },
- { 0x100075c9, 0x47 },
- { 0x100075ca, 0x17 },
- { 0x100075cb, 0x08 },
- { 0x100075cc, 0x93 },
- { 0x100075cd, 0xf7 },
- { 0x100075ce, 0x47 },
- { 0x100075cf, 0x00 },
- { 0x100075d0, 0x63 },
- { 0x100075d1, 0x80 },
- { 0x100075d2, 0x07 },
- { 0x100075d3, 0x04 },
- { 0x100075d4, 0xb7 },
- { 0x100075d5, 0xc7 },
- { 0x100075d6, 0xc2 },
- { 0x100075d7, 0x3f },
- { 0x100075d8, 0x93 },
- { 0x100075d9, 0x87 },
- { 0x100075da, 0x07 },
- { 0x100075db, 0xfc },
- { 0x100075dc, 0x83 },
- { 0x100075dd, 0xa7 },
- { 0x100075de, 0x47 },
- { 0x100075df, 0x00 },
- { 0x100075e0, 0x93 },
- { 0x100075e1, 0xd7 },
- { 0x100075e2, 0x17 },
- { 0x100075e3, 0x00 },
- { 0x100075e4, 0x93 },
- { 0x100075e5, 0xf7 },
- { 0x100075e6, 0x17 },
- { 0x100075e7, 0x00 },
- { 0x100075e8, 0x63 },
- { 0x100075e9, 0x84 },
- { 0x100075ea, 0x07 },
- { 0x100075eb, 0x02 },
- { 0x100075ec, 0x23 },
- { 0x100075ed, 0x8a },
- { 0x100075ee, 0xf1 },
- { 0x100075ef, 0x40 },
- { 0x100075f0, 0xb7 },
- { 0x100075f1, 0x07 },
- { 0x100075f2, 0x00 },
- { 0x100075f3, 0xc0 },
- { 0x100075f4, 0x37 },
- { 0x100075f5, 0xf7 },
- { 0x100075f6, 0x00 },
- { 0x100075f7, 0x00 },
- { 0x100075f8, 0x93 },
- { 0x100075f9, 0x87 },
- { 0x100075fa, 0xf7 },
- { 0x100075fb, 0xff },
- { 0x100075fc, 0x23 },
- { 0x100075fd, 0x2c },
- { 0x100075fe, 0xf7 },
- { 0x100075ff, 0x06 },
- { 0x10007600, 0x67 },
- { 0x10007601, 0x80 },
- { 0x10007602, 0x00 },
- { 0x10007603, 0x00 },
- { 0x10007604, 0x23 },
- { 0x10007605, 0x8a },
- { 0x10007606, 0x01 },
- { 0x10007607, 0x40 },
- { 0x10007608, 0xb7 },
- { 0x10007609, 0xf7 },
- { 0x1000760a, 0x00 },
- { 0x1000760b, 0x00 },
- { 0x1000760c, 0x23 },
- { 0x1000760d, 0xac },
- { 0x1000760e, 0x07 },
- { 0x1000760f, 0x06 },
- { 0x10007610, 0x67 },
- { 0x10007611, 0x80 },
- { 0x10007612, 0x00 },
- { 0x10007613, 0x00 },
- { 0x10007614, 0x13 },
- { 0x10007615, 0x01 },
- { 0x10007616, 0x01 },
- { 0x10007617, 0xff },
- { 0x10007618, 0x23 },
- { 0x10007619, 0x26 },
- { 0x1000761a, 0x11 },
- { 0x1000761b, 0x00 },
- { 0x1000761c, 0x23 },
- { 0x1000761d, 0x24 },
- { 0x1000761e, 0x81 },
- { 0x1000761f, 0x00 },
- { 0x10007620, 0x37 },
- { 0x10007621, 0xc7 },
- { 0x10007622, 0x00 },
- { 0x10007623, 0x00 },
- { 0x10007624, 0x83 },
- { 0x10007625, 0x47 },
- { 0x10007626, 0x07 },
- { 0x10007627, 0x56 },
- { 0x10007628, 0x93 },
- { 0x10007629, 0xf7 },
- { 0x1000762a, 0x17 },
- { 0x1000762b, 0x00 },
- { 0x1000762c, 0x63 },
- { 0x1000762d, 0x98 },
- { 0x1000762e, 0x07 },
- { 0x1000762f, 0x00 },
- { 0x10007630, 0x83 },
- { 0x10007631, 0x47 },
- { 0x10007632, 0x07 },
- { 0x10007633, 0x56 },
- { 0x10007634, 0x93 },
- { 0x10007635, 0xf7 },
- { 0x10007636, 0x27 },
- { 0x10007637, 0x00 },
- { 0x10007638, 0x63 },
- { 0x10007639, 0x82 },
- { 0x1000763a, 0x07 },
- { 0x1000763b, 0x08 },
- { 0x1000763c, 0x37 },
- { 0x1000763d, 0xd4 },
- { 0x1000763e, 0x00 },
- { 0x1000763f, 0x00 },
- { 0x10007640, 0x83 },
- { 0x10007641, 0x47 },
- { 0x10007642, 0x14 },
- { 0x10007643, 0x47 },
- { 0x10007644, 0x93 },
- { 0x10007645, 0xf7 },
- { 0x10007646, 0x27 },
- { 0x10007647, 0x00 },
- { 0x10007648, 0x63 },
- { 0x10007649, 0x8a },
- { 0x1000764a, 0x07 },
- { 0x1000764b, 0x06 },
- { 0x1000764c, 0x93 },
- { 0x1000764d, 0x05 },
- { 0x1000764e, 0x10 },
- { 0x1000764f, 0x00 },
- { 0x10007650, 0x13 },
- { 0x10007651, 0x05 },
- { 0x10007652, 0x20 },
- { 0x10007653, 0x10 },
- { 0x10007654, 0xef },
- { 0x10007655, 0xa0 },
- { 0x10007656, 0x8f },
- { 0x10007657, 0x9a },
- { 0x10007658, 0x37 },
- { 0x10007659, 0x05 },
- { 0x1000765a, 0x01 },
- { 0x1000765b, 0x00 },
- { 0x1000765c, 0x93 },
- { 0x1000765d, 0x05 },
- { 0x1000765e, 0x00 },
- { 0x1000765f, 0x01 },
- { 0x10007660, 0x13 },
- { 0x10007661, 0x05 },
- { 0x10007662, 0xb5 },
- { 0x10007663, 0xa0 },
- { 0x10007664, 0xef },
- { 0x10007665, 0xa0 },
- { 0x10007666, 0x8f },
- { 0x10007667, 0x99 },
- { 0x10007668, 0x83 },
- { 0x10007669, 0x47 },
- { 0x1000766a, 0x24 },
- { 0x1000766b, 0xe0 },
- { 0x1000766c, 0x13 },
- { 0x1000766d, 0x05 },
- { 0x1000766e, 0x80 },
- { 0x1000766f, 0x3e },
- { 0x10007670, 0x93 },
- { 0x10007671, 0x05 },
- { 0x10007672, 0x00 },
- { 0x10007673, 0x00 },
- { 0x10007674, 0x93 },
- { 0x10007675, 0xe7 },
- { 0x10007676, 0x07 },
- { 0x10007677, 0xf8 },
- { 0x10007678, 0x93 },
- { 0x10007679, 0xf7 },
- { 0x1000767a, 0xf7 },
- { 0x1000767b, 0x0f },
- { 0x1000767c, 0x23 },
- { 0x1000767d, 0x01 },
- { 0x1000767e, 0xf4 },
- { 0x1000767f, 0xe0 },
- { 0x10007680, 0x83 },
- { 0x10007681, 0x47 },
- { 0x10007682, 0x24 },
- { 0x10007683, 0xe0 },
- { 0x10007684, 0x93 },
- { 0x10007685, 0xf7 },
- { 0x10007686, 0xf7 },
- { 0x10007687, 0x0f },
- { 0x10007688, 0x93 },
- { 0x10007689, 0xe7 },
- { 0x1000768a, 0x07 },
- { 0x1000768b, 0x04 },
- { 0x1000768c, 0x23 },
- { 0x1000768d, 0x01 },
- { 0x1000768e, 0xf4 },
- { 0x1000768f, 0xe0 },
- { 0x10007690, 0xef },
- { 0x10007691, 0xe0 },
- { 0x10007692, 0x8f },
- { 0x10007693, 0xb9 },
- { 0x10007694, 0x83 },
- { 0x10007695, 0x47 },
- { 0x10007696, 0x34 },
- { 0x10007697, 0xe0 },
- { 0x10007698, 0x93 },
- { 0x10007699, 0xf7 },
- { 0x1000769a, 0x07 },
- { 0x1000769b, 0x02 },
- { 0x1000769c, 0xe3 },
- { 0x1000769d, 0x9c },
- { 0x1000769e, 0x07 },
- { 0x1000769f, 0xfe },
- { 0x100076a0, 0x37 },
- { 0x100076a1, 0x05 },
- { 0x100076a2, 0x01 },
- { 0x100076a3, 0x00 },
- { 0x100076a4, 0x93 },
- { 0x100076a5, 0x05 },
- { 0x100076a6, 0x00 },
- { 0x100076a7, 0x00 },
- { 0x100076a8, 0x13 },
- { 0x100076a9, 0x05 },
- { 0x100076aa, 0xb5 },
- { 0x100076ab, 0xa0 },
- { 0x100076ac, 0xef },
- { 0x100076ad, 0xa0 },
- { 0x100076ae, 0x0f },
- { 0x100076af, 0x95 },
- { 0x100076b0, 0x83 },
- { 0x100076b1, 0x47 },
- { 0x100076b2, 0x14 },
- { 0x100076b3, 0x47 },
- { 0x100076b4, 0x93 },
- { 0x100076b5, 0xf7 },
- { 0x100076b6, 0xd7 },
- { 0x100076b7, 0x0f },
- { 0x100076b8, 0xa3 },
- { 0x100076b9, 0x08 },
- { 0x100076ba, 0xf4 },
- { 0x100076bb, 0x46 },
- { 0x100076bc, 0x03 },
- { 0x100076bd, 0xa7 },
- { 0x100076be, 0x01 },
- { 0x100076bf, 0x57 },
- { 0x100076c0, 0x93 },
- { 0x100076c1, 0x07 },
- { 0x100076c2, 0xa0 },
- { 0x100076c3, 0x05 },
- { 0x100076c4, 0x63 },
- { 0x100076c5, 0x14 },
- { 0x100076c6, 0xf7 },
- { 0x100076c7, 0x04 },
- { 0x100076c8, 0x37 },
- { 0x100076c9, 0x07 },
- { 0x100076ca, 0x00 },
- { 0x100076cb, 0x11 },
- { 0x100076cc, 0x83 },
- { 0x100076cd, 0x47 },
- { 0x100076ce, 0x07 },
- { 0x100076cf, 0x01 },
- { 0x100076d0, 0x13 },
- { 0x100076d1, 0x06 },
- { 0x100076d2, 0x30 },
- { 0x100076d3, 0x00 },
- { 0x100076d4, 0x93 },
- { 0x100076d5, 0xf7 },
- { 0x100076d6, 0xf7 },
- { 0x100076d7, 0x0f },
- { 0x100076d8, 0x63 },
- { 0x100076d9, 0x9a },
- { 0x100076da, 0xc7 },
- { 0x100076db, 0x02 },
- { 0x100076dc, 0x03 },
- { 0x100076dd, 0x47 },
- { 0x100076de, 0x87 },
- { 0x100076df, 0x01 },
- { 0x100076e0, 0x13 },
- { 0x100076e1, 0x77 },
- { 0x100076e2, 0xf7 },
- { 0x100076e3, 0x0f },
- { 0x100076e4, 0x63 },
- { 0x100076e5, 0x14 },
- { 0x100076e6, 0xf7 },
- { 0x100076e7, 0x02 },
- { 0x100076e8, 0x37 },
- { 0x100076e9, 0xd7 },
- { 0x100076ea, 0x00 },
- { 0x100076eb, 0x00 },
- { 0x100076ec, 0x83 },
- { 0x100076ed, 0x47 },
- { 0x100076ee, 0x37 },
- { 0x100076ef, 0x54 },
- { 0x100076f0, 0x93 },
- { 0x100076f1, 0xf7 },
- { 0x100076f2, 0xf7 },
- { 0x100076f3, 0x0f },
- { 0x100076f4, 0x93 },
- { 0x100076f5, 0xe7 },
- { 0x100076f6, 0x07 },
- { 0x100076f7, 0x02 },
- { 0x100076f8, 0xa3 },
- { 0x100076f9, 0x01 },
- { 0x100076fa, 0xf7 },
- { 0x100076fb, 0x54 },
- { 0x100076fc, 0x83 },
- { 0x100076fd, 0x47 },
- { 0x100076fe, 0x37 },
- { 0x100076ff, 0x54 },
- { 0x10007700, 0x93 },
- { 0x10007701, 0xf7 },
- { 0x10007702, 0xf7 },
- { 0x10007703, 0x0d },
- { 0x10007704, 0xa3 },
- { 0x10007705, 0x01 },
- { 0x10007706, 0xf7 },
- { 0x10007707, 0x54 },
- { 0x10007708, 0x23 },
- { 0x10007709, 0xa8 },
- { 0x1000770a, 0x01 },
- { 0x1000770b, 0x56 },
- { 0x1000770c, 0xb7 },
- { 0x1000770d, 0xd7 },
- { 0x1000770e, 0x00 },
- { 0x1000770f, 0x10 },
- { 0x10007710, 0x03 },
- { 0x10007711, 0xc7 },
- { 0x10007712, 0x07 },
- { 0x10007713, 0xd9 },
- { 0x10007714, 0x93 },
- { 0x10007715, 0x06 },
- { 0x10007716, 0x10 },
- { 0x10007717, 0x00 },
- { 0x10007718, 0x13 },
- { 0x10007719, 0x77 },
- { 0x1000771a, 0xf7 },
- { 0x1000771b, 0x0f },
- { 0x1000771c, 0x63 },
- { 0x1000771d, 0x1a },
- { 0x1000771e, 0xd7 },
- { 0x1000771f, 0x04 },
- { 0x10007720, 0x03 },
- { 0x10007721, 0xc7 },
- { 0x10007722, 0x27 },
- { 0x10007723, 0xd9 },
- { 0x10007724, 0x13 },
- { 0x10007725, 0x07 },
- { 0x10007726, 0x17 },
- { 0x10007727, 0x00 },
- { 0x10007728, 0x13 },
- { 0x10007729, 0x77 },
- { 0x1000772a, 0xf7 },
- { 0x1000772b, 0x0f },
- { 0x1000772c, 0x23 },
- { 0x1000772d, 0x89 },
- { 0x1000772e, 0xe7 },
- { 0x1000772f, 0xd8 },
- { 0x10007730, 0x83 },
- { 0x10007731, 0xc6 },
- { 0x10007732, 0x27 },
- { 0x10007733, 0xd9 },
- { 0x10007734, 0x03 },
- { 0x10007735, 0xc7 },
- { 0x10007736, 0x17 },
- { 0x10007737, 0xd9 },
- { 0x10007738, 0x93 },
- { 0x10007739, 0xf6 },
- { 0x1000773a, 0xf6 },
- { 0x1000773b, 0x0f },
- { 0x1000773c, 0x13 },
- { 0x1000773d, 0x77 },
- { 0x1000773e, 0xf7 },
- { 0x1000773f, 0x0f },
- { 0x10007740, 0x63 },
- { 0x10007741, 0xe8 },
- { 0x10007742, 0xe6 },
- { 0x10007743, 0x02 },
- { 0x10007744, 0xb7 },
- { 0x10007745, 0xd6 },
- { 0x10007746, 0x00 },
- { 0x10007747, 0x00 },
- { 0x10007748, 0x03 },
- { 0x10007749, 0xc7 },
- { 0x1000774a, 0xa6 },
- { 0x1000774b, 0xe1 },
- { 0x1000774c, 0x13 },
- { 0x1000774d, 0x67 },
- { 0x1000774e, 0x07 },
- { 0x1000774f, 0xf8 },
- { 0x10007750, 0x13 },
- { 0x10007751, 0x77 },
- { 0x10007752, 0xf7 },
- { 0x10007753, 0x0f },
- { 0x10007754, 0x23 },
- { 0x10007755, 0x8d },
- { 0x10007756, 0xe6 },
- { 0x10007757, 0xe0 },
- { 0x10007758, 0x03 },
- { 0x10007759, 0xc7 },
- { 0x1000775a, 0x37 },
- { 0x1000775b, 0xd9 },
- { 0x1000775c, 0x13 },
- { 0x1000775d, 0x07 },
- { 0x1000775e, 0x17 },
- { 0x1000775f, 0x00 },
- { 0x10007760, 0x13 },
- { 0x10007761, 0x77 },
- { 0x10007762, 0xf7 },
- { 0x10007763, 0x0f },
- { 0x10007764, 0xa3 },
- { 0x10007765, 0x89 },
- { 0x10007766, 0xe7 },
- { 0x10007767, 0xd8 },
- { 0x10007768, 0x13 },
- { 0x10007769, 0x07 },
- { 0x1000776a, 0x20 },
- { 0x1000776b, 0x00 },
- { 0x1000776c, 0x23 },
- { 0x1000776d, 0x88 },
- { 0x1000776e, 0xe7 },
- { 0x1000776f, 0xd8 },
- { 0x10007770, 0x83 },
- { 0x10007771, 0x20 },
- { 0x10007772, 0xc1 },
- { 0x10007773, 0x00 },
- { 0x10007774, 0x03 },
- { 0x10007775, 0x24 },
- { 0x10007776, 0x81 },
- { 0x10007777, 0x00 },
- { 0x10007778, 0x13 },
- { 0x10007779, 0x01 },
- { 0x1000777a, 0x01 },
- { 0x1000777b, 0x01 },
- { 0x1000777c, 0x67 },
- { 0x1000777d, 0x80 },
- { 0x1000777e, 0x00 },
- { 0x1000777f, 0x00 },
- { 0x10007780, 0x03 },
- { 0x10007781, 0xc7 },
- { 0x10007782, 0xa1 },
- { 0x10007783, 0x40 },
- { 0x10007784, 0x93 },
- { 0x10007785, 0x06 },
- { 0x10007786, 0x10 },
- { 0x10007787, 0x00 },
- { 0x10007788, 0x63 },
- { 0x10007789, 0x16 },
- { 0x1000778a, 0xd7 },
- { 0x1000778b, 0x00 },
- { 0x1000778c, 0xb7 },
- { 0x1000778d, 0xd6 },
- { 0x1000778e, 0x00 },
- { 0x1000778f, 0x10 },
- { 0x10007790, 0xa3 },
- { 0x10007791, 0x8a },
- { 0x10007792, 0xe6 },
- { 0x10007793, 0xd8 },
- { 0x10007794, 0x83 },
- { 0x10007795, 0xc7 },
- { 0x10007796, 0xa1 },
- { 0x10007797, 0x40 },
- { 0x10007798, 0x63 },
- { 0x10007799, 0x9c },
- { 0x1000779a, 0x07 },
- { 0x1000779b, 0x06 },
- { 0x1000779c, 0x13 },
- { 0x1000779d, 0x01 },
- { 0x1000779e, 0x01 },
- { 0x1000779f, 0xff },
- { 0x100077a0, 0x23 },
- { 0x100077a1, 0x22 },
- { 0x100077a2, 0x91 },
- { 0x100077a3, 0x00 },
- { 0x100077a4, 0x23 },
- { 0x100077a5, 0x26 },
- { 0x100077a6, 0x11 },
- { 0x100077a7, 0x00 },
- { 0x100077a8, 0x23 },
- { 0x100077a9, 0x24 },
- { 0x100077aa, 0x81 },
- { 0x100077ab, 0x00 },
- { 0x100077ac, 0xb7 },
- { 0x100077ad, 0xc4 },
- { 0x100077ae, 0x00 },
- { 0x100077af, 0x00 },
- { 0x100077b0, 0x83 },
- { 0x100077b1, 0xc7 },
- { 0x100077b2, 0x04 },
- { 0x100077b3, 0x56 },
- { 0x100077b4, 0x13 },
- { 0x100077b5, 0x07 },
- { 0x100077b6, 0x80 },
- { 0x100077b7, 0x01 },
- { 0x100077b8, 0x93 },
- { 0x100077b9, 0xf7 },
- { 0x100077ba, 0xf7 },
- { 0x100077bb, 0x0f },
- { 0x100077bc, 0x63 },
- { 0x100077bd, 0x70 },
- { 0x100077be, 0xf7 },
- { 0x100077bf, 0x04 },
- { 0x100077c0, 0x37 },
- { 0x100077c1, 0xd4 },
- { 0x100077c2, 0x00 },
- { 0x100077c3, 0x10 },
- { 0x100077c4, 0x83 },
- { 0x100077c5, 0x47 },
- { 0x100077c6, 0x54 },
- { 0x100077c7, 0xd9 },
- { 0x100077c8, 0x93 },
- { 0x100077c9, 0xf7 },
- { 0x100077ca, 0xf7 },
- { 0x100077cb, 0x0f },
- { 0x100077cc, 0x63 },
- { 0x100077cd, 0x88 },
- { 0x100077ce, 0x07 },
- { 0x100077cf, 0x02 },
- { 0x100077d0, 0x93 },
- { 0x100077d1, 0x07 },
- { 0x100077d2, 0x10 },
- { 0x100077d3, 0x00 },
- { 0x100077d4, 0x23 },
- { 0x100077d5, 0x82 },
- { 0x100077d6, 0xf4 },
- { 0x100077d7, 0x58 },
- { 0x100077d8, 0x03 },
- { 0x100077d9, 0x45 },
- { 0x100077da, 0x64 },
- { 0x100077db, 0xd9 },
- { 0x100077dc, 0xb7 },
- { 0x100077dd, 0x15 },
- { 0x100077de, 0x00 },
- { 0x100077df, 0x00 },
- { 0x100077e0, 0x93 },
- { 0x100077e1, 0x85 },
- { 0x100077e2, 0x85 },
- { 0x100077e3, 0x38 },
- { 0x100077e4, 0x13 },
- { 0x100077e5, 0x75 },
- { 0x100077e6, 0xf5 },
- { 0x100077e7, 0x0f },
- { 0x100077e8, 0xef },
- { 0x100077e9, 0xe0 },
- { 0x100077ea, 0x9f },
- { 0x100077eb, 0xd0 },
- { 0x100077ec, 0x93 },
- { 0x100077ed, 0x55 },
- { 0x100077ee, 0xf5 },
- { 0x100077ef, 0x41 },
- { 0x100077f0, 0xef },
- { 0x100077f1, 0xe0 },
- { 0x100077f2, 0x8f },
- { 0x100077f3, 0xa3 },
- { 0x100077f4, 0x23 },
- { 0x100077f5, 0x82 },
- { 0x100077f6, 0x04 },
- { 0x100077f7, 0x58 },
- { 0x100077f8, 0xa3 },
- { 0x100077f9, 0x0a },
- { 0x100077fa, 0x04 },
- { 0x100077fb, 0xd8 },
- { 0x100077fc, 0x83 },
- { 0x100077fd, 0x20 },
- { 0x100077fe, 0xc1 },
- { 0x100077ff, 0x00 },
- { 0x10007800, 0x03 },
- { 0x10007801, 0x24 },
- { 0x10007802, 0x81 },
- { 0x10007803, 0x00 },
- { 0x10007804, 0x83 },
- { 0x10007805, 0x24 },
- { 0x10007806, 0x41 },
- { 0x10007807, 0x00 },
- { 0x10007808, 0x13 },
- { 0x10007809, 0x01 },
- { 0x1000780a, 0x01 },
- { 0x1000780b, 0x01 },
- { 0x1000780c, 0x67 },
- { 0x1000780d, 0x80 },
- { 0x1000780e, 0x00 },
- { 0x1000780f, 0x00 },
- { 0x10007810, 0x67 },
- { 0x10007811, 0x80 },
- { 0x10007812, 0x00 },
- { 0x10007813, 0x00 },
- { 0x10007814, 0x13 },
- { 0x10007815, 0x01 },
- { 0x10007816, 0x01 },
- { 0x10007817, 0xff },
- { 0x10007818, 0x23 },
- { 0x10007819, 0x26 },
- { 0x1000781a, 0x11 },
- { 0x1000781b, 0x00 },
- { 0x1000781c, 0xef },
- { 0x1000781d, 0xd0 },
- { 0x1000781e, 0x8f },
- { 0x1000781f, 0x86 },
- { 0x10007820, 0x83 },
- { 0x10007821, 0xc7 },
- { 0x10007822, 0x11 },
- { 0x10007823, 0x42 },
- { 0x10007824, 0x63 },
- { 0x10007825, 0x86 },
- { 0x10007826, 0x07 },
- { 0x10007827, 0x00 },
- { 0x10007828, 0x03 },
- { 0x10007829, 0xc7 },
- { 0x1000782a, 0x01 },
- { 0x1000782b, 0x42 },
- { 0x1000782c, 0x63 },
- { 0x1000782d, 0x10 },
- { 0x1000782e, 0x07 },
- { 0x1000782f, 0x02 },
- { 0x10007830, 0x83 },
- { 0x10007831, 0xc6 },
- { 0x10007832, 0x21 },
- { 0x10007833, 0x41 },
- { 0x10007834, 0x13 },
- { 0x10007835, 0x07 },
- { 0x10007836, 0xf0 },
- { 0x10007837, 0x01 },
- { 0x10007838, 0x13 },
- { 0x10007839, 0x05 },
- { 0x1000783a, 0xf0 },
- { 0x1000783b, 0x01 },
- { 0x1000783c, 0x63 },
- { 0x1000783d, 0x98 },
- { 0x1000783e, 0xe6 },
- { 0x1000783f, 0x02 },
- { 0x10007840, 0x63 },
- { 0x10007841, 0x8a },
- { 0x10007842, 0x07 },
- { 0x10007843, 0x02 },
- { 0x10007844, 0x83 },
- { 0x10007845, 0xc7 },
- { 0x10007846, 0x01 },
- { 0x10007847, 0x42 },
- { 0x10007848, 0x63 },
- { 0x10007849, 0x86 },
- { 0x1000784a, 0x07 },
- { 0x1000784b, 0x02 },
- { 0x1000784c, 0x83 },
- { 0x1000784d, 0xc7 },
- { 0x1000784e, 0x31 },
- { 0x1000784f, 0x42 },
- { 0x10007850, 0x63 },
- { 0x10007851, 0x86 },
- { 0x10007852, 0x07 },
- { 0x10007853, 0x00 },
- { 0x10007854, 0x83 },
- { 0x10007855, 0xc7 },
- { 0x10007856, 0x21 },
- { 0x10007857, 0x42 },
- { 0x10007858, 0x63 },
- { 0x10007859, 0x9e },
- { 0x1000785a, 0x07 },
- { 0x1000785b, 0x00 },
- { 0x1000785c, 0x03 },
- { 0x1000785d, 0xc7 },
- { 0x1000785e, 0x21 },
- { 0x1000785f, 0x41 },
- { 0x10007860, 0x93 },
- { 0x10007861, 0x07 },
- { 0x10007862, 0xb0 },
- { 0x10007863, 0x01 },
- { 0x10007864, 0x63 },
- { 0x10007865, 0x08 },
- { 0x10007866, 0xf7 },
- { 0x10007867, 0x00 },
- { 0x10007868, 0x13 },
- { 0x10007869, 0x05 },
- { 0x1000786a, 0xb0 },
- { 0x1000786b, 0x01 },
- { 0x1000786c, 0xef },
- { 0x1000786d, 0xd0 },
- { 0x1000786e, 0x0f },
- { 0x1000786f, 0xcf },
- { 0x10007870, 0xef },
- { 0x10007871, 0xd0 },
- { 0x10007872, 0x8f },
- { 0x10007873, 0xa4 },
- { 0x10007874, 0x93 },
- { 0x10007875, 0x06 },
- { 0x10007876, 0x10 },
- { 0x10007877, 0x00 },
- { 0x10007878, 0xa3 },
- { 0x10007879, 0x89 },
- { 0x1000787a, 0xd1 },
- { 0x1000787b, 0x40 },
- { 0x1000787c, 0x37 },
- { 0x1000787d, 0xd7 },
- { 0x1000787e, 0x00 },
- { 0x1000787f, 0x10 },
- { 0x10007880, 0x83 },
- { 0x10007881, 0x47 },
- { 0x10007882, 0x07 },
- { 0x10007883, 0xd9 },
- { 0x10007884, 0x93 },
- { 0x10007885, 0xf7 },
- { 0x10007886, 0xf7 },
- { 0x10007887, 0x0f },
- { 0x10007888, 0x63 },
- { 0x10007889, 0x90 },
- { 0x1000788a, 0x07 },
- { 0x1000788b, 0x02 },
- { 0x1000788c, 0x37 },
- { 0x1000788d, 0xc6 },
- { 0x1000788e, 0x00 },
- { 0x1000788f, 0x00 },
- { 0x10007890, 0x83 },
- { 0x10007891, 0x47 },
- { 0x10007892, 0x26 },
- { 0x10007893, 0x04 },
- { 0x10007894, 0x93 },
- { 0x10007895, 0xe7 },
- { 0x10007896, 0x07 },
- { 0x10007897, 0xf8 },
- { 0x10007898, 0x93 },
- { 0x10007899, 0xf7 },
- { 0x1000789a, 0xf7 },
- { 0x1000789b, 0x0f },
- { 0x1000789c, 0x23 },
- { 0x1000789d, 0x01 },
- { 0x1000789e, 0xf6 },
- { 0x1000789f, 0x04 },
- { 0x100078a0, 0x23 },
- { 0x100078a1, 0x08 },
- { 0x100078a2, 0xd7 },
- { 0x100078a3, 0xd8 },
- { 0x100078a4, 0x23 },
- { 0x100078a5, 0x09 },
- { 0x100078a6, 0x07 },
- { 0x100078a7, 0xd8 },
- { 0x100078a8, 0x83 },
- { 0x100078a9, 0x20 },
- { 0x100078aa, 0xc1 },
- { 0x100078ab, 0x00 },
- { 0x100078ac, 0x13 },
- { 0x100078ad, 0x01 },
- { 0x100078ae, 0x01 },
- { 0x100078af, 0x01 },
- { 0x100078b0, 0x67 },
- { 0x100078b1, 0x80 },
- { 0x100078b2, 0x00 },
- { 0x100078b3, 0x00 },
- { 0x3fc2bfc7, 0x00 },
- { 0x3fc2bfc6, 0x00 },
- { 0x3fc2bfc5, 0x00 },
- { 0x3fc2bfc4, 0x01 },
- { 0x0000d486, 0x43 },
- { 0x1000db00, 0x02 },
- { 0x1000db01, 0x00 },
- { 0x1000db02, 0x11 },
- { 0x1000db03, 0x00 },
- { 0x1000db04, 0x00 },
- { 0x1000db05, 0x82 },
- { 0x1000db06, 0x04 },
- { 0x1000db07, 0xf1 },
- { 0x1000db08, 0x00 },
- { 0x1000db09, 0x00 },
- { 0x1000db0a, 0x40 },
- { 0x0000d540, 0x01 },
-};
-
static const struct reg_default rt1320_reg_defaults[] = {
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x0b },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE27, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0), 0x00 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x0b },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), 0x03 },
};
static const struct reg_default rt1320_mbq_defaults[] = {
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
};
@@ -3514,6 +328,17 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg)
case 0x1000f021:
case 0x3fe2e000 ... 0x3fe2e003:
case 0x3fc2ab80 ... 0x3fc2abd4:
+ /* 0x40801508/0x40801809/0x4080180a/0x40801909/0x4080190a */
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_02):
+ /* 0x40880900/0x40880980 */
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ /* 0x40881500 */
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0):
/* 0x41000189/0x4100018a */
case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01):
case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02):
@@ -3596,6 +421,7 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg)
case 0x3fc2bf80 ... 0x3fc2bf83:
case 0x3fc2bfc0 ... 0x3fc2bfc7:
case 0x3fe2e000 ... 0x3fe2e003:
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0):
case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0):
case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
@@ -3609,6 +435,10 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg)
static bool rt1320_mbq_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_02):
case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01):
case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02):
return true;
@@ -3664,7 +494,7 @@ static int rt1320_read_prop(struct sdw_slave *slave)
prop->lane_control_support = true;
/* first we need to allocate memory for set bits in port lists */
- prop->source_ports = BIT(4);
+ prop->source_ports = BIT(4) | BIT(8) | BIT(10);
prop->sink_ports = BIT(1);
nval = hweight32(prop->source_ports);
@@ -3708,7 +538,8 @@ static int rt1320_read_prop(struct sdw_slave *slave)
return 0;
}
-static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned char ps)
+static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned char func,
+ unsigned char entity, unsigned char ps)
{
unsigned int delay = 1000, val;
@@ -3717,8 +548,7 @@ static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned
/* waiting for Actual PDE becomes to PS0/PS3 */
while (delay) {
regmap_read(rt1320->regmap,
- SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
- RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), &val);
+ SDW_SDCA_CTL(func, entity, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), &val);
if (val == ps)
break;
@@ -3733,17 +563,88 @@ static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned
return 0;
}
+/*
+ * The 'patch code' is written to the patch code area.
+ * The patch code area is used for SDCA register expansion flexibility.
+ */
+static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320)
+{
+ struct sdw_slave *slave = rt1320->sdw_slave;
+ const struct firmware *patch;
+ const char *filename;
+ unsigned int addr, val;
+ const unsigned char *ptr;
+ int ret, i;
+
+ if (rt1320->version_id <= RT1320_VB)
+ filename = RT1320_VAB_MCU_PATCH;
+ else
+ filename = RT1320_VC_MCU_PATCH;
+
+ /* load the patch code here */
+ ret = request_firmware(&patch, filename, &slave->dev);
+ if (ret) {
+ dev_err(&slave->dev, "%s: Failed to load %s firmware", __func__, filename);
+ regmap_write(rt1320->regmap, 0xc598, 0x00);
+ regmap_write(rt1320->regmap, 0x10007000, 0x67);
+ regmap_write(rt1320->regmap, 0x10007001, 0x80);
+ regmap_write(rt1320->regmap, 0x10007002, 0x00);
+ regmap_write(rt1320->regmap, 0x10007003, 0x00);
+ } else {
+ ptr = (const unsigned char *)patch->data;
+ if ((patch->size % 8) == 0) {
+ for (i = 0; i < patch->size; i += 8) {
+ addr = (ptr[i] & 0xff) | (ptr[i + 1] & 0xff) << 8 |
+ (ptr[i + 2] & 0xff) << 16 | (ptr[i + 3] & 0xff) << 24;
+ val = (ptr[i + 4] & 0xff) | (ptr[i + 5] & 0xff) << 8 |
+ (ptr[i + 6] & 0xff) << 16 | (ptr[i + 7] & 0xff) << 24;
+
+ if (addr > 0x10007fff || addr < 0x10007000) {
+ dev_err(&slave->dev, "%s: the address 0x%x is wrong", __func__, addr);
+ goto _exit_;
+ }
+ if (val > 0xff) {
+ dev_err(&slave->dev, "%s: the value 0x%x is wrong", __func__, val);
+ goto _exit_;
+ }
+ regmap_write(rt1320->regmap, addr, val);
+ }
+ }
+_exit_:
+ release_firmware(patch);
+ }
+}
+
+static void rt1320_vab_preset(struct rt1320_sdw_priv *rt1320)
+{
+ unsigned int i, reg, val, delay;
+
+ for (i = 0; i < ARRAY_SIZE(rt1320_blind_write); i++) {
+ reg = rt1320_blind_write[i].reg;
+ val = rt1320_blind_write[i].def;
+ delay = rt1320_blind_write[i].delay_us;
+
+ if (reg == 0x3fc2bfc7)
+ rt1320_load_mcu_patch(rt1320);
+
+ regmap_write(rt1320->regmap, reg, val);
+ if (delay)
+ usleep_range(delay, delay + 1000);
+ }
+}
+
static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320)
{
struct sdw_slave *slave = rt1320->sdw_slave;
unsigned int i, reg, val, delay, retry, tmp;
- regmap_multi_reg_write(rt1320->regmap, rt1320_vc_blind_write, ARRAY_SIZE(rt1320_vc_blind_write));
+ for (i = 0; i < ARRAY_SIZE(rt1320_vc_blind_write); i++) {
+ reg = rt1320_vc_blind_write[i].reg;
+ val = rt1320_vc_blind_write[i].def;
+ delay = rt1320_vc_blind_write[i].delay_us;
- for (i = 0; i < ARRAY_SIZE(rt1320_vc_patch_code_write); i++) {
- reg = rt1320_vc_patch_code_write[i].reg;
- val = rt1320_vc_patch_code_write[i].def;
- delay = rt1320_vc_patch_code_write[i].delay_us;
+ if (reg == 0x3fc2bf83)
+ rt1320_load_mcu_patch(rt1320);
if ((reg == SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0)) &&
(val == 0x00)) {
@@ -3762,6 +663,9 @@ static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320)
regmap_write(rt1320->regmap, reg, val);
if (delay)
usleep_range(delay, delay + 1000);
+
+ if (reg == SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0))
+ rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, val);
}
}
@@ -3799,13 +703,10 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave)
/* initialization write */
if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION)) {
- if (rt1320->version_id < RT1320_VC) {
- regmap_multi_reg_write(rt1320->regmap, rt1320_blind_write, ARRAY_SIZE(rt1320_blind_write));
- regmap_multi_reg_write(rt1320->regmap, rt1320_patch_code_write,
- ARRAY_SIZE(rt1320_patch_code_write));
- } else if (rt1320->version_id == RT1320_VC) {
+ if (rt1320->version_id < RT1320_VC)
+ rt1320_vab_preset(rt1320);
+ else
rt1320_vc_preset(rt1320);
- }
regmap_write(rt1320->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0),
@@ -3870,6 +771,34 @@ static int rt1320_update_status(struct sdw_slave *slave,
return rt1320_io_init(&slave->dev, slave);
}
+static int rt1320_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 rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11,
+ RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ rt1320_pde_transition_delay(rt1320, FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11,
+ RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ rt1320_pde_transition_delay(rt1320, FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, ps3);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int rt1320_pde23_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -3883,13 +812,13 @@ static int rt1320_pde23_event(struct snd_soc_dapm_widget *w,
regmap_write(rt1320->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
- rt1320_pde_transition_delay(rt1320, ps0);
+ rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, ps0);
break;
case SND_SOC_DAPM_PRE_PMD:
regmap_write(rt1320->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
- rt1320_pde_transition_delay(rt1320, ps3);
+ rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, ps3);
break;
default:
break;
@@ -3908,6 +837,13 @@ static int rt1320_set_gain_put(struct snd_kcontrol *kcontrol,
unsigned int gain_l_val, gain_r_val;
unsigned int lvalue, rvalue;
const unsigned int interval_offset = 0xc0;
+ unsigned int changed = 0, reg_base;
+ struct rt_sdca_dmic_kctrl_priv *p;
+ unsigned int regvalue[4], gain_val[4], i;
+ int err;
+
+ if (strstr(ucontrol->id.name, "FU Capture Volume"))
+ goto _dmic_vol_;
regmap_read(rt1320->mbq_regmap, mc->reg, &lvalue);
regmap_read(rt1320->mbq_regmap, mc->rreg, &rvalue);
@@ -3933,7 +869,48 @@ static int rt1320_set_gain_put(struct snd_kcontrol *kcontrol,
regmap_write(rt1320->mbq_regmap, mc->reg, gain_l_val);
/* Rch */
regmap_write(rt1320->mbq_regmap, mc->rreg, gain_r_val);
+ goto _done_;
+
+_dmic_vol_:
+ p = (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ if (i < 2) {
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ regmap_read(rt1320->mbq_regmap, reg_base + i, &regvalue[i]);
+ } else {
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ regmap_read(rt1320->mbq_regmap, reg_base + i - 2, &regvalue[i]);
+ }
+
+ gain_val[i] = ucontrol->value.integer.value[i];
+ if (gain_val[i] > p->max)
+ gain_val[i] = p->max;
+
+ gain_val[i] = 0x1e00 - ((p->max - gain_val[i]) * interval_offset);
+ gain_val[i] &= 0xffff;
+ if (regvalue[i] != gain_val[i])
+ changed = 1;
+ }
+
+ if (!changed)
+ return 0;
+ for (i = 0; i < p->count; i++) {
+ if (i < 2) {
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ err = regmap_write(rt1320->mbq_regmap, reg_base + i, gain_val[i]);
+ } else {
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ err = regmap_write(rt1320->mbq_regmap, reg_base + i - 2, gain_val[i]);
+ }
+
+ if (err < 0)
+ dev_err(&rt1320->sdw_slave->dev, "0x%08x can't be set\n", reg_base + i);
+ }
+
+_done_:
return 1;
}
@@ -3946,6 +923,11 @@ static int rt1320_set_gain_get(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0;
const unsigned int interval_offset = 0xc0;
+ unsigned int reg_base, regvalue, ctl, i;
+ struct rt_sdca_dmic_kctrl_priv *p;
+
+ if (strstr(ucontrol->id.name, "FU Capture Volume"))
+ goto _dmic_vol_;
regmap_read(rt1320->mbq_regmap, mc->reg, &read_l);
regmap_read(rt1320->mbq_regmap, mc->rreg, &read_r);
@@ -3959,6 +941,121 @@ static int rt1320_set_gain_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = ctl_l;
ucontrol->value.integer.value[1] = ctl_r;
+ goto _done_;
+
+_dmic_vol_:
+ p = (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ if (i < 2) {
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ regmap_read(rt1320->mbq_regmap, reg_base + i, &regvalue);
+ } else {
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ regmap_read(rt1320->mbq_regmap, reg_base + i - 2, &regvalue);
+ }
+
+ ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset);
+ ucontrol->value.integer.value[i] = ctl;
+ }
+_done_:
+ return 0;
+}
+
+static int rt1320_set_fu_capture_ctl(struct rt1320_sdw_priv *rt1320)
+{
+ int err, i;
+ unsigned int ch_mute;
+
+ for (i = 0; i < ARRAY_SIZE(rt1320->fu_mixer_mute); i++) {
+ ch_mute = (rt1320->fu_dapm_mute || rt1320->fu_mixer_mute[i]) ? 0x01 : 0x00;
+
+ if (i < 2)
+ err = regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113,
+ RT1320_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute);
+ else
+ err = regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14,
+ RT1320_SDCA_CTL_FU_MUTE, CH_01) + i - 2, ch_mute);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int rt1320_dmic_fu_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ struct rt_sdca_dmic_kctrl_priv *p =
+ (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ unsigned int i;
+
+ for (i = 0; i < p->count; i++)
+ ucontrol->value.integer.value[i] = !rt1320->fu_mixer_mute[i];
+
+ return 0;
+}
+
+static int rt1320_dmic_fu_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ struct rt_sdca_dmic_kctrl_priv *p =
+ (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ int err, changed = 0, i;
+
+ for (i = 0; i < p->count; i++) {
+ if (rt1320->fu_mixer_mute[i] != !ucontrol->value.integer.value[i])
+ changed = 1;
+ rt1320->fu_mixer_mute[i] = !ucontrol->value.integer.value[i];
+ }
+
+ err = rt1320_set_fu_capture_ctl(rt1320);
+ if (err < 0)
+ return err;
+
+ return changed;
+}
+
+static int rt1320_dmic_fu_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct rt_sdca_dmic_kctrl_priv *p =
+ (struct rt_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 rt1320_dmic_fu_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt1320->fu_dapm_mute = false;
+ rt1320_set_fu_capture_ctl(rt1320);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt1320->fu_dapm_mute = true;
+ rt1320_set_fu_capture_ctl(rt1320);
+ break;
+ }
return 0;
}
@@ -3979,6 +1076,7 @@ static SOC_ENUM_SINGLE_DECL(rt1320_rx_data_ch_enum,
rt1320_rx_data_ch_select);
static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
static const struct snd_kcontrol_new rt1320_snd_controls[] = {
SOC_DOUBLE_R_EXT_TLV("FU21 Playback Volume",
@@ -3986,6 +1084,13 @@ static const struct snd_kcontrol_new rt1320_snd_controls[] = {
SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02),
0, 0x57, 0, rt1320_set_gain_get, rt1320_set_gain_put, out_vol_tlv),
SOC_ENUM("RX Channel Select", rt1320_rx_data_ch_enum),
+
+ RT_SDCA_FU_CTRL("FU Capture Switch",
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01),
+ 1, 1, 4, rt1320_dmic_fu_info, rt1320_dmic_fu_capture_get, rt1320_dmic_fu_capture_put),
+ RT_SDCA_EXT_TLV("FU Capture Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01),
+ rt1320_set_gain_get, rt1320_set_gain_put, 4, 0x3f, in_vol_tlv, rt1320_dmic_fu_info),
};
static const struct snd_kcontrol_new rt1320_spk_l_dac =
@@ -4001,12 +1106,19 @@ static const struct snd_soc_dapm_widget rt1320_dapm_widgets[] = {
/* Audio Interface */
SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP8-10TX", "DP8-10 Capture", 0, SND_SOC_NOPM, 0, 0),
/* Digital Interface */
SND_SOC_DAPM_PGA("FU21", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0,
rt1320_pde23_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0,
+ rt1320_pde11_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC("FU 113", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("FU 14", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_PGA_E("FU", SND_SOC_NOPM, 0, 0, NULL, 0,
+ rt1320_dmic_fu_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
/* Output */
SND_SOC_DAPM_SWITCH("OT23 L", SND_SOC_NOPM, 0, 0, &rt1320_spk_l_dac),
@@ -4017,6 +1129,8 @@ static const struct snd_soc_dapm_widget rt1320_dapm_widgets[] = {
/* Input */
SND_SOC_DAPM_PGA("AEC Data", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_SIGGEN("AEC Gen"),
+ SND_SOC_DAPM_INPUT("DMIC1"),
+ SND_SOC_DAPM_INPUT("DMIC2"),
};
static const struct snd_soc_dapm_route rt1320_dapm_routes[] = {
@@ -4029,6 +1143,13 @@ static const struct snd_soc_dapm_route rt1320_dapm_routes[] = {
{ "AEC Data", NULL, "AEC Gen" },
{ "DP4TX", NULL, "AEC Data" },
+
+ {"DP8-10TX", NULL, "FU"},
+ {"FU", NULL, "PDE 11"},
+ {"FU", NULL, "FU 113"},
+ {"FU", NULL, "FU 14"},
+ {"FU 113", NULL, "DMIC1"},
+ {"FU 14", NULL, "DMIC2"},
};
static int rt1320_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
@@ -4052,6 +1173,7 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream,
snd_soc_component_get_drvdata(component);
struct sdw_stream_config stream_config;
struct sdw_port_config port_config;
+ struct sdw_port_config dmic_port_config[2];
struct sdw_stream_runtime *sdw_stream;
int retval;
unsigned int sampling_rate;
@@ -4076,12 +1198,23 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream,
} else {
if (dai->id == RT1320_AIF1)
port_config.num = 4;
- else
+ else if (dai->id == RT1320_AIF2) {
+ dmic_port_config[0].ch_mask = BIT(0) | BIT(1);
+ dmic_port_config[0].num = 8;
+ dmic_port_config[1].ch_mask = BIT(0) | BIT(1);
+ dmic_port_config[1].num = 10;
+ } else
return -EINVAL;
}
- retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config,
+ if (dai->id == RT1320_AIF1)
+ retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config,
&port_config, 1, sdw_stream);
+ else if (dai->id == RT1320_AIF2)
+ retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config,
+ dmic_port_config, 2, sdw_stream);
+ else
+ return -EINVAL;
if (retval) {
dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
return retval;
@@ -4114,9 +1247,18 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream,
}
/* set sampling frequency */
- regmap_write(rt1320->regmap,
- SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
- sampling_rate);
+ if (dai->id == RT1320_AIF1)
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+ else {
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+ }
return 0;
}
@@ -4207,6 +1349,19 @@ static struct snd_soc_dai_driver rt1320_sdw_dai[] = {
},
.ops = &rt1320_aif_dai_ops,
},
+ /* DMIC: DP8 2ch + DP10 2ch */
+ {
+ .name = "rt1320-aif2",
+ .id = RT1320_AIF2,
+ .capture = {
+ .stream_name = "DP8-10 Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = RT1320_STEREO_RATES,
+ .formats = RT1320_FORMATS,
+ },
+ .ops = &rt1320_aif_dai_ops,
+ },
};
static int rt1320_sdw_init(struct device *dev, struct regmap *regmap,
@@ -4234,6 +1389,9 @@ static int rt1320_sdw_init(struct device *dev, struct regmap *regmap,
rt1320->hw_init = false;
rt1320->first_hw_init = false;
rt1320->version_id = -1;
+ rt1320->fu_dapm_mute = true;
+ rt1320->fu_mixer_mute[0] = rt1320->fu_mixer_mute[1] =
+ rt1320->fu_mixer_mute[2] = rt1320->fu_mixer_mute[3] = true;
ret = devm_snd_soc_register_component(dev,
&soc_component_sdw_rt1320,
diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h
index 1fbc1fcd71cf..23b321aee6a9 100644
--- a/sound/soc/codecs/rt1320-sdw.h
+++ b/sound/soc/codecs/rt1320-sdw.h
@@ -26,6 +26,7 @@
/* RT1320 SDCA Control - function number */
#define FUNC_NUM_AMP 0x04
+#define FUNC_NUM_MIC 0x02
/* RT1320 SDCA entity */
#define RT1320_SDCA_ENT0 0x00
@@ -69,6 +70,7 @@
enum {
RT1320_AIF1,
+ RT1320_AIF2,
};
/*
@@ -82,6 +84,8 @@ enum rt1320_version_id {
};
#define RT1320_VER_B_ID 0x07392238
+#define RT1320_VAB_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vab.bin"
+#define RT1320_VC_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vc.bin"
struct rt1320_sdw_priv {
struct snd_soc_component *component;
@@ -92,6 +96,8 @@ struct rt1320_sdw_priv {
bool hw_init;
bool first_hw_init;
int version_id;
+ bool fu_dapm_mute;
+ bool fu_mixer_mute[4];
};
#endif /* __RT1320_SDW_H__ */
diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c
index 90d5aaddbd5b..b584a3f854b8 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -507,3 +507,4 @@ module_sdw_driver(rt712_sdca_sdw_driver);
MODULE_DESCRIPTION("ASoC RT712 SDCA SDW driver");
MODULE_AUTHOR("Shuming Fan <[email protected]>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_SDCA");
diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c
index e210c574bb74..78dbf9eed494 100644
--- a/sound/soc/codecs/rt712-sdca.c
+++ b/sound/soc/codecs/rt712-sdca.c
@@ -18,6 +18,7 @@
#include <linux/pm_runtime.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/sdca.h>
#include <linux/soundwire/sdw_registers.h>
#include <linux/slab.h>
#include <sound/soc-dapm.h>
@@ -1652,6 +1653,17 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
if (ret < 0)
return ret;
+ /* only add the dmic component if a SMART_MIC function is exposed in ACPI */
+ if (sdca_device_quirk_match(slave, SDCA_QUIRKS_RT712_VB)) {
+ ret = devm_snd_soc_register_component(dev,
+ &soc_sdca_dev_rt712_dmic,
+ rt712_sdca_dmic_dai,
+ ARRAY_SIZE(rt712_sdca_dmic_dai));
+ if (ret < 0)
+ return ret;
+ rt712->dmic_function_found = true;
+ }
+
/* set autosuspend parameters */
pm_runtime_set_autosuspend_delay(dev, 3000);
pm_runtime_use_autosuspend(dev);
@@ -1799,7 +1811,6 @@ static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712)
int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
{
struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev);
- int ret = 0;
unsigned int val;
struct sdw_slave_prop *prop = &slave->prop;
@@ -1829,15 +1840,22 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
rt712->version_id = (val & 0x0f00) >> 8;
dev_dbg(&slave->dev, "%s hw_id=0x%x, version_id=0x%x\n", __func__, rt712->hw_id, rt712->version_id);
- if (rt712->version_id == RT712_VA)
+ if (rt712->version_id == RT712_VA) {
+ if (rt712->dmic_function_found) {
+ dev_err(&slave->dev, "%s RT712 VA detected but SMART_MIC function exposed in ACPI\n",
+ __func__);
+ goto suspend;
+ }
+
rt712_sdca_va_io_init(rt712);
- else {
- /* multilanes and DMIC are supported by rt712vb */
- ret = devm_snd_soc_register_component(dev,
- &soc_sdca_dev_rt712_dmic, rt712_sdca_dmic_dai, ARRAY_SIZE(rt712_sdca_dmic_dai));
- if (ret < 0)
- return ret;
+ } else {
+ if (!rt712->dmic_function_found) {
+ dev_err(&slave->dev, "%s RT712 VB detected but no SMART_MIC function exposed in ACPI\n",
+ __func__);
+ goto suspend;
+ }
+ /* multilanes and DMIC are supported by rt712vb */
prop->lane_control_support = true;
rt712_sdca_vb_io_init(rt712);
}
@@ -1862,10 +1880,12 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
/* Mark Slave initialization complete */
rt712->hw_init = true;
+ dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
+
+suspend:
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;
}
diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h
index 2169f2f726b9..a08491496d90 100644
--- a/sound/soc/codecs/rt712-sdca.h
+++ b/sound/soc/codecs/rt712-sdca.h
@@ -36,6 +36,7 @@ struct rt712_sdca_priv {
unsigned int scp_sdca_stat2;
unsigned int hw_id;
unsigned int version_id;
+ bool dmic_function_found;
bool fu0f_dapm_mute;
bool fu0f_mixer_l_mute;
bool fu0f_mixer_r_mute;
diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c
new file mode 100644
index 000000000000..c71453da088a
--- /dev/null
+++ b/sound/soc/codecs/rt721-sdca-sdw.c
@@ -0,0 +1,546 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt721-sdca-sdw.c -- rt721 SDCA ALSA SoC audio driver
+//
+// Copyright(c) 2024 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 "rt721-sdca.h"
+#include "rt721-sdca-sdw.h"
+#include "rt-sdw-common.h"
+
+static bool rt721_sdca_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f01 ... 0x2f0a:
+ case 0x2f35:
+ case 0x2f50:
+ case 0x2f51:
+ case 0x2f58 ... 0x2f5d:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XUV,
+ RT721_SDCA_CTL_XUV, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49,
+ RT721_SDCA_CTL_SELECTED_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49,
+ RT721_SDCA_CTL_DETECTED_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT721_SDCA_ENT_HID01,
+ RT721_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID,
+ RT721_SDCA_ENT_HID01, RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case RT721_BUF_ADDR_HID1 ... RT721_BUF_ADDR_HID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt721_sdca_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f01:
+ case 0x2f51:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49,
+ RT721_SDCA_CTL_DETECTED_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XUV,
+ RT721_SDCA_CTL_XUV, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT721_SDCA_ENT_HID01,
+ RT721_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID,
+ RT721_SDCA_ENT_HID01, RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case RT721_BUF_ADDR_HID1 ... RT721_BUF_ADDR_HID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt721_sdca_mbq_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x0900007:
+ case 0x0a00005:
+ case 0x0c00005:
+ case 0x0d00014:
+ case 0x0310100:
+ case 0x2000001:
+ case 0x2000002:
+ case 0x2000003:
+ case 0x2000013:
+ case 0x200003c:
+ case 0x2000046:
+ case 0x5810000:
+ case 0x5810036:
+ case 0x5810037:
+ case 0x5810038:
+ case 0x5810039:
+ case 0x5b10018:
+ case 0x5b10019:
+ case 0x5f00045:
+ case 0x5f00048:
+ case 0x6100000:
+ case 0x6100005:
+ case 0x6100006:
+ case 0x610000d:
+ case 0x6100010:
+ case 0x6100011:
+ case 0x6100013:
+ case 0x6100015:
+ case 0x6100017:
+ case 0x6100025:
+ case 0x6100029:
+ case 0x610002c ... 0x610002f:
+ case 0x6100053 ... 0x6100055:
+ case 0x6100057:
+ case 0x610005a:
+ case 0x610005b:
+ case 0x610006a:
+ case 0x610006d:
+ case 0x6100092:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME,
+ CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME,
+ CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME,
+ CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME,
+ CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44,
+ RT721_SDCA_CTL_FU_CH_GAIN, CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44,
+ RT721_SDCA_CTL_FU_CH_GAIN, CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_03):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_04):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_R):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt721_sdca_mbq_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x0310100:
+ case 0x0a00005:
+ case 0x0c00005:
+ case 0x0d00014:
+ case 0x2000000:
+ case 0x200000d:
+ case 0x2000019:
+ case 0x2000020:
+ case 0x2000030:
+ case 0x2000046:
+ case 0x2000067:
+ case 0x2000084:
+ case 0x2000086:
+ case 0x5810000:
+ case 0x5810036:
+ case 0x5810037:
+ case 0x5810038:
+ case 0x5810039:
+ case 0x5b10018:
+ case 0x5b10019:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rt721_sdca_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt721_sdca_readable_register,
+ .volatile_reg = rt721_sdca_volatile_register,
+ .max_register = 0x44ffffff,
+ .reg_defaults = rt721_sdca_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt721_sdca_reg_defaults),
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static const struct regmap_config rt721_sdca_mbq_regmap = {
+ .name = "sdw-mbq",
+ .reg_bits = 32,
+ .val_bits = 16,
+ .readable_reg = rt721_sdca_mbq_readable_register,
+ .volatile_reg = rt721_sdca_mbq_volatile_register,
+ .max_register = 0x41000312,
+ .reg_defaults = rt721_sdca_mbq_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt721_sdca_mbq_defaults),
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt721_sdca_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt721_sdca_priv *rt721 = dev_get_drvdata(&slave->dev);
+
+ if (status == SDW_SLAVE_UNATTACHED)
+ rt721->hw_init = false;
+
+ if (status == SDW_SLAVE_ATTACHED) {
+ if (rt721->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 rt721_sdca_jack_init set.
+ */
+ sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0);
+ sdw_write_no_pm(rt721->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 (rt721->hw_init || status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt721_sdca_io_init(&slave->dev, slave);
+}
+
+static int rt721_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;
+
+ sdw_slave_read_prop(slave);
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+
+ prop->paging_support = true;
+
+ /*
+ * 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 = 1380;
+
+ /* wake-up event */
+ prop->wake_capable = 1;
+
+ /* Three data lanes are supported by rt721-sdca codec */
+ prop->lane_control_support = true;
+
+ return 0;
+}
+
+static int rt721_sdca_interrupt_callback(struct sdw_slave *slave,
+ struct sdw_slave_intr_status *status)
+{
+ struct rt721_sdca_priv *rt721 = 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(&rt721->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 (rt721->scp_sdca_stat2)
+ scp_sdca_stat2 = rt721->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(&rt721->disable_irq_lock);
+
+ ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1);
+ if (ret < 0)
+ goto io_error;
+
+ rt721->scp_sdca_stat1 = ret;
+ ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2);
+ if (ret < 0)
+ goto io_error;
+
+ rt721->scp_sdca_stat2 = ret;
+ if (scp_sdca_stat2)
+ rt721->scp_sdca_stat2 |= scp_sdca_stat2;
+ do {
+ /* clear flag */
+ ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1);
+ if (ret < 0)
+ goto io_error;
+ if (ret & SDW_SCP_SDCA_INTMASK_SDCA_0) {
+ ret = sdw_update_no_pm(rt721->slave, SDW_SCP_SDCA_INT1,
+ SDW_SCP_SDCA_INT_SDCA_0, SDW_SCP_SDCA_INT_SDCA_0);
+ if (ret < 0)
+ goto io_error;
+ }
+ ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2);
+ if (ret < 0)
+ goto io_error;
+ if (ret & SDW_SCP_SDCA_INTMASK_SDCA_8) {
+ ret = sdw_write_no_pm(rt721->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(rt721->slave, SDW_DP0_INT);
+ if (ret < 0)
+ goto io_error;
+ sdca_cascade = ret & SDW_DP0_SDCA_CASCADE;
+
+ ret = sdw_read_no_pm(rt721->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(rt721->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__,
+ rt721->scp_sdca_stat1, rt721->scp_sdca_stat2);
+ ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1);
+ ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2);
+
+ if (status->sdca_cascade && !rt721->disable_irq)
+ mod_delayed_work(system_power_efficient_wq,
+ &rt721->jack_detect_work, msecs_to_jiffies(280));
+
+ mutex_unlock(&rt721->disable_irq_lock);
+
+ return 0;
+
+io_error:
+ mutex_unlock(&rt721->disable_irq_lock);
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+ return ret;
+}
+
+static const struct sdw_slave_ops rt721_sdca_slave_ops = {
+ .read_prop = rt721_sdca_read_prop,
+ .interrupt_callback = rt721_sdca_interrupt_callback,
+ .update_status = rt721_sdca_update_status,
+};
+
+static int rt721_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, &rt721_sdca_mbq_regmap);
+ if (IS_ERR(mbq_regmap))
+ return PTR_ERR(mbq_regmap);
+
+ regmap = devm_regmap_init_sdw(slave, &rt721_sdca_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt721_sdca_init(&slave->dev, regmap, mbq_regmap, slave);
+}
+
+static int rt721_sdca_sdw_remove(struct sdw_slave *slave)
+{
+ struct rt721_sdca_priv *rt721 = dev_get_drvdata(&slave->dev);
+
+ if (rt721->hw_init) {
+ cancel_delayed_work_sync(&rt721->jack_detect_work);
+ cancel_delayed_work_sync(&rt721->jack_btn_check_work);
+ }
+
+ if (rt721->first_hw_init)
+ pm_runtime_disable(&slave->dev);
+
+ mutex_destroy(&rt721->calibrate_mutex);
+ mutex_destroy(&rt721->disable_irq_lock);
+
+ return 0;
+}
+
+static const struct sdw_device_id rt721_sdca_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x721, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt721_sdca_id);
+
+static int __maybe_unused rt721_sdca_dev_suspend(struct device *dev)
+{
+ struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev);
+
+ if (!rt721->hw_init)
+ return 0;
+
+ cancel_delayed_work_sync(&rt721->jack_detect_work);
+ cancel_delayed_work_sync(&rt721->jack_btn_check_work);
+
+ regcache_cache_only(rt721->regmap, true);
+ regcache_cache_only(rt721->mbq_regmap, true);
+
+ return 0;
+}
+
+static int __maybe_unused rt721_sdca_dev_system_suspend(struct device *dev)
+{
+ struct rt721_sdca_priv *rt721_sdca = dev_get_drvdata(dev);
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ int ret1, ret2;
+
+ if (!rt721_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(&rt721_sdca->disable_irq_lock);
+ rt721_sdca->disable_irq = true;
+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0, 0);
+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
+ mutex_unlock(&rt721_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 rt721_sdca_dev_suspend(dev);
+}
+
+#define RT721_PROBE_TIMEOUT 5000
+
+static int __maybe_unused rt721_sdca_dev_resume(struct device *dev)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev);
+ unsigned long time;
+
+ if (!rt721->first_hw_init)
+ return 0;
+
+ if (!slave->unattach_request) {
+ mutex_lock(&rt721->disable_irq_lock);
+ if (rt721->disable_irq == true) {
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0);
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8);
+ rt721->disable_irq = false;
+ }
+ mutex_unlock(&rt721->disable_irq_lock);
+ goto regmap_sync;
+ }
+
+ time = wait_for_completion_timeout(&slave->initialization_complete,
+ msecs_to_jiffies(RT721_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(rt721->regmap, false);
+ regcache_sync(rt721->regmap);
+ regcache_cache_only(rt721->mbq_regmap, false);
+ regcache_sync(rt721->mbq_regmap);
+ return 0;
+}
+
+static const struct dev_pm_ops rt721_sdca_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rt721_sdca_dev_system_suspend, rt721_sdca_dev_resume)
+ SET_RUNTIME_PM_OPS(rt721_sdca_dev_suspend, rt721_sdca_dev_resume, NULL)
+};
+
+static struct sdw_driver rt721_sdca_sdw_driver = {
+ .driver = {
+ .name = "rt721-sdca",
+ .owner = THIS_MODULE,
+ .pm = &rt721_sdca_pm,
+ },
+ .probe = rt721_sdca_sdw_probe,
+ .remove = rt721_sdca_sdw_remove,
+ .ops = &rt721_sdca_slave_ops,
+ .id_table = rt721_sdca_id,
+};
+module_sdw_driver(rt721_sdca_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT721 SDCA SDW driver");
+MODULE_AUTHOR("Jack Yu <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt721-sdca-sdw.h b/sound/soc/codecs/rt721-sdca-sdw.h
new file mode 100644
index 000000000000..214b31b82583
--- /dev/null
+++ b/sound/soc/codecs/rt721-sdca-sdw.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt721-sdca-sdw.h -- RT721 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2024 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT721_SDW_H__
+#define __RT721_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw_registers.h>
+
+static const struct reg_default rt721_sdca_reg_defaults[] = {
+ { 0x202d, 0x00 },
+ { 0x2f01, 0x00 },
+ { 0x2f02, 0x09 },
+ { 0x2f03, 0x08 },
+ { 0x2f04, 0x00 },
+ { 0x2f05, 0x0e },
+ { 0x2f06, 0x01 },
+ { 0x2f09, 0x00 },
+ { 0x2f0a, 0x00 },
+ { 0x2f35, 0x00 },
+ { 0x2f50, 0xf0 },
+ { 0x2f58, 0x07 },
+ { 0x2f59, 0x07 },
+ { 0x2f5a, 0x00 },
+ { 0x2f5b, 0x07 },
+ { 0x2f5c, 0x27 },
+ { 0x2f5d, 0x07 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS01,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS11,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
+ RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
+ RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
+ RT721_SDCA_CTL_FU_MUTE, CH_03), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
+ RT721_SDCA_CTL_FU_MUTE, CH_04), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_CS1F,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_IT26,
+ RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_CS31,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23,
+ RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
+ RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
+ RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+};
+
+static const struct reg_default rt721_sdca_mbq_defaults[] = {
+ { 0x0900007, 0xc004 },
+ { 0x2000001, 0x0000 },
+ { 0x2000002, 0x0000 },
+ { 0x2000003, 0x0000 },
+ { 0x2000013, 0x8001 },
+ { 0x200003c, 0x0000 },
+ { 0x2000046, 0x3400 },
+ { 0x5f00044, 0x6040 },
+ { 0x5f00045, 0x3333 },
+ { 0x5f00048, 0x0000 },
+ { 0x6100005, 0x0005 },
+ { 0x6100006, 0x0000 },
+ { 0x610000d, 0x0051 },
+ { 0x6100010, 0x0180 },
+ { 0x6100011, 0x0000 },
+ { 0x6100013, 0x0000 },
+ { 0x6100015, 0x0000 },
+ { 0x6100017, 0x8049 },
+ { 0x6100025, 0x1000 },
+ { 0x6100029, 0x0809 },
+ { 0x610002c, 0x2828 },
+ { 0x610002d, 0x2929 },
+ { 0x610002e, 0x3529 },
+ { 0x610002f, 0x2901 },
+ { 0x6100053, 0x2630 },
+ { 0x6100054, 0x2a2a },
+ { 0x6100055, 0x152f },
+ { 0x6100057, 0x2200 },
+ { 0x610005a, 0x2a4b },
+ { 0x610005b, 0x2a00 },
+ { 0x610006a, 0x0102 },
+ { 0x610006d, 0x0102 },
+ { 0x6100092, 0x4f61 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME,
+ CH_L), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME,
+ CH_R), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME,
+ CH_L), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME,
+ CH_R), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, RT721_SDCA_CTL_FU_CH_GAIN,
+ CH_L), 0xfe00 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, RT721_SDCA_CTL_FU_CH_GAIN,
+ CH_R), 0xfe00 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_01),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_02),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_03),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_04),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_03), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_04), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_L),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_R),
+ 0x0000 },
+};
+
+#endif /* __RT721_SDW_H__ */
diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c
new file mode 100644
index 000000000000..1c9f32e405cf
--- /dev/null
+++ b/sound/soc/codecs/rt721-sdca.c
@@ -0,0 +1,1545 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt721-sdca.c -- rt721 SDCA ALSA SoC audio driver
+//
+// Copyright(c) 2024 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 "rt721-sdca.h"
+#include "rt-sdw-common.h"
+
+static void rt721_sdca_jack_detect_handler(struct work_struct *work)
+{
+ struct rt721_sdca_priv *rt721 =
+ container_of(work, struct rt721_sdca_priv, jack_detect_work.work);
+ int btn_type = 0;
+
+ if (!rt721->hs_jack)
+ return;
+
+ if (!rt721->component->card || !rt721->component->card->instantiated)
+ return;
+
+ /* SDW_SCP_SDCA_INT_SDCA_6 is used for jack detection */
+ if (rt721->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) {
+ rt721->jack_type = rt_sdca_headset_detect(rt721->regmap,
+ RT721_SDCA_ENT_GE49);
+ if (rt721->jack_type < 0)
+ return;
+ }
+
+ /* SDW_SCP_SDCA_INT_SDCA_8 is used for button detection */
+ if (rt721->scp_sdca_stat2 & SDW_SCP_SDCA_INT_SDCA_8)
+ btn_type = rt_sdca_button_detect(rt721->regmap,
+ RT721_SDCA_ENT_HID01, RT721_BUF_ADDR_HID1,
+ RT721_SDCA_HID_ID);
+
+ if (rt721->jack_type == 0)
+ btn_type = 0;
+
+ dev_dbg(&rt721->slave->dev,
+ "in %s, jack_type=%d\n", __func__, rt721->jack_type);
+ dev_dbg(&rt721->slave->dev,
+ "in %s, btn_type=0x%x\n", __func__, btn_type);
+ dev_dbg(&rt721->slave->dev,
+ "in %s, scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__,
+ rt721->scp_sdca_stat1, rt721->scp_sdca_stat2);
+
+ snd_soc_jack_report(rt721->hs_jack, rt721->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(rt721->hs_jack, rt721->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,
+ &rt721->jack_btn_check_work, msecs_to_jiffies(200));
+ }
+}
+
+static void rt721_sdca_btn_check_handler(struct work_struct *work)
+{
+ struct rt721_sdca_priv *rt721 =
+ container_of(work, struct rt721_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(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49,
+ RT721_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(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT721_SDCA_ENT_HID01,
+ RT721_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset);
+ if (ret < 0)
+ goto io_error;
+
+ for (idx = 0; idx < sizeof(buf); idx++) {
+ ret = regmap_read(rt721->regmap,
+ RT721_BUF_ADDR_HID1 + offset + idx, &val);
+ if (ret < 0)
+ goto io_error;
+ buf[idx] = val & 0xff;
+ }
+ /* Report ID for HID1 */
+ if (buf[0] == 0x11)
+ btn_type = rt_sdca_btn_type(&buf[1]);
+ } else
+ rt721->jack_type = 0;
+
+ dev_dbg(&rt721->slave->dev, "%s, btn_type=0x%x\n", __func__, btn_type);
+ snd_soc_jack_report(rt721->hs_jack, rt721->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(rt721->hs_jack, rt721->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,
+ &rt721->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 rt721_sdca_dmic_preset(struct rt721_sdca_priv *rt721)
+{
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_MISC_POWER_CTL31, 0x8000);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+ RT721_VREF1_HV_CTRL1, 0xe000);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_MISC_POWER_CTL31, 0x8007);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL9, 0x2a2a);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL10, 0x2a00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL6, 0x2a2a);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL5, 0x2626);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL8, 0x1e00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL7, 0x1515);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_CH_FLOAT_CTL3, 0x0304);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_CH_FLOAT_CTL4, 0x0304);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_HDA_LEGACY_CTL1, 0x0000);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_IT26,
+ RT721_SDCA_CTL_VENDOR_DEF, 0), 0x01);
+ regmap_write(rt721->mbq_regmap, 0x5910009, 0x2e01);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
+ RT721_RC_CALIB_CTRL0, 0x0b00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
+ RT721_RC_CALIB_CTRL0, 0x0b40);
+ regmap_write(rt721->regmap, 0x2f5c, 0x25);
+}
+
+static void rt721_sdca_amp_preset(struct rt721_sdca_priv *rt721)
+{
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_MISC_POWER_CTL31, 0x8000);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+ RT721_VREF1_HV_CTRL1, 0xe000);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_MISC_POWER_CTL31, 0x8007);
+ regmap_write(rt721->mbq_regmap, 0x5810000, 0x6420);
+ regmap_write(rt721->mbq_regmap, 0x5810000, 0x6421);
+ regmap_write(rt721->mbq_regmap, 0x5810000, 0xe421);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_CH_FLOAT_CTL6, 0x5561);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_REG,
+ RT721_GPIO_PAD_CTRL5, 0x8003);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23,
+ RT721_SDCA_CTL_VENDOR_DEF, 0), 0x04);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_01), 0x00);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
+ RT721_SDCA_CTL_FU_MUTE, CH_01), 0x00);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
+ RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00);
+}
+
+static void rt721_sdca_jack_preset(struct rt721_sdca_priv *rt721)
+{
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_MISC_POWER_CTL31, 0x8000);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+ RT721_VREF1_HV_CTRL1, 0xe000);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_MISC_POWER_CTL31, 0x8007);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_GE_REL_CTRL1, 0x8011);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_UMP_HID_CTRL3, 0xcf00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_UMP_HID_CTRL4, 0x000f);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_UMP_HID_CTRL1, 0x1100);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_UMP_HID_CTRL5, 0x0c12);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_JD_CTRL,
+ RT721_JD_1PIN_GAT_CTRL2, 0xc002);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
+ RT721_RC_CALIB_CTRL0, 0x0b00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
+ RT721_RC_CALIB_CTRL0, 0x0b40);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_UAJ_TOP_TCON14, 0x3333);
+ regmap_write(rt721->mbq_regmap, 0x5810035, 0x0036);
+ regmap_write(rt721->mbq_regmap, 0x5810030, 0xee00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL,
+ RT721_HP_AMP_2CH_CAL1, 0x0140);
+ regmap_write(rt721->mbq_regmap, 0x5810000, 0x0021);
+ regmap_write(rt721->mbq_regmap, 0x5810000, 0x8021);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL,
+ RT721_HP_AMP_2CH_CAL18, 0x5522);
+ regmap_write(rt721->mbq_regmap, 0x5b10007, 0x2000);
+ regmap_write(rt721->mbq_regmap, 0x5B10017, 0x1b0f);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_CBJ_CTRL,
+ RT721_CBJ_A0_GAT_CTRL1, 0x2a02);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL,
+ RT721_HP_AMP_2CH_CAL4, 0xa105);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_UAJ_TOP_TCON14, 0x3b33);
+ regmap_write(rt721->mbq_regmap, 0x310400, 0x3023);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_UAJ_TOP_TCON14, 0x3f33);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_UAJ_TOP_TCON13, 0x6048);
+ regmap_write(rt721->mbq_regmap, 0x310401, 0x3000);
+ regmap_write(rt721->mbq_regmap, 0x310402, 0x1b00);
+ regmap_write(rt721->mbq_regmap, 0x310300, 0x000f);
+ regmap_write(rt721->mbq_regmap, 0x310301, 0x3000);
+ regmap_write(rt721->mbq_regmap, 0x310302, 0x1b00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_UAJ_TOP_TCON17, 0x0008);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_DAC_CTRL,
+ RT721_DAC_2CH_CTRL3, 0x55ff);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_DAC_CTRL,
+ RT721_DAC_2CH_CTRL4, 0xcc00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+ RT721_MBIAS_LV_CTRL2, 0x6677);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+ RT721_VREF2_LV_CTRL1, 0x7600);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL2, 0x1234);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL3, 0x3512);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL1, 0x4040);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL4, 0x1201);
+ regmap_write(rt721->regmap, 0x2f58, 0x07);
+}
+
+static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721)
+{
+ mutex_lock(&rt721->calibrate_mutex);
+ if (rt721->hs_jack) {
+ sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0);
+ sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8);
+ dev_dbg(&rt721->slave->dev, "in %s enable\n", __func__);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_HDA_LEGACY_UAJ_CTL, 0x036E);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XU03,
+ RT721_SDCA_CTL_SELECTED_MODE, 0), 0);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XU0D,
+ RT721_SDCA_CTL_SELECTED_MODE, 0), 0);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_XU_REL_CTRL, 0x0000);
+ rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_GE_REL_CTRL1, 0x4000, 0x4000);
+ }
+ mutex_unlock(&rt721->calibrate_mutex);
+}
+
+static int rt721_sdca_set_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *hs_jack, void *data)
+{
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ rt721->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;
+ }
+
+ rt721_sdca_jack_init(rt721);
+
+ pm_runtime_mark_last_busy(component->dev);
+ pm_runtime_put_autosuspend(component->dev);
+
+ return 0;
+}
+
+/* For SDCA control DAC/ADC Gain */
+static int rt721_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 rt721_sdca_priv *rt721 = 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 tendA = 0x200;
+ 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(rt721->mbq_regmap, mc->reg, &lvalue);
+ regmap_read(rt721->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 if (mc->shift == 1) {
+ /* FU33 boost gain */
+ if (gain_l_val == 0)
+ gain_l_val = 0x8000;
+ else
+ gain_l_val = (gain_l_val - 1) * tendA;
+ } 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 if (mc->shift == 1) {
+ /* FU33 boost gain */
+ if (gain_r_val == 0)
+ gain_r_val = 0x8000;
+ else
+ gain_r_val = (gain_r_val - 1) * tendA;
+ } 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(rt721->mbq_regmap, mc->reg, gain_l_val);
+
+ /* Rch */
+ regmap_write(rt721->mbq_regmap, mc->rreg, gain_r_val);
+
+ regmap_read(rt721->mbq_regmap, mc->reg, &read_l);
+ regmap_read(rt721->mbq_regmap, mc->rreg, &read_r);
+ if (read_r == gain_r_val && read_l == gain_l_val)
+ return changed;
+
+ return -EIO;
+}
+
+static int rt721_sdca_set_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt721_sdca_priv *rt721 = 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(rt721->mbq_regmap, mc->reg, &read_l);
+ regmap_read(rt721->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 rt721_sdca_set_fu1e_capture_ctl(struct rt721_sdca_priv *rt721)
+{
+ int err, i;
+ unsigned int ch_mute;
+
+ for (i = 0; i < ARRAY_SIZE(rt721->fu1e_mixer_mute); i++) {
+ ch_mute = rt721->fu1e_dapm_mute || rt721->fu1e_mixer_mute[i];
+ err = regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
+ RT721_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int rt721_sdca_fu1e_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ struct rt721_sdca_dmic_kctrl_priv *p =
+ (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ unsigned int i;
+
+ for (i = 0; i < p->count; i++)
+ ucontrol->value.integer.value[i] = !rt721->fu1e_mixer_mute[i];
+
+ return 0;
+}
+
+static int rt721_sdca_fu1e_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ struct rt721_sdca_dmic_kctrl_priv *p =
+ (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ int err, changed = 0, i;
+
+ for (i = 0; i < p->count; i++) {
+ if (rt721->fu1e_mixer_mute[i] != !ucontrol->value.integer.value[i])
+ changed = 1;
+ rt721->fu1e_mixer_mute[i] = !ucontrol->value.integer.value[i];
+ }
+
+ err = rt721_sdca_set_fu1e_capture_ctl(rt721);
+ if (err < 0)
+ return err;
+
+ return changed;
+}
+
+static int rt721_sdca_set_fu0f_capture_ctl(struct rt721_sdca_priv *rt721)
+{
+ int err;
+ unsigned int ch_l, ch_r;
+
+ ch_l = (rt721->fu0f_dapm_mute || rt721->fu0f_mixer_l_mute) ? 0x01 : 0x00;
+ ch_r = (rt721->fu0f_dapm_mute || rt721->fu0f_mixer_r_mute) ? 0x01 : 0x00;
+
+ err = regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), ch_l);
+ if (err < 0)
+ return err;
+
+ err = regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), ch_r);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int rt721_sdca_fu0f_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = !rt721->fu0f_mixer_l_mute;
+ ucontrol->value.integer.value[1] = !rt721->fu0f_mixer_r_mute;
+ return 0;
+}
+
+static int rt721_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ int err, changed = 0;
+
+ if (rt721->fu0f_mixer_l_mute != !ucontrol->value.integer.value[0] ||
+ rt721->fu0f_mixer_r_mute != !ucontrol->value.integer.value[1])
+ changed = 1;
+
+ rt721->fu0f_mixer_l_mute = !ucontrol->value.integer.value[0];
+ rt721->fu0f_mixer_r_mute = !ucontrol->value.integer.value[1];
+ err = rt721_sdca_set_fu0f_capture_ctl(rt721);
+ if (err < 0)
+ return err;
+
+ return changed;
+}
+
+static int rt721_sdca_fu_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct rt721_sdca_dmic_kctrl_priv *p =
+ (struct rt721_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 rt721_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ struct rt721_sdca_dmic_kctrl_priv *p =
+ (struct rt721_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(rt721->mbq_regmap, p->reg_base + i, &regvalue);
+
+ if (!adc_vol_flag) /* boost gain */
+ ctl = regvalue / boost_step;
+ else /* ADC gain */
+ ctl = p->max - (((vol_max - regvalue) & 0xffff) / interval_offset);
+
+ ucontrol->value.integer.value[i] = ctl;
+ }
+
+ return 0;
+}
+
+static int rt721_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 rt721_sdca_dmic_kctrl_priv *p =
+ (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ struct rt721_sdca_priv *rt721 = 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(rt721->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(rt721->mbq_regmap, p->reg_base + i, gain_val[i]);
+ if (err < 0)
+ dev_err(&rt721->slave->dev, "%#08x can't be set\n", p->reg_base + i);
+ }
+
+ return changed;
+}
+
+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 DECLARE_TLV_DB_SCALE(mic2_boost_vol_tlv, -200, 200, 0);
+
+static const struct snd_kcontrol_new rt721_sdca_controls[] = {
+ /* Headphone playback settings */
+ SOC_DOUBLE_R_EXT_TLV("FU05 Playback Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x57, 0,
+ rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, out_vol_tlv),
+ /* Headset mic capture settings */
+ SOC_DOUBLE_EXT("FU0F Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0,
+ rt721_sdca_fu0f_capture_get, rt721_sdca_fu0f_capture_put),
+ SOC_DOUBLE_R_EXT_TLV("FU0F Capture Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F,
+ RT721_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F,
+ RT721_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x3f, 0,
+ rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, mic_vol_tlv),
+ SOC_DOUBLE_R_EXT_TLV("FU33 Boost Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44,
+ RT721_SDCA_CTL_FU_CH_GAIN, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44,
+ RT721_SDCA_CTL_FU_CH_GAIN, CH_R), 1, 0x15, 0,
+ rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, mic2_boost_vol_tlv),
+ /* AMP playback settings */
+ SOC_DOUBLE_R_EXT_TLV("FU06 Playback Volume",
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x57, 0,
+ rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, out_vol_tlv),
+ /* DMIC capture settings */
+ RT_SDCA_FU_CTRL("FU1E Capture Switch",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
+ RT721_SDCA_CTL_FU_MUTE, CH_01), 1, 1, 4, rt721_sdca_fu_info,
+ rt721_sdca_fu1e_capture_get, rt721_sdca_fu1e_capture_put),
+ RT_SDCA_EXT_TLV("FU1E Capture Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
+ RT721_SDCA_CTL_FU_VOLUME, CH_01),
+ rt721_sdca_dmic_set_gain_get, rt721_sdca_dmic_set_gain_put,
+ 4, 0x3f, mic_vol_tlv, rt721_sdca_fu_info),
+ RT_SDCA_EXT_TLV("FU15 Boost Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15,
+ RT721_SDCA_CTL_FU_CH_GAIN, CH_01),
+ rt721_sdca_dmic_set_gain_get, rt721_sdca_dmic_set_gain_put,
+ 4, 3, boost_vol_tlv, rt721_sdca_fu_info),
+};
+
+static int rt721_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned int val = 0, mask_sft, mask;
+
+ if (strstr(ucontrol->id.name, "ADC 09 Mux")) {
+ mask_sft = 12;
+ mask = 0x7;
+ } else if (strstr(ucontrol->id.name, "ADC 08 R Mux")) {
+ mask_sft = 10;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 08 L Mux")) {
+ mask_sft = 8;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 10 R Mux")) {
+ mask_sft = 6;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 10 L Mux")) {
+ mask_sft = 4;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 07 R Mux")) {
+ mask_sft = 2;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 07 L Mux")) {
+ mask_sft = 0;
+ mask = 0x3;
+ } else
+ return -EINVAL;
+
+ rt_sdca_index_read(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_HDA_LEGACY_MUX_CTL0, &val);
+
+ ucontrol->value.enumerated.item[0] = (val >> mask_sft) & mask;
+
+ return 0;
+}
+
+static int rt721_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 rt721_sdca_priv *rt721 = 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, mask;
+ unsigned int check;
+
+ if (item[0] >= e->items)
+ return -EINVAL;
+
+ if (strstr(ucontrol->id.name, "ADC 09 Mux")) {
+ mask_sft = 12;
+ mask = 0x7;
+ } else if (strstr(ucontrol->id.name, "ADC 08 R Mux")) {
+ mask_sft = 10;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 08 L Mux")) {
+ mask_sft = 8;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 10 R Mux")) {
+ mask_sft = 6;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 10 L Mux")) {
+ mask_sft = 4;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 07 R Mux")) {
+ mask_sft = 2;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 07 L Mux")) {
+ mask_sft = 0;
+ mask = 0x3;
+ } else
+ return -EINVAL;
+
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+ rt_sdca_index_read(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_HDA_LEGACY_MUX_CTL0, &val2);
+
+ if (strstr(ucontrol->id.name, "ADC 09 Mux"))
+ val2 = (val2 >> mask_sft) & 0x7;
+ else
+ val2 = (val2 >> mask_sft) & 0x3;
+
+ if (val == val2)
+ change = 0;
+ else
+ change = 1;
+
+ if (change) {
+ rt_sdca_index_read(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_HDA_LEGACY_MUX_CTL0, &check);
+ rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_HDA_LEGACY_MUX_CTL0, mask << mask_sft,
+ val << mask_sft);
+ }
+
+ snd_soc_dapm_mux_update_power(dapm, kcontrol,
+ item[0], e, NULL);
+
+ return change;
+}
+
+static const char * const adc09_mux_text[] = {
+ "MIC2",
+ "LINE1",
+ "LINE2",
+};
+static const char * const adc07_10_mux_text[] = {
+ "DMIC1 RE",
+ "DMIC1 FE",
+ "DMIC2 RE",
+ "DMIC2 FE",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt721_adc09_enum, SND_SOC_NOPM, 0, adc09_mux_text);
+static SOC_ENUM_SINGLE_DECL(
+ rt721_dmic_enum, SND_SOC_NOPM, 0, adc07_10_mux_text);
+
+static const struct snd_kcontrol_new rt721_sdca_adc09_mux =
+ SOC_DAPM_ENUM_EXT("ADC 09 Mux", rt721_adc09_enum,
+ rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put);
+static const struct snd_kcontrol_new rt721_sdca_adc08_r_mux =
+ SOC_DAPM_ENUM_EXT("ADC 08 R Mux", rt721_dmic_enum,
+ rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put);
+static const struct snd_kcontrol_new rt721_sdca_adc08_l_mux =
+ SOC_DAPM_ENUM_EXT("ADC 08 L Mux", rt721_dmic_enum,
+ rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put);
+static const struct snd_kcontrol_new rt721_sdca_adc10_r_mux =
+ SOC_DAPM_ENUM_EXT("ADC 10 R Mux", rt721_dmic_enum,
+ rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put);
+static const struct snd_kcontrol_new rt721_sdca_adc10_l_mux =
+ SOC_DAPM_ENUM_EXT("ADC 10 L Mux", rt721_dmic_enum,
+ rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put);
+static const struct snd_kcontrol_new rt721_sdca_adc07_r_mux =
+ SOC_DAPM_ENUM_EXT("ADC 07 R Mux", rt721_dmic_enum,
+ rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put);
+static const struct snd_kcontrol_new rt721_sdca_adc07_l_mux =
+ SOC_DAPM_ENUM_EXT("ADC 07 L Mux", rt721_dmic_enum,
+ rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put);
+
+
+static int rt721_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned char unmute = 0x0, mute = 0x1;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ msleep(100);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), unmute);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), unmute);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), mute);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), mute);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned char unmute = 0x0, mute = 0x1;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), unmute);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), unmute);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), mute);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), mute);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_sdca_fu23_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned char unmute = 0x0, mute = 0x1;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), unmute);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), unmute);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), mute);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), mute);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt721->fu1e_dapm_mute = false;
+ rt721_sdca_set_fu1e_capture_ctl(rt721);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt721->fu1e_dapm_mute = true;
+ rt721_sdca_set_fu1e_capture_ctl(rt721);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt721->fu0f_dapm_mute = false;
+ rt721_sdca_set_fu0f_capture_ctl(rt721);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt721->fu0f_dapm_mute = true;
+ rt721_sdca_set_fu0f_capture_ctl(rt721);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_sdca_pde41_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE41,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE41,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_sdca_pde34_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt721_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 41", SND_SOC_NOPM, 0, 0,
+ rt721_sdca_pde41_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 47", SND_SOC_NOPM, 0, 0,
+ rt721_sdca_pde47_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0,
+ rt721_sdca_pde11_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 34", SND_SOC_NOPM, 0, 0,
+ rt721_sdca_pde34_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_DAC_E("FU 21", NULL, SND_SOC_NOPM, 0, 0,
+ rt721_sdca_fu21_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("FU 23", NULL, SND_SOC_NOPM, 0, 0,
+ rt721_sdca_fu23_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("FU 42", NULL, SND_SOC_NOPM, 0, 0,
+ rt721_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,
+ rt721_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,
+ rt721_sdca_fu113_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_MUX("ADC 09 Mux", SND_SOC_NOPM, 0, 0,
+ &rt721_sdca_adc09_mux),
+ SND_SOC_DAPM_MUX("ADC 08 R Mux", SND_SOC_NOPM, 0, 0,
+ &rt721_sdca_adc08_r_mux),
+ SND_SOC_DAPM_MUX("ADC 08 L Mux", SND_SOC_NOPM, 0, 0,
+ &rt721_sdca_adc08_l_mux),
+ SND_SOC_DAPM_MUX("ADC 10 R Mux", SND_SOC_NOPM, 0, 0,
+ &rt721_sdca_adc10_r_mux),
+ SND_SOC_DAPM_MUX("ADC 10 L Mux", SND_SOC_NOPM, 0, 0,
+ &rt721_sdca_adc10_l_mux),
+ SND_SOC_DAPM_MUX("ADC 07 R Mux", SND_SOC_NOPM, 0, 0,
+ &rt721_sdca_adc07_r_mux),
+ SND_SOC_DAPM_MUX("ADC 07 L Mux", SND_SOC_NOPM, 0, 0,
+ &rt721_sdca_adc07_l_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 rt721_sdca_audio_map[] = {
+ {"FU 42", NULL, "DP1RX"},
+ {"FU 21", NULL, "DP3RX"},
+ {"FU 23", NULL, "DP3RX"},
+
+ {"ADC 09 Mux", "MIC2", "MIC2"},
+ {"ADC 09 Mux", "LINE1", "LINE1"},
+ {"ADC 09 Mux", "LINE2", "LINE2"},
+ {"ADC 07 R Mux", "DMIC1 RE", "DMIC1_2"},
+ {"ADC 07 R Mux", "DMIC1 FE", "DMIC1_2"},
+ {"ADC 07 R Mux", "DMIC2 RE", "DMIC3_4"},
+ {"ADC 07 R Mux", "DMIC2 FE", "DMIC3_4"},
+ {"ADC 07 L Mux", "DMIC1 RE", "DMIC1_2"},
+ {"ADC 07 L Mux", "DMIC1 FE", "DMIC1_2"},
+ {"ADC 07 L Mux", "DMIC2 RE", "DMIC3_4"},
+ {"ADC 07 L Mux", "DMIC2 FE", "DMIC3_4"},
+ {"ADC 08 R Mux", "DMIC1 RE", "DMIC1_2"},
+ {"ADC 08 R Mux", "DMIC1 FE", "DMIC1_2"},
+ {"ADC 08 R Mux", "DMIC2 RE", "DMIC3_4"},
+ {"ADC 08 R Mux", "DMIC2 FE", "DMIC3_4"},
+ {"ADC 08 L Mux", "DMIC1 RE", "DMIC1_2"},
+ {"ADC 08 L Mux", "DMIC1 FE", "DMIC1_2"},
+ {"ADC 08 L Mux", "DMIC2 RE", "DMIC3_4"},
+ {"ADC 08 L Mux", "DMIC2 FE", "DMIC3_4"},
+ {"ADC 10 R Mux", "DMIC1 RE", "DMIC1_2"},
+ {"ADC 10 R Mux", "DMIC1 FE", "DMIC1_2"},
+ {"ADC 10 R Mux", "DMIC2 RE", "DMIC3_4"},
+ {"ADC 10 R Mux", "DMIC2 FE", "DMIC3_4"},
+ {"ADC 10 L Mux", "DMIC1 RE", "DMIC1_2"},
+ {"ADC 10 L Mux", "DMIC1 FE", "DMIC1_2"},
+ {"ADC 10 L Mux", "DMIC2 RE", "DMIC3_4"},
+ {"ADC 10 L Mux", "DMIC2 FE", "DMIC3_4"},
+ {"FU 36", NULL, "PDE 34"},
+ {"FU 36", NULL, "ADC 09 Mux"},
+ {"FU 113", NULL, "PDE 11"},
+ {"FU 113", NULL, "ADC 07 R Mux"},
+ {"FU 113", NULL, "ADC 07 L Mux"},
+ {"FU 113", NULL, "ADC 10 R Mux"},
+ {"FU 113", NULL, "ADC 10 L Mux"},
+ {"DP2TX", NULL, "FU 36"},
+ {"DP6TX", NULL, "FU 113"},
+
+ {"HP", NULL, "PDE 47"},
+ {"HP", NULL, "FU 42"},
+ {"SPK", NULL, "PDE 41"},
+ {"SPK", NULL, "FU 21"},
+ {"SPK", NULL, "FU 23"},
+};
+
+static int rt721_sdca_parse_dt(struct rt721_sdca_priv *rt721, struct device *dev)
+{
+ device_property_read_u32(dev, "realtek,jd-src", &rt721->jd_src);
+
+ return 0;
+}
+
+static int rt721_sdca_probe(struct snd_soc_component *component)
+{
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ rt721_sdca_parse_dt(rt721, &rt721->slave->dev);
+ rt721->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_rt721 = {
+ .probe = rt721_sdca_probe,
+ .controls = rt721_sdca_controls,
+ .num_controls = ARRAY_SIZE(rt721_sdca_controls),
+ .dapm_widgets = rt721_sdca_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt721_sdca_dapm_widgets),
+ .dapm_routes = rt721_sdca_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rt721_sdca_audio_map),
+ .set_jack = rt721_sdca_set_jack_detect,
+ .endianness = 1,
+};
+
+static int rt721_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 rt721_sdca_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int rt721_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 rt721_sdca_priv *rt721 = 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 (!rt721->slave)
+ return -EINVAL;
+
+ /*
+ * RT721_AIF1 with port = 1 for headphone playback
+ * RT721_AIF1 with port = 2 for headset-mic capture
+ * RT721_AIF2 with port = 3 for speaker playback
+ * RT721_AIF3 with port = 6 for digital-mic capture
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ direction = SDW_DATA_DIR_RX;
+ if (dai->id == RT721_AIF1)
+ port = 1;
+ else if (dai->id == RT721_AIF2)
+ port = 3;
+ else
+ return -EINVAL;
+ } else {
+ direction = SDW_DATA_DIR_TX;
+ if (dai->id == RT721_AIF1)
+ port = 2;
+ else if (dai->id == RT721_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(rt721->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 8000:
+ sampling_rate = RT721_SDCA_RATE_8000HZ;
+ break;
+ case 16000:
+ sampling_rate = RT721_SDCA_RATE_16000HZ;
+ break;
+ case 24000:
+ sampling_rate = RT721_SDCA_RATE_24000HZ;
+ break;
+ case 32000:
+ sampling_rate = RT721_SDCA_RATE_32000HZ;
+ break;
+ case 44100:
+ sampling_rate = RT721_SDCA_RATE_44100HZ;
+ break;
+ case 48000:
+ sampling_rate = RT721_SDCA_RATE_48000HZ;
+ break;
+ case 96000:
+ sampling_rate = RT721_SDCA_RATE_96000HZ;
+ break;
+ case 192000:
+ sampling_rate = RT721_SDCA_RATE_192000HZ;
+ break;
+ case 384000:
+ sampling_rate = RT721_SDCA_RATE_384000HZ;
+ break;
+ case 768000:
+ sampling_rate = RT721_SDCA_RATE_768000HZ;
+ break;
+ default:
+ dev_err(component->dev, "Rate %d is not supported\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ /* set sampling frequency */
+ if (dai->id == RT721_AIF1) {
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS01,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS11,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+ }
+
+ if (dai->id == RT721_AIF2)
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_CS31,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+
+ if (dai->id == RT721_AIF3)
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_CS1F,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+
+ return 0;
+}
+
+static int rt721_sdca_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_runtime *sdw_stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt721->slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt721->slave, sdw_stream);
+ return 0;
+}
+
+#define RT721_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define RT721_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops rt721_sdca_ops = {
+ .hw_params = rt721_sdca_pcm_hw_params,
+ .hw_free = rt721_sdca_pcm_hw_free,
+ .set_stream = rt721_sdca_set_sdw_stream,
+ .shutdown = rt721_sdca_shutdown,
+};
+
+static struct snd_soc_dai_driver rt721_sdca_dai[] = {
+ {
+ .name = "rt721-sdca-aif1",
+ .id = RT721_AIF1,
+ .playback = {
+ .stream_name = "DP1 Headphone Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT721_STEREO_RATES,
+ .formats = RT721_FORMATS,
+ },
+ .capture = {
+ .stream_name = "DP2 Headset Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT721_STEREO_RATES,
+ .formats = RT721_FORMATS,
+ },
+ .ops = &rt721_sdca_ops,
+ },
+ {
+ .name = "rt721-sdca-aif2",
+ .id = RT721_AIF2,
+ .playback = {
+ .stream_name = "DP3 Speaker Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT721_STEREO_RATES,
+ .formats = RT721_FORMATS,
+ },
+ .ops = &rt721_sdca_ops,
+ },
+ {
+ .name = "rt721-sdca-aif3",
+ .id = RT721_AIF3,
+ .capture = {
+ .stream_name = "DP6 DMic Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = RT721_STEREO_RATES,
+ .formats = RT721_FORMATS,
+ },
+ .ops = &rt721_sdca_ops,
+ }
+};
+
+int rt721_sdca_init(struct device *dev, struct regmap *regmap,
+ struct regmap *mbq_regmap, struct sdw_slave *slave)
+{
+ struct rt721_sdca_priv *rt721;
+
+ rt721 = devm_kzalloc(dev, sizeof(*rt721), GFP_KERNEL);
+ if (!rt721)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt721);
+ rt721->slave = slave;
+ rt721->regmap = regmap;
+ rt721->mbq_regmap = mbq_regmap;
+
+ regcache_cache_only(rt721->regmap, true);
+ regcache_cache_only(rt721->mbq_regmap, true);
+
+ mutex_init(&rt721->calibrate_mutex);
+ mutex_init(&rt721->disable_irq_lock);
+
+ INIT_DELAYED_WORK(&rt721->jack_detect_work, rt721_sdca_jack_detect_handler);
+ INIT_DELAYED_WORK(&rt721->jack_btn_check_work, rt721_sdca_btn_check_handler);
+
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt721->hw_init = false;
+ rt721->first_hw_init = false;
+ rt721->fu1e_dapm_mute = true;
+ rt721->fu0f_dapm_mute = true;
+ rt721->fu0f_mixer_l_mute = rt721->fu0f_mixer_r_mute = true;
+ rt721->fu1e_mixer_mute[0] = rt721->fu1e_mixer_mute[1] =
+ rt721->fu1e_mixer_mute[2] = rt721->fu1e_mixer_mute[3] = true;
+
+ return devm_snd_soc_register_component(dev,
+ &soc_sdca_dev_rt721, rt721_sdca_dai, ARRAY_SIZE(rt721_sdca_dai));
+}
+
+int rt721_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev);
+
+ rt721->disable_irq = false;
+
+ if (rt721->hw_init)
+ return 0;
+
+ regcache_cache_only(rt721->regmap, false);
+ regcache_cache_only(rt721->mbq_regmap, false);
+ if (rt721->first_hw_init) {
+ regcache_cache_bypass(rt721->regmap, true);
+ regcache_cache_bypass(rt721->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);
+ rt721_sdca_dmic_preset(rt721);
+ rt721_sdca_amp_preset(rt721);
+ rt721_sdca_jack_preset(rt721);
+ if (rt721->first_hw_init) {
+ regcache_cache_bypass(rt721->regmap, false);
+ regcache_mark_dirty(rt721->regmap);
+ regcache_cache_bypass(rt721->mbq_regmap, false);
+ regcache_mark_dirty(rt721->mbq_regmap);
+ } else
+ rt721->first_hw_init = true;
+
+ /* Mark Slave initialization complete */
+ rt721->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 RT721 SDCA SDW driver");
+MODULE_AUTHOR("Jack Yu <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt721-sdca.h b/sound/soc/codecs/rt721-sdca.h
new file mode 100644
index 000000000000..0a82c107b19a
--- /dev/null
+++ b/sound/soc/codecs/rt721-sdca.h
@@ -0,0 +1,269 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt721-sdca.h -- RT721 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2024 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT721_H__
+#define __RT721_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 rt721_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 rt721_sdca_dmic_kctrl_priv {
+ unsigned int reg_base;
+ unsigned int count;
+ unsigned int max;
+ unsigned int invert;
+};
+
+/* NID */
+#define RT721_ANA_POW_PART 0x01
+#define RT721_DAC_CTRL 0x04
+#define RT721_JD_CTRL 0x09
+#define RT721_CBJ_CTRL 0x0a
+#define RT721_CAP_PORT_CTRL 0x0c
+#define RT721_CLASD_AMP_CTRL 0x0d
+#define RT721_VENDOR_REG 0x20
+#define RT721_RC_CALIB_CTRL 0x40
+#define RT721_VENDOR_EQ_L 0x53
+#define RT721_VENDOR_EQ_R 0x54
+#define RT721_VENDOR_HP_CALI 0x56
+#define RT721_VENDOR_CHARGE_PUMP 0x57
+#define RT721_VENDOR_CLASD_CALI 0x58
+#define RT721_VENDOR_IMS_DRE 0x5b
+#define RT721_VENDOR_SPK_EFUSE 0x5c
+#define RT721_VENDOR_LEVEL_CTRL 0x5d
+#define RT721_VENDOR_ANA_CTL 0x5f
+#define RT721_HDA_SDCA_FLOAT 0x61
+
+/* Index (NID:01h) */
+#define RT721_MBIAS_LV_CTRL2 0x07
+#define RT721_VREF1_HV_CTRL1 0x0a
+#define RT721_VREF2_LV_CTRL1 0x0b
+
+/* Index (NID:04h) */
+#define RT721_DAC_2CH_CTRL3 0x02
+#define RT721_DAC_2CH_CTRL4 0x03
+
+/* Index (NID:09h) */
+#define RT721_JD_1PIN_GAT_CTRL2 0x07
+
+/* Index (NID:0ah) */
+#define RT721_CBJ_A0_GAT_CTRL1 0x04
+#define RT721_CBJ_A0_GAT_CTRL2 0x05
+
+/* Index (NID:0Ch) */
+#define RT721_HP_AMP_2CH_CAL1 0x05
+#define RT721_HP_AMP_2CH_CAL4 0x08
+#define RT721_HP_AMP_2CH_CAL18 0x1b
+
+/* Index (NID:0dh) */
+#define RT721_CLASD_AMP_2CH_CAL 0x14
+
+/* Index (NID:20h) */
+#define RT721_JD_PRODUCT_NUM 0x00
+#define RT721_ANALOG_BIAS_CTL3 0x04
+#define RT721_JD_CTRL1 0x09
+#define RT721_LDO2_3_CTL1 0x0e
+#define RT721_GPIO_PAD_CTRL5 0x13
+#define RT721_LDO1_CTL 0x1a
+#define RT721_HP_JD_CTRL 0x24
+#define RT721_VD_HIDDEN_CTRL 0x26
+#define RT721_CLSD_CTRL6 0x3c
+#define RT721_COMBO_JACK_AUTO_CTL1 0x45
+#define RT721_COMBO_JACK_AUTO_CTL2 0x46
+#define RT721_COMBO_JACK_AUTO_CTL3 0x47
+#define RT721_DIGITAL_MISC_CTRL4 0x4a
+#define RT721_VREFO_GAT 0x63
+#define RT721_FSM_CTL 0x67
+#define RT721_SDCA_INTR_REC 0x82
+#define RT721_SW_CONFIG1 0x8a
+#define RT721_SW_CONFIG2 0x8b
+
+/* Index (NID:40h) */
+#define RT721_RC_CALIB_CTRL0 0x00
+
+/* Index (NID:58h) */
+#define RT721_DAC_DC_CALI_CTL1 0x01
+#define RT721_DAC_DC_CALI_CTL2 0x02
+#define RT721_DAC_DC_CALI_CTL3 0x03
+
+/* Index (NID:5fh) */
+#define RT721_MISC_POWER_CTL0 0x00
+#define RT721_MISC_POWER_CTL31 0x31
+#define RT721_UAJ_TOP_TCON13 0x44
+#define RT721_UAJ_TOP_TCON14 0x45
+#define RT721_UAJ_TOP_TCON17 0x48
+
+/* Index (NID:61h) */
+#define RT721_HDA_LEGACY_MUX_CTL0 0x00
+#define RT721_HDA_LEGACY_UAJ_CTL 0x02
+#define RT721_HDA_LEGACY_CTL1 0x05
+#define RT721_HDA_LEGACY_RESET_CTL 0x06
+#define RT721_XU_REL_CTRL 0x0c
+#define RT721_GE_REL_CTRL1 0x0d
+#define RT721_HDA_LEGACY_GPIO_WAKE_EN_CTL 0x0e
+#define RT721_GE_SDCA_RST_CTRL 0x10
+#define RT721_INT_RST_EN_CTRL 0x11
+#define RT721_XU_EVENT_EN 0x13
+#define RT721_INLINE_CTL2 0x17
+#define RT721_UMP_HID_CTRL1 0x18
+#define RT721_UMP_HID_CTRL2 0x19
+#define RT721_UMP_HID_CTRL3 0x1a
+#define RT721_UMP_HID_CTRL4 0x1b
+#define RT721_UMP_HID_CTRL5 0x1c
+#define RT721_FUNC_FLOAT_CTL0 0x22
+#define RT721_FUNC_FLOAT_CTL1 0x23
+#define RT721_FUNC_FLOAT_CTL2 0x24
+#define RT721_FUNC_FLOAT_CTL3 0x25
+#define RT721_ENT_FLOAT_CTL0 0x29
+#define RT721_ENT_FLOAT_CTL1 0x2c
+#define RT721_ENT_FLOAT_CTL2 0x2d
+#define RT721_ENT_FLOAT_CTL3 0x2e
+#define RT721_ENT_FLOAT_CTL4 0x2f
+#define RT721_CH_FLOAT_CTL1 0x45
+#define RT721_CH_FLOAT_CTL2 0x46
+#define RT721_ENT_FLOAT_CTL5 0x53
+#define RT721_ENT_FLOAT_CTL6 0x54
+#define RT721_ENT_FLOAT_CTL7 0x55
+#define RT721_ENT_FLOAT_CTL8 0x57
+#define RT721_ENT_FLOAT_CTL9 0x5a
+#define RT721_ENT_FLOAT_CTL10 0x5b
+#define RT721_CH_FLOAT_CTL3 0x6a
+#define RT721_CH_FLOAT_CTL4 0x6d
+#define RT721_CH_FLOAT_CTL5 0x70
+#define RT721_CH_FLOAT_CTL6 0x92
+
+/* Parameter & Verb control 01 (0x26)(NID:20h) */
+#define RT721_HIDDEN_REG_SW_RESET (0x1 << 14)
+
+/* Buffer address for HID */
+#define RT721_BUF_ADDR_HID1 0x44030000
+#define RT721_BUF_ADDR_HID2 0x44030020
+
+/* RT721 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
+
+/* RT721 SDCA entity */
+#define RT721_SDCA_ENT_HID01 0x01
+#define RT721_SDCA_ENT_XUV 0x03
+#define RT721_SDCA_ENT_GE49 0x49
+#define RT721_SDCA_ENT_USER_FU05 0x05
+#define RT721_SDCA_ENT_USER_FU06 0x06
+#define RT721_SDCA_ENT_USER_FU0F 0x0f
+#define RT721_SDCA_ENT_USER_FU10 0x19
+#define RT721_SDCA_ENT_USER_FU1E 0x1e
+#define RT721_SDCA_ENT_FU15 0x15
+#define RT721_SDCA_ENT_PDE23 0x23
+#define RT721_SDCA_ENT_PDE40 0x40
+#define RT721_SDCA_ENT_PDE41 0x41
+#define RT721_SDCA_ENT_PDE11 0x11
+#define RT721_SDCA_ENT_PDE12 0x12
+#define RT721_SDCA_ENT_PDE2A 0x2a
+#define RT721_SDCA_ENT_CS01 0x01
+#define RT721_SDCA_ENT_CS11 0x11
+#define RT721_SDCA_ENT_CS1F 0x1f
+#define RT721_SDCA_ENT_CS1C 0x1c
+#define RT721_SDCA_ENT_CS31 0x31
+#define RT721_SDCA_ENT_OT23 0x42
+#define RT721_SDCA_ENT_IT26 0x26
+#define RT721_SDCA_ENT_IT09 0x09
+#define RT721_SDCA_ENT_PLATFORM_FU15 0x15
+#define RT721_SDCA_ENT_PLATFORM_FU44 0x44
+#define RT721_SDCA_ENT_XU03 0x03
+#define RT721_SDCA_ENT_XU0D 0x0d
+#define RT721_SDCA_ENT_FU55 0x55
+
+/* RT721 SDCA control */
+#define RT721_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10
+#define RT721_SDCA_CTL_FU_MUTE 0x01
+#define RT721_SDCA_CTL_FU_VOLUME 0x02
+#define RT721_SDCA_CTL_HIDTX_CURRENT_OWNER 0x10
+#define RT721_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE 0x11
+#define RT721_SDCA_CTL_HIDTX_MESSAGE_OFFSET 0x12
+#define RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH 0x13
+#define RT721_SDCA_CTL_SELECTED_MODE 0x01
+#define RT721_SDCA_CTL_DETECTED_MODE 0x02
+#define RT721_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT721_SDCA_CTL_VENDOR_DEF 0x30
+#define RT721_SDCA_CTL_XUV 0x34
+#define RT721_SDCA_CTL_FU_CH_GAIN 0x0b
+
+/* RT721 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
+#define CH_09 0x09
+#define CH_0A 0x0a
+
+/* sample frequency index */
+#define RT721_SDCA_RATE_8000HZ 0x01
+#define RT721_SDCA_RATE_11025HZ 0x02
+#define RT721_SDCA_RATE_12000HZ 0x03
+#define RT721_SDCA_RATE_16000HZ 0x04
+#define RT721_SDCA_RATE_22050HZ 0x05
+#define RT721_SDCA_RATE_24000HZ 0x06
+#define RT721_SDCA_RATE_32000HZ 0x07
+#define RT721_SDCA_RATE_44100HZ 0x08
+#define RT721_SDCA_RATE_48000HZ 0x09
+#define RT721_SDCA_RATE_88200HZ 0x0a
+#define RT721_SDCA_RATE_96000HZ 0x0b
+#define RT721_SDCA_RATE_176400HZ 0x0c
+#define RT721_SDCA_RATE_192000HZ 0x0d
+#define RT721_SDCA_RATE_384000HZ 0x0e
+#define RT721_SDCA_RATE_768000HZ 0x0f
+
+/* RT721 HID ID */
+#define RT721_SDCA_HID_ID 0x11
+
+enum {
+ RT721_AIF1, /* For headset mic and headphone */
+ RT721_AIF2, /* For speaker */
+ RT721_AIF3, /* For dmic */
+ RT721_AIFS,
+};
+
+int rt721_sdca_io_init(struct device *dev, struct sdw_slave *slave);
+int rt721_sdca_init(struct device *dev, struct regmap *regmap,
+ struct regmap *mbq_regmap, struct sdw_slave *slave);
+#endif /* __RT721_H__ */
diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
index d5c985ff5ac5..25fc13687bc8 100644
--- a/sound/soc/codecs/rt722-sdca-sdw.c
+++ b/sound/soc/codecs/rt722-sdca-sdw.c
@@ -177,7 +177,7 @@ static int rt722_sdca_update_status(struct sdw_slave *slave,
* 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_6);
+ SDW_SCP_SDCA_INTMASK_SDCA_0);
sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2,
SDW_SCP_SDCA_INTMASK_SDCA_8);
}
@@ -308,12 +308,8 @@ static int rt722_sdca_interrupt_callback(struct sdw_slave *slave,
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;
@@ -444,7 +440,7 @@ static int __maybe_unused rt722_sdca_dev_system_suspend(struct device *dev)
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);
+ SDW_SCP_SDCA_INTMASK_SDCA_0, 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);
@@ -471,7 +467,7 @@ static int __maybe_unused rt722_sdca_dev_resume(struct device *dev)
if (!slave->unattach_request) {
mutex_lock(&rt722->disable_irq_lock);
if (rt722->disable_irq == true) {
- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_6);
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0);
sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8);
rt722->disable_irq = false;
}
diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c
index e5bd9ef812de..e17a142d03b9 100644
--- a/sound/soc/codecs/rt722-sdca.c
+++ b/sound/soc/codecs/rt722-sdca.c
@@ -190,8 +190,8 @@ static void rt722_sdca_jack_detect_handler(struct work_struct *work)
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) {
+ /* SDW_SCP_SDCA_INT_SDCA_0 is used for jack detection */
+ if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) {
ret = rt722_sdca_headset_detect(rt722);
if (ret < 0)
return;
@@ -294,7 +294,7 @@ static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722)
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);
+ SDW_SCP_SDCA_INTMASK_SDCA_0);
/* set SCP_SDCA_IntMask2[0]=1 */
sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2,
SDW_SCP_SDCA_INTMASK_SDCA_8);
@@ -308,6 +308,7 @@ static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722)
regmap_write(rt722->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU0D,
RT722_SDCA_CTL_SELECTED_MODE, 0), 0);
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_GE_RELATED_CTL1, 0x0000);
/* trigger GE interrupt */
rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL,
RT722_GE_RELATED_CTL2, 0x4000, 0x4000);
@@ -607,12 +608,8 @@ static int rt722_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol,
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);
- }
+ else /* ADC gain */
+ ctl = p->max - (((vol_max - regvalue) & 0xffff) / interval_offset);
ucontrol->value.integer.value[i] = ctl;
}
@@ -1471,13 +1468,18 @@ static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722)
0x008d);
/* check HP calibration FSM status */
for (loop_check = 0; loop_check < chk_cnt; loop_check++) {
+ usleep_range(10000, 11000);
ret = rt722_sdca_index_read(rt722, RT722_VENDOR_CALI,
RT722_DAC_DC_CALI_CTL3, &calib_status);
- if (ret < 0 || loop_check == chk_cnt)
+ if (ret < 0)
dev_dbg(&rt722->slave->dev, "calibration failed!, ret=%d\n", ret);
if ((calib_status & 0x0040) == 0x0)
break;
}
+
+ if (loop_check == chk_cnt)
+ dev_dbg(&rt722->slave->dev, "%s, calibration time-out!\n", __func__);
+
/* Set ADC09 power entity floating control */
rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ADC0A_08_PDE_FLOAT_CTL,
0x2a12);
diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c
index 240af0563283..390696440155 100644
--- a/sound/soc/codecs/simple-mux.c
+++ b/sound/soc/codecs/simple-mux.c
@@ -6,6 +6,7 @@
#include <linux/gpio/consumer.h>
#include <linux/module.h>
+#include <linux/mux/driver.h>
#include <linux/regulator/consumer.h>
#include <sound/soc.h>
@@ -16,6 +17,7 @@ struct simple_mux {
struct gpio_desc *gpiod_mux;
unsigned int mux;
const char *mux_texts[MUX_TEXT_SIZE];
+ unsigned int idle_state;
struct soc_enum mux_enum;
struct snd_kcontrol_new mux_mux;
struct snd_soc_dapm_widget mux_widgets[MUX_WIDGET_SIZE];
@@ -57,6 +59,9 @@ static int simple_mux_control_put(struct snd_kcontrol *kcontrol,
priv->mux = ucontrol->value.enumerated.item[0];
+ if (priv->idle_state != MUX_IDLE_AS_IS && dapm->bias_level < SND_SOC_BIAS_PREPARE)
+ return 0;
+
gpiod_set_value_cansleep(priv->gpiod_mux, priv->mux);
return snd_soc_dapm_mux_update_power(dapm, kcontrol,
@@ -75,10 +80,33 @@ static unsigned int simple_mux_read(struct snd_soc_component *component,
static const struct snd_kcontrol_new simple_mux_mux =
SOC_DAPM_ENUM_EXT("Muxer", simple_mux_enum, simple_mux_control_get, simple_mux_control_put);
+static int simple_mux_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+ struct simple_mux *priv = snd_soc_component_get_drvdata(c);
+
+ if (priv->idle_state != MUX_IDLE_AS_IS) {
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ gpiod_set_value_cansleep(priv->gpiod_mux, priv->mux);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ gpiod_set_value_cansleep(priv->gpiod_mux, priv->idle_state);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget simple_mux_dapm_widgets[MUX_WIDGET_SIZE] = {
SND_SOC_DAPM_INPUT("IN1"),
SND_SOC_DAPM_INPUT("IN2"),
- SND_SOC_DAPM_MUX("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux), // see simple_mux_probe()
+ SND_SOC_DAPM_MUX_E("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux, // see simple_mux_probe()
+ simple_mux_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_OUTPUT("OUT"),
};
@@ -93,6 +121,7 @@ static int simple_mux_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct simple_mux *priv;
+ int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -121,6 +150,14 @@ static int simple_mux_probe(struct platform_device *pdev)
/* Overwrite text ("Input 1", "Input 2") if property exists */
of_property_read_string_array(np, "state-labels", priv->mux_texts, MUX_TEXT_SIZE);
+ ret = of_property_read_u32(np, "idle-state", &priv->idle_state);
+ if (ret < 0) {
+ priv->idle_state = MUX_IDLE_AS_IS;
+ } else if (priv->idle_state != MUX_IDLE_AS_IS && priv->idle_state >= 2) {
+ dev_err(dev, "invalid idle-state %u\n", priv->idle_state);
+ return -EINVAL;
+ }
+
/* switch to use priv data instead of default */
priv->mux_enum.texts = priv->mux_texts;
priv->mux_mux.private_value = (unsigned long)&priv->mux_enum;
diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c
new file mode 100644
index 000000000000..f2cea6186d98
--- /dev/null
+++ b/sound/soc/codecs/sma1307.c
@@ -0,0 +1,2049 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// sma1307.c -- sma1307 ALSA SoC Audio driver
+//
+// Copyright 2024 Iron Device Corporation
+//
+// Auther: Gyuhwa Park <[email protected]>
+// Auther: Kiseok Jo <[email protected]>
+
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include "sma1307.h"
+
+#define CHECK_PERIOD_TIME 1 /* sec per HZ */
+#define PLL_MATCH(_input_clk_name, _output_clk_name, _input_clk,\
+ _post_n, _n, _vco, _p_cp)\
+{\
+ .input_clk_name = _input_clk_name,\
+ .output_clk_name = _output_clk_name,\
+ .input_clk = _input_clk,\
+ .post_n = _post_n,\
+ .n = _n,\
+ .vco = _vco,\
+ .p_cp = _p_cp,\
+}
+
+static const char *setting_file = "sma1307_setting.bin";
+#define SMA1307_SETTING_CHECKSUM 0x100000
+
+/* PLL clock setting Table */
+struct sma1307_pll_match {
+ char *input_clk_name;
+ char *output_clk_name;
+ unsigned int input_clk;
+ unsigned int post_n;
+ unsigned int n;
+ unsigned int vco;
+ unsigned int p_cp;
+};
+
+struct sma1307_data {
+ char *name;
+ void (*init)(struct regmap *regmap);
+};
+
+struct sma1307_priv {
+ bool check_fault_status;
+ bool force_mute_status;
+ bool sw_ot1_prot;
+ char *name;
+ enum sma1307_mode amp_mode;
+ int binary_mode;
+ int dapm_aif_in;
+ int dapm_aif_out0;
+ int dapm_aif_out1;
+ int dapm_sdo_en;
+ int dapm_sdo_setting;
+ int num_of_pll_matches;
+ int check_fault_period;
+ struct delayed_work check_fault_work;
+ struct device *dev;
+ struct kobject *kobj;
+ struct mutex default_lock;
+ struct regmap *regmap;
+ struct sma1307_setting_file set;
+ const struct sma1307_pll_match *pll_matches;
+ const struct sma1307_data *data;
+ unsigned int cur_vol;
+ unsigned int format;
+ unsigned int frame_size;
+ unsigned int init_vol;
+ unsigned int last_bclk;
+ unsigned int otp_trm2;
+ unsigned int otp_trm3;
+ unsigned int rev_num;
+ unsigned int sys_clk_id;
+ unsigned int tdm_slot0_rx;
+ unsigned int tdm_slot1_rx;
+ unsigned int tdm_slot0_tx;
+ unsigned int tdm_slot1_tx;
+ unsigned int tsdw_cnt;
+};
+
+static const struct sma1307_pll_match sma1307_pll_matches[] = {
+ /* in_clk_name, out_clk_name, input_clk post_n, n, vco, p_cp */
+ PLL_MATCH("1.411MHz", "24.554MHz",
+ 1411200, 0x06, 0xD1, 0x88, 0x00),
+ PLL_MATCH("1.536MHz", "24.576MHz",
+ 1536000, 0x06, 0xC0, 0x88, 0x00),
+ PLL_MATCH("2.822MHz", "24.554MHz",
+ 2822400, 0x06, 0xD1, 0x88, 0x04),
+ PLL_MATCH("3.072MHz", "24.576MHz",
+ 3072000, 0x06, 0x60, 0x88, 0x00),
+ PLL_MATCH("6.144MHz", "24.576MHz",
+ 6144000, 0x06, 0x60, 0x88, 0x04),
+ PLL_MATCH("12.288MHz", "24.576MHz",
+ 12288000, 0x06, 0x60, 0x88, 0x08),
+ PLL_MATCH("19.2MHz", "24.48MHz",
+ 19200000, 0x06, 0x7B, 0x88, 0x0C),
+ PLL_MATCH("24.576MHz", "24.576MHz",
+ 24576000, 0x06, 0x60, 0x88, 0x0C),
+};
+
+static struct snd_soc_component *sma1307_amp_component;
+
+static void sma1307_startup(struct snd_soc_component *);
+static void sma1307_shutdown(struct snd_soc_component *);
+static void sma1307_reset(struct snd_soc_component *);
+static void sma1307_set_binary(struct snd_soc_component *);
+static void sma1307_set_default(struct snd_soc_component *);
+
+/* Initial register value - 6.0W SPK (8ohm load) */
+static const struct reg_default sma1307_reg_def[] = {
+ { 0x00, 0x80 },
+ { 0x01, 0x00 },
+ { 0x02, 0x52 },
+ { 0x03, 0x4C },
+ { 0x04, 0x47 },
+ { 0x05, 0x42 },
+ { 0x06, 0x40 },
+ { 0x07, 0x40 },
+ { 0x08, 0x3C },
+ { 0x09, 0x2F },
+ { 0x0A, 0x32 },
+ { 0x0B, 0x50 },
+ { 0x0C, 0x8C },
+ { 0x0D, 0x00 },
+ { 0x0E, 0x3F },
+ { 0x0F, 0x00 },
+ { 0x10, 0x00 },
+ { 0x11, 0x00 },
+ { 0x12, 0x00 },
+ { 0x13, 0x09 },
+ { 0x14, 0x12 },
+ { 0x1C, 0x00 },
+ { 0x1D, 0x85 },
+ { 0x1E, 0xA1 },
+ { 0x1F, 0x67 },
+ { 0x22, 0x00 },
+ { 0x23, 0x1F },
+ { 0x24, 0x7A },
+ { 0x25, 0x00 },
+ { 0x26, 0xFF },
+ { 0x27, 0x39 },
+ { 0x28, 0x54 },
+ { 0x29, 0x92 },
+ { 0x2A, 0xB0 },
+ { 0x2B, 0xED },
+ { 0x2C, 0xED },
+ { 0x2D, 0xFF },
+ { 0x2E, 0xFF },
+ { 0x2F, 0xFF },
+ { 0x30, 0xFF },
+ { 0x31, 0xFF },
+ { 0x32, 0xFF },
+ { 0x34, 0x01 },
+ { 0x35, 0x17 },
+ { 0x36, 0x92 },
+ { 0x37, 0x00 },
+ { 0x38, 0x01 },
+ { 0x39, 0x10 },
+ { 0x3E, 0x01 },
+ { 0x3F, 0x08 },
+ { 0x8B, 0x05 },
+ { 0x8C, 0x50 },
+ { 0x8D, 0x80 },
+ { 0x8E, 0x10 },
+ { 0x8F, 0x02 },
+ { 0x90, 0x02 },
+ { 0x91, 0x83 },
+ { 0x92, 0xC0 },
+ { 0x93, 0x00 },
+ { 0x94, 0xA4 },
+ { 0x95, 0x74 },
+ { 0x96, 0x57 },
+ { 0xA2, 0xCC },
+ { 0xA3, 0x28 },
+ { 0xA4, 0x40 },
+ { 0xA5, 0x01 },
+ { 0xA6, 0x41 },
+ { 0xA7, 0x08 },
+ { 0xA8, 0x04 },
+ { 0xA9, 0x27 },
+ { 0xAA, 0x10 },
+ { 0xAB, 0x10 },
+ { 0xAC, 0x10 },
+ { 0xAD, 0x0F },
+ { 0xAE, 0xCD },
+ { 0xAF, 0x70 },
+ { 0xB0, 0x03 },
+ { 0xB1, 0xEF },
+ { 0xB2, 0x03 },
+ { 0xB3, 0xEF },
+ { 0xB4, 0xF3 },
+ { 0xB5, 0x3D },
+};
+
+static bool sma1307_readable_register(struct device *dev, unsigned int reg)
+{
+ if (reg > SMA1307_FF_DEVICE_INDEX)
+ return false;
+
+ switch (reg) {
+ case SMA1307_00_SYSTEM_CTRL ... SMA1307_1F_TONE_FINE_VOLUME:
+ case SMA1307_22_COMP_HYS_SEL ... SMA1307_32_BROWN_OUT_PROT19:
+ case SMA1307_34_OCP_SPK ... SMA1307_39_PMT_NZ_VAL:
+ case SMA1307_3B_TEST1 ... SMA1307_3F_ATEST2:
+ case SMA1307_8B_PLL_POST_N ... SMA1307_9A_OTP_TRM3:
+ case SMA1307_A0_PAD_CTRL0 ... SMA1307_BE_MCBS_CTRL2:
+ case SMA1307_F5_READY_FOR_V_SAR:
+ case SMA1307_F7_READY_FOR_T_SAR ... SMA1307_FF_DEVICE_INDEX:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+static bool sma1307_writeable_register(struct device *dev, unsigned int reg)
+{
+ if (reg > SMA1307_FF_DEVICE_INDEX)
+ return false;
+
+ switch (reg) {
+ case SMA1307_00_SYSTEM_CTRL ... SMA1307_1F_TONE_FINE_VOLUME:
+ case SMA1307_22_COMP_HYS_SEL ... SMA1307_32_BROWN_OUT_PROT19:
+ case SMA1307_34_OCP_SPK ... SMA1307_39_PMT_NZ_VAL:
+ case SMA1307_3B_TEST1 ... SMA1307_3F_ATEST2:
+ case SMA1307_8B_PLL_POST_N ... SMA1307_9A_OTP_TRM3:
+ case SMA1307_A0_PAD_CTRL0 ... SMA1307_BE_MCBS_CTRL2:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+static bool sma1307_volatile_register(struct device *dev, unsigned int reg)
+{
+ if (reg > SMA1307_FF_DEVICE_INDEX)
+ return false;
+
+ switch (reg) {
+ case SMA1307_F8_STATUS_T1 ... SMA1307_FF_DEVICE_INDEX:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+/* DB scale conversion of speaker volume */
+static const DECLARE_TLV_DB_SCALE(sma1307_spk_tlv, -6000, 50, 0);
+
+static const char *const sma1307_aif_in_source_text[] = {
+ "Mono", "Left", "Right"
+};
+
+static const char *const sma1307_sdo_setting_text[] = {
+ "Data_One_48k", "Data_Two_48k", "Data_Two_24k",
+ "Clk_PLL", "Clk_OSC"
+};
+
+static const char *const sma1307_aif_out_source_text[] = {
+ "Disable", "After_FmtC", "After_Mixer", "After_DSP",
+ "Vrms2_Avg", "Battery", "Temperature", "After_Delay"
+};
+
+static const char *const sma1307_tdm_slot_text[] = {
+ "Slot0", "Slot1", "Slot2", "Slot3",
+ "Slot4", "Slot5", "Slot6", "Slot7"
+};
+
+static const char *const sma1307_binary_mode_text[] = {
+ "Mode0", "Mode1", "Mode2", "Mode3", "Mode4"
+};
+
+static const char *const sma1307_reset_text[] = {
+ "Reset"
+};
+
+static const struct soc_enum sma1307_aif_in_source_enum =
+SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_aif_in_source_text),
+ sma1307_aif_in_source_text);
+static const struct soc_enum sma1307_sdo_setting_enum =
+SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_sdo_setting_text),
+ sma1307_sdo_setting_text);
+static const struct soc_enum sma1307_aif_out_source_enum =
+SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_aif_out_source_text),
+ sma1307_aif_out_source_text);
+static const struct soc_enum sma1307_tdm_slot_enum =
+SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_tdm_slot_text),
+ sma1307_tdm_slot_text);
+static const struct soc_enum sma1307_binary_mode_enum =
+SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_binary_mode_text),
+ sma1307_binary_mode_text);
+static const struct soc_enum sma1307_reset_enum =
+SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_reset_text),
+ sma1307_reset_text);
+
+static int sma1307_force_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = (int)sma1307->force_mute_status;
+
+ return 0;
+}
+
+static int sma1307_force_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ bool change = false, val = (bool)ucontrol->value.integer.value[0];
+
+ if (sma1307->force_mute_status == val) {
+ change = false;
+ } else {
+ change = true;
+ sma1307->force_mute_status = val;
+ }
+
+ return change;
+}
+
+static int sma1307_tdm_slot_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ int val1, val2;
+
+ regmap_read(sma1307->regmap, SMA1307_A5_TDM1, &val1);
+ regmap_read(sma1307->regmap, SMA1307_A6_TDM2, &val2);
+
+ if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX0_POS_NAME)) {
+ ucontrol->value.integer.value[0]
+ = (val1 & SMA1307_TDM_SLOT0_RX_POS_MASK) >> 3;
+ sma1307->tdm_slot0_rx = ucontrol->value.integer.value[0];
+ } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX1_POS_NAME)) {
+ ucontrol->value.integer.value[0]
+ = val1 & SMA1307_TDM_SLOT1_RX_POS_MASK;
+ sma1307->tdm_slot1_rx = ucontrol->value.integer.value[0];
+ } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX0_POS_NAME)) {
+ ucontrol->value.integer.value[0]
+ = (val2 & SMA1307_TDM_SLOT0_TX_POS_MASK) >> 3;
+ sma1307->tdm_slot0_tx = ucontrol->value.integer.value[0];
+ } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX1_POS_NAME)) {
+ ucontrol->value.integer.value[0]
+ = val2 & SMA1307_TDM_SLOT1_TX_POS_MASK;
+ sma1307->tdm_slot1_tx = ucontrol->value.integer.value[0];
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sma1307_tdm_slot_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ int val = (int)ucontrol->value.integer.value[0];
+ bool change;
+
+ if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX0_POS_NAME)) {
+ if (sma1307->tdm_slot0_rx == val)
+ change = false;
+ else {
+ change = true;
+ sma1307->tdm_slot0_rx = val;
+ regmap_update_bits(sma1307->regmap, SMA1307_A5_TDM1,
+ SMA1307_TDM_SLOT0_RX_POS_MASK, val << 3);
+ }
+ } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX1_POS_NAME)) {
+ if (sma1307->tdm_slot1_rx == val)
+ change = false;
+ else {
+ change = true;
+ sma1307->tdm_slot1_rx = val;
+ regmap_update_bits(sma1307->regmap, SMA1307_A5_TDM1,
+ SMA1307_TDM_SLOT1_RX_POS_MASK, val);
+ }
+ } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX0_POS_NAME)) {
+ if (sma1307->tdm_slot0_tx == val)
+ change = false;
+ else {
+ change = true;
+ sma1307->tdm_slot0_tx = val;
+ regmap_update_bits(sma1307->regmap, SMA1307_A6_TDM2,
+ SMA1307_TDM_SLOT0_TX_POS_MASK, val << 3);
+ }
+ } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX1_POS_NAME)) {
+ if (sma1307->tdm_slot1_tx == val)
+ change = false;
+ else {
+ change = true;
+ sma1307->tdm_slot1_tx = val;
+ regmap_update_bits(sma1307->regmap, SMA1307_A6_TDM2,
+ SMA1307_TDM_SLOT1_TX_POS_MASK, val);
+ }
+ } else {
+ dev_err(sma1307->dev, "%s: Invalid Control ID - %s\n",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ return change;
+}
+
+static int sma1307_sw_ot1_prot_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = (int)sma1307->sw_ot1_prot;
+
+ return 0;
+}
+
+static int sma1307_sw_ot1_prot_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ bool change = false, val = (bool)ucontrol->value.integer.value[0];
+
+ if (sma1307->sw_ot1_prot == val)
+ change = false;
+ else {
+ change = true;
+ sma1307->sw_ot1_prot = val;
+ }
+
+ return change;
+}
+
+static int sma1307_check_fault_status_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = (int)sma1307->check_fault_status;
+
+ return 0;
+}
+
+static int sma1307_check_fault_status_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ bool change = false, val = (bool)ucontrol->value.integer.value[0];
+
+ if (sma1307->check_fault_status == val) {
+ change = false;
+ } else {
+ change = true;
+ sma1307->check_fault_status = val;
+ }
+
+ return change;
+}
+
+static int sma1307_check_fault_period_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = sma1307->check_fault_period;
+
+ return 0;
+}
+
+static int sma1307_check_fault_period_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ bool change = false;
+ int val = ucontrol->value.integer.value[0];
+
+ if (val < mc->min || val > mc->max)
+ return -EINVAL;
+ if (sma1307->check_fault_period == val) {
+ change = false;
+ } else {
+ change = true;
+ sma1307->check_fault_period = val;
+ }
+
+ return change;
+}
+
+static int sma1307_reset_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ regmap_update_bits(sma1307->regmap, SMA1307_00_SYSTEM_CTRL,
+ SMA1307_RESET_MASK, SMA1307_RESET_ON);
+ sma1307_reset(component);
+
+ snd_ctl_notify(component->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &kcontrol->id);
+
+ return true;
+}
+
+static int sma1307_binary_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct sma1307_priv *sma1307 = snd_kcontrol_chip(kcontrol);
+
+ sma1307->binary_mode = (int)ucontrol->value.enumerated.item[0];
+ if (sma1307->set.status)
+ sma1307_set_binary(component);
+
+ return snd_soc_put_enum_double(kcontrol, ucontrol);
+}
+
+static void sma1307_startup(struct snd_soc_component *component)
+{
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ regmap_update_bits(sma1307->regmap, SMA1307_A2_TOP_MAN1,
+ SMA1307_PLL_MASK, SMA1307_PLL_ON);
+ regmap_update_bits(sma1307->regmap, SMA1307_00_SYSTEM_CTRL,
+ SMA1307_POWER_MASK, SMA1307_POWER_ON);
+
+ if (sma1307->amp_mode == SMA1307_MONO_MODE) {
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_10_SYSTEM_CTRL1,
+ SMA1307_SPK_MODE_MASK,
+ SMA1307_SPK_MONO);
+ } else {
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_10_SYSTEM_CTRL1,
+ SMA1307_SPK_MODE_MASK,
+ SMA1307_SPK_STEREO);
+ }
+
+ if (sma1307->check_fault_status) {
+ if (sma1307->check_fault_period > 0)
+ queue_delayed_work(system_freezable_wq,
+ &sma1307->check_fault_work,
+ sma1307->check_fault_period * HZ);
+ else
+ queue_delayed_work(system_freezable_wq,
+ &sma1307->check_fault_work,
+ CHECK_PERIOD_TIME * HZ);
+ }
+}
+
+static void sma1307_shutdown(struct snd_soc_component *component)
+{
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ /* for SMA1307A */
+ cancel_delayed_work_sync(&sma1307->check_fault_work);
+
+ regmap_update_bits(sma1307->regmap, SMA1307_0E_MUTE_VOL_CTRL,
+ SMA1307_SPK_MUTE_MASK, SMA1307_SPK_MUTE);
+ /* Need to wait time for mute slope */
+ msleep(55);
+
+ regmap_update_bits(sma1307->regmap, SMA1307_10_SYSTEM_CTRL1,
+ SMA1307_SPK_MODE_MASK, SMA1307_SPK_OFF);
+ regmap_update_bits(sma1307->regmap, SMA1307_A2_TOP_MAN1,
+ SMA1307_PLL_MASK, SMA1307_PLL_OFF);
+ regmap_update_bits(sma1307->regmap, SMA1307_00_SYSTEM_CTRL,
+ SMA1307_POWER_MASK, SMA1307_POWER_OFF);
+}
+
+static int sma1307_aif_in_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 sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ unsigned int mux = sma1307->dapm_aif_in;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ switch (mux) {
+ case SMA1307_MONO_MODE:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_11_SYSTEM_CTRL2,
+ SMA1307_MONOMIX_MASK,
+ SMA1307_MONOMIX_ON);
+ break;
+ case SMA1307_LEFT_MODE:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_11_SYSTEM_CTRL2,
+ SMA1307_MONOMIX_MASK,
+ SMA1307_MONOMIX_OFF);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_11_SYSTEM_CTRL2,
+ SMA1307_LR_DATA_SW_MASK,
+ SMA1307_LR_DATA_SW_NORMAL);
+ break;
+ case SMA1307_RIGHT_MODE:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_11_SYSTEM_CTRL2,
+ SMA1307_MONOMIX_MASK,
+ SMA1307_MONOMIX_OFF);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_11_SYSTEM_CTRL2,
+ SMA1307_LR_DATA_SW_MASK,
+ SMA1307_LR_DATA_SW_SWAP);
+ break;
+ default:
+
+ dev_err(sma1307->dev, "%s: Invalid value (%d)\n",
+ __func__, mux);
+ return -EINVAL;
+ }
+ sma1307->amp_mode = mux;
+ break;
+ }
+ return 0;
+}
+
+static int sma1307_sdo_setting_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 sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ unsigned int mux = sma1307->dapm_sdo_setting;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ switch (mux) {
+ case SMA1307_OUT_DATA_ONE_48K:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A2_TOP_MAN1,
+ SMA1307_SDO_OUTPUT2_MASK,
+ SMA1307_ONE_SDO_PER_CH);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A3_TOP_MAN2,
+ SMA1307_SDO_OUTPUT3_MASK
+ |
+ SMA1307_DATA_CLK_SEL_MASK,
+ SMA1307_SDO_OUTPUT3_DIS
+ | SMA1307_SDO_DATA);
+ break;
+ case SMA1307_OUT_DATA_TWO_48K:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A2_TOP_MAN1,
+ SMA1307_SDO_OUTPUT2_MASK,
+ SMA1307_TWO_SDO_PER_CH);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A3_TOP_MAN2,
+ SMA1307_SDO_OUTPUT3_MASK
+ |
+ SMA1307_DATA_CLK_SEL_MASK,
+ SMA1307_SDO_OUTPUT3_DIS
+ | SMA1307_SDO_DATA);
+ break;
+ case SMA1307_OUT_DATA_TWO_24K:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A2_TOP_MAN1,
+ SMA1307_SDO_OUTPUT2_MASK,
+ SMA1307_TWO_SDO_PER_CH);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A3_TOP_MAN2,
+ SMA1307_SDO_OUTPUT3_MASK
+ |
+ SMA1307_DATA_CLK_SEL_MASK,
+ SMA1307_TWO_SDO_PER_CH_24K
+ | SMA1307_SDO_DATA);
+ break;
+ case SMA1307_OUT_CLK_PLL:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A3_TOP_MAN2,
+ SMA1307_DATA_CLK_SEL_MASK,
+ SMA1307_SDO_CLK_PLL);
+
+ break;
+ case SMA1307_OUT_CLK_OSC:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A3_TOP_MAN2,
+ SMA1307_DATA_CLK_SEL_MASK,
+ SMA1307_SDO_CLK_OSC);
+
+ break;
+ default:
+ dev_err(sma1307->dev, "%s: Invalid value (%d)\n",
+ __func__, mux);
+ return -EINVAL;
+ }
+ break;
+ }
+ return 0;
+}
+
+static int sma1307_aif_out_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 sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ unsigned int mux = 0, val = 0, mask = 0;
+
+ if (!strcmp(w->name, SMA1307_AIF_OUT0_NAME)) {
+ mux = sma1307->dapm_aif_out0;
+ val = mux;
+ mask = SMA1307_SDO_OUT0_SEL_MASK;
+ } else if (!strcmp(w->name, SMA1307_AIF_OUT1_NAME)) {
+ mux = sma1307->dapm_aif_out1;
+ val = mux << 3;
+ mask = SMA1307_SDO_OUT1_SEL_MASK;
+ } else {
+ dev_err(sma1307->dev, "%s: Invalid widget - %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_update_bits(sma1307->regmap, SMA1307_09_OUTPUT_CTRL,
+ mask, val);
+ break;
+ }
+ return 0;
+}
+
+static int sma1307_sdo_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 sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_09_OUTPUT_CTRL,
+ SMA1307_PORT_CONFIG_MASK,
+ SMA1307_OUTPUT_PORT_ENABLE);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A3_TOP_MAN2,
+ SMA1307_SDO_OUTPUT_MASK,
+ SMA1307_LOGIC_OUTPUT);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_09_OUTPUT_CTRL,
+ SMA1307_PORT_CONFIG_MASK,
+ SMA1307_INPUT_PORT_ONLY);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A3_TOP_MAN2,
+ SMA1307_SDO_OUTPUT_MASK,
+ SMA1307_HIGH_Z_OUTPUT);
+ break;
+ }
+ return 0;
+}
+
+static int sma1307_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ sma1307_startup(component);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ sma1307_shutdown(component);
+ break;
+ }
+ return 0;
+}
+
+static int sma1307_dapm_aif_in_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct sma1307_priv *sma1307 =
+ snd_soc_component_get_drvdata(dapm->component);
+
+ ucontrol->value.enumerated.item[0] = (unsigned int)sma1307->dapm_aif_in;
+ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ return 0;
+}
+
+static int sma1307_dapm_aif_in_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct sma1307_priv *sma1307 =
+ snd_soc_component_get_drvdata(dapm->component);
+ int val = (int)ucontrol->value.enumerated.item[0];
+ bool change;
+
+ if ((val < 0) || (val >= ARRAY_SIZE(sma1307_aif_in_source_text))) {
+ dev_err(sma1307->dev, "%s: Out of range\n", __func__);
+ return -EINVAL;
+ }
+
+ if (sma1307->dapm_aif_in != val) {
+ change = true;
+ sma1307->dapm_aif_in = val;
+ } else
+ change = false;
+
+ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ return change;
+}
+
+static int sma1307_dapm_sdo_setting_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct sma1307_priv *sma1307 =
+ snd_soc_component_get_drvdata(dapm->component);
+
+ ucontrol->value.enumerated.item[0] =
+ (unsigned int)sma1307->dapm_sdo_setting;
+ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ return 0;
+}
+
+static int sma1307_dapm_sdo_setting_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct sma1307_priv *sma1307 =
+ snd_soc_component_get_drvdata(dapm->component);
+ int val = (int)ucontrol->value.enumerated.item[0];
+ bool change;
+
+ if ((val < 0) || (val >= ARRAY_SIZE(sma1307_sdo_setting_text))) {
+ dev_err(sma1307->dev, "%s: Out of range\n", __func__);
+ return -EINVAL;
+ }
+
+ if (sma1307->dapm_sdo_setting != val) {
+ change = true;
+ sma1307->dapm_sdo_setting = val;
+ } else
+ change = false;
+
+ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ return change;
+}
+
+static int sma1307_dapm_aif_out_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct sma1307_priv *sma1307 =
+ snd_soc_component_get_drvdata(dapm->component);
+ unsigned int val = 0;
+
+ if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT0_NAME)) {
+ val = (unsigned int)sma1307->dapm_aif_out0;
+ } else if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT1_NAME)) {
+ val = (unsigned int)sma1307->dapm_aif_out1;
+ } else {
+ dev_err(sma1307->dev, "%s: Invalid Control ID - %s\n",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+ ucontrol->value.enumerated.item[0] = val;
+ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ return 0;
+}
+
+static int sma1307_dapm_aif_out_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct sma1307_priv *sma1307 =
+ snd_soc_component_get_drvdata(dapm->component);
+ int val = (int)ucontrol->value.enumerated.item[0];
+ bool change;
+
+ if ((val < 0) || (val >= ARRAY_SIZE(sma1307_aif_out_source_text))) {
+ dev_err(sma1307->dev, "%s: Out of range\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT0_NAME)) {
+ if (sma1307->dapm_aif_out0 != val) {
+ change = true;
+ sma1307->dapm_aif_out0 = val;
+ } else
+ change = false;
+ } else if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT1_NAME)) {
+ if (sma1307->dapm_aif_out1 != val) {
+ change = true;
+ sma1307->dapm_aif_out1 = val;
+ } else
+ change = false;
+ } else {
+ dev_err(sma1307->dev, "%s: Invalid Control ID - %s\n",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ return change;
+}
+
+static int sma1307_dapm_sdo_enable_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct sma1307_priv *sma1307 =
+ snd_soc_component_get_drvdata(dapm->component);
+
+ ucontrol->value.integer.value[0] = (long)sma1307->dapm_sdo_en;
+ snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+
+ return 0;
+}
+
+static int sma1307_dapm_sdo_enable_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct sma1307_priv *sma1307 =
+ snd_soc_component_get_drvdata(dapm->component);
+ int val = (int)ucontrol->value.integer.value[0];
+ bool change;
+
+ if ((val < 0) || (val > 1)) {
+ dev_err(sma1307->dev, "%s: Out of range\n", __func__);
+ return -EINVAL;
+ }
+
+ if (sma1307->dapm_sdo_en != val) {
+ change = true;
+ sma1307->dapm_sdo_en = val;
+ } else
+ change = false;
+
+ snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+
+ return change;
+}
+
+static const struct snd_kcontrol_new sma1307_aif_in_source_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = SMA1307_AIF_IN_NAME,
+ .info = snd_soc_info_enum_double,
+ .get = sma1307_dapm_aif_in_get,
+ .put = sma1307_dapm_aif_in_put,
+ .private_value = (unsigned long)&sma1307_aif_in_source_enum
+};
+
+static const struct snd_kcontrol_new sma1307_sdo_setting_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "SDO Setting",
+ .info = snd_soc_info_enum_double,
+ .get = sma1307_dapm_sdo_setting_get,
+ .put = sma1307_dapm_sdo_setting_put,
+ .private_value = (unsigned long)&sma1307_sdo_setting_enum
+};
+
+static const struct snd_kcontrol_new sma1307_aif_out0_source_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = SMA1307_AIF_OUT0_NAME,
+ .info = snd_soc_info_enum_double,
+ .get = sma1307_dapm_aif_out_get,
+ .put = sma1307_dapm_aif_out_put,
+ .private_value = (unsigned long)&sma1307_aif_out_source_enum
+};
+
+static const struct snd_kcontrol_new sma1307_aif_out1_source_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = SMA1307_AIF_OUT1_NAME,
+ .info = snd_soc_info_enum_double,
+ .get = sma1307_dapm_aif_out_get,
+ .put = sma1307_dapm_aif_out_put,
+ .private_value = (unsigned long)&sma1307_aif_out_source_enum
+};
+
+static const struct snd_kcontrol_new sma1307_sdo_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Switch",
+ .info = snd_soc_info_volsw,
+ .get = sma1307_dapm_sdo_enable_get,
+ .put = sma1307_dapm_sdo_enable_put,
+ .private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, 0, 1, 0, 0)
+};
+
+static const struct snd_kcontrol_new sma1307_enable_control =
+ SOC_DAPM_SINGLE("Switch", SMA1307_00_SYSTEM_CTRL, 0, 1, 0);
+
+static const struct snd_kcontrol_new sma1307_binary_mode_control[] = {
+ SOC_ENUM_EXT("Binary Mode", sma1307_binary_mode_enum,
+ snd_soc_get_enum_double, sma1307_binary_mode_put),
+};
+
+static const struct snd_kcontrol_new sma1307_snd_controls[] = {
+ SOC_SINGLE_TLV(SMA1307_VOL_CTRL_NAME, SMA1307_0A_SPK_VOL,
+ 0, 167, 1, sma1307_spk_tlv),
+ SOC_ENUM_EXT(SMA1307_TDM_RX0_POS_NAME, sma1307_tdm_slot_enum,
+ sma1307_tdm_slot_get, sma1307_tdm_slot_put),
+ SOC_ENUM_EXT(SMA1307_TDM_RX1_POS_NAME, sma1307_tdm_slot_enum,
+ sma1307_tdm_slot_get, sma1307_tdm_slot_put),
+ SOC_ENUM_EXT(SMA1307_TDM_TX0_POS_NAME, sma1307_tdm_slot_enum,
+ sma1307_tdm_slot_get, sma1307_tdm_slot_put),
+ SOC_ENUM_EXT(SMA1307_TDM_TX1_POS_NAME, sma1307_tdm_slot_enum,
+ sma1307_tdm_slot_get, sma1307_tdm_slot_put),
+ SOC_ENUM_EXT(SMA1307_RESET_CTRL_NAME, sma1307_reset_enum,
+ snd_soc_get_enum_double, sma1307_reset_put),
+ SOC_SINGLE_BOOL_EXT(SMA1307_FORCE_MUTE_CTRL_NAME, 0,
+ sma1307_force_mute_get, sma1307_force_mute_put),
+ SOC_SINGLE_BOOL_EXT(SMA1307_OT1_SW_PROT_CTRL_NAME, 0,
+ sma1307_sw_ot1_prot_get, sma1307_sw_ot1_prot_put),
+ SOC_SINGLE_BOOL_EXT(SMA1307_CHECK_FAULT_STATUS_NAME, 0,
+ sma1307_check_fault_status_get,
+ sma1307_check_fault_status_put),
+ SOC_SINGLE_EXT(SMA1307_CHECK_FAULT_PERIOD_NAME, SND_SOC_NOPM, 0, 600, 0,
+ sma1307_check_fault_period_get,
+ sma1307_check_fault_period_put),
+};
+
+static const struct snd_soc_dapm_widget sma1307_dapm_widgets[] = {
+ /* platform domain */
+ SND_SOC_DAPM_OUTPUT("SPK"),
+ SND_SOC_DAPM_INPUT("SDO"),
+
+ /* path domain */
+ SND_SOC_DAPM_MUX_E(SMA1307_AIF_IN_NAME, SND_SOC_NOPM, 0, 0,
+ &sma1307_aif_in_source_control,
+ sma1307_aif_in_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MUX_E("SDO Setting", SND_SOC_NOPM, 0, 0,
+ &sma1307_sdo_setting_control,
+ sma1307_sdo_setting_event,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MUX_E(SMA1307_AIF_OUT0_NAME, SND_SOC_NOPM, 0, 0,
+ &sma1307_aif_out0_source_control,
+ sma1307_aif_out_event,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MUX_E(SMA1307_AIF_OUT1_NAME, SND_SOC_NOPM, 0, 0,
+ &sma1307_aif_out1_source_control,
+ sma1307_aif_out_event,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SWITCH_E("SDO Enable", SND_SOC_NOPM, 0, 0,
+ &sma1307_sdo_control,
+ sma1307_sdo_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("Entry", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV_E("AMP Power", SND_SOC_NOPM, 0, 0, NULL, 0,
+ sma1307_power_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SWITCH("AMP Enable", SND_SOC_NOPM, 0, 0,
+ &sma1307_enable_control),
+
+ /* stream domain */
+ SND_SOC_DAPM_AIF_IN("AIF IN", "Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF OUT", "Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route sma1307_audio_map[] = {
+ /* Playback */
+ { "AIF IN Source", "Mono", "AIF IN" },
+ { "AIF IN Source", "Left", "AIF IN" },
+ { "AIF IN Source", "Right", "AIF IN" },
+
+ { "SDO Enable", "Switch", "AIF IN" },
+
+ { "SDO Setting", "Data_One_48k", "SDO Enable" },
+ { "SDO Setting", "Data_Two_48k", "SDO Enable" },
+ { "SDO Setting", "Data_Two_24k", "SDO Enable" },
+ { "SDO Setting", "Clk_PLL", "SDO Enable" },
+ { "SDO Setting", "Clk_OSC", "SDO Enable" },
+
+ { "AIF OUT0 Source", "Disable", "SDO Setting" },
+ { "AIF OUT0 Source", "After_FmtC", "SDO Setting" },
+ { "AIF OUT0 Source", "After_Mixer", "SDO Setting" },
+ { "AIF OUT0 Source", "After_DSP", "SDO Setting" },
+ { "AIF OUT0 Source", "Vrms2_Avg", "SDO Setting" },
+ { "AIF OUT0 Source", "Battery", "SDO Setting" },
+ { "AIF OUT0 Source", "Temperature", "SDO Setting" },
+ { "AIF OUT0 Source", "After_Delay", "SDO Setting" },
+
+ { "AIF OUT1 Source", "Disable", "SDO Setting" },
+ { "AIF OUT1 Source", "After_FmtC", "SDO Setting" },
+ { "AIF OUT1 Source", "After_Mixer", "SDO Setting" },
+ { "AIF OUT1 Source", "After_DSP", "SDO Setting" },
+ { "AIF OUT1 Source", "Vrms2_Avg", "SDO Setting" },
+ { "AIF OUT1 Source", "Battery", "SDO Setting" },
+ { "AIF OUT1 Source", "Temperature", "SDO Setting" },
+ { "AIF OUT1 Source", "After_Delay", "SDO Setting" },
+
+ { "Entry", NULL, "AIF OUT0 Source" },
+ { "Entry", NULL, "AIF OUT1 Source" },
+ { "Entry", NULL, "AIF IN Source" },
+
+ { "AMP Power", NULL, "Entry" },
+
+ { "AMP Enable", "Switch", "AMP Power" },
+ { "SPK", NULL, "AMP Enable" },
+
+ /* Capture */
+ { "AIF OUT", NULL, "AMP Enable" },
+};
+
+static void sma1307_setup_pll(struct snd_soc_component *component,
+ unsigned int bclk)
+{
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ int i = 0;
+
+ dev_dbg(component->dev, "%s: BCLK = %dHz\n", __func__, bclk);
+
+ if (sma1307->sys_clk_id == SMA1307_PLL_CLKIN_MCLK) {
+ dev_warn(component->dev, "%s: MCLK is not supported\n",
+ __func__);
+ } else if (sma1307->sys_clk_id == SMA1307_PLL_CLKIN_BCLK) {
+ for (i = 0; i < sma1307->num_of_pll_matches; i++) {
+ if (sma1307->pll_matches[i].input_clk == bclk)
+ break;
+ }
+ if (i == sma1307->num_of_pll_matches) {
+ dev_warn(component->dev,
+ "%s: No matching value between pll table and SCK\n",
+ __func__);
+ return;
+ }
+
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A2_TOP_MAN1,
+ SMA1307_PLL_MASK, SMA1307_PLL_ON);
+ }
+
+ regmap_write(sma1307->regmap, SMA1307_8B_PLL_POST_N,
+ sma1307->pll_matches[i].post_n);
+ regmap_write(sma1307->regmap, SMA1307_8C_PLL_N,
+ sma1307->pll_matches[i].n);
+ regmap_write(sma1307->regmap, SMA1307_8D_PLL_A_SETTING,
+ sma1307->pll_matches[i].vco);
+ regmap_write(sma1307->regmap, SMA1307_8E_PLL_P_CP,
+ sma1307->pll_matches[i].p_cp);
+}
+
+static int sma1307_dai_hw_params_amp(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ unsigned int bclk = 0;
+
+ if (sma1307->format == SND_SOC_DAIFMT_DSP_A)
+ bclk = params_rate(params) * sma1307->frame_size;
+ else
+ bclk = params_rate(params) * params_physical_width(params)
+ * params_channels(params);
+
+ dev_dbg(component->dev,
+ "%s: rate = %d : bit size = %d : channel = %d\n",
+ __func__, params_rate(params), params_width(params),
+ params_channels(params));
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (sma1307->sys_clk_id == SMA1307_PLL_CLKIN_BCLK) {
+ if (sma1307->last_bclk != bclk) {
+ sma1307_setup_pll(component, bclk);
+ sma1307->last_bclk = bclk;
+ }
+ }
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 12000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 44100:
+ case 48000:
+ break;
+
+ case 96000:
+ dev_warn(component->dev,
+ "%s: %d rate not support SDO\n", __func__,
+ params_rate(params));
+ break;
+
+ default:
+ dev_err(component->dev, "%s: not support rate : %d\n",
+ __func__, params_rate(params));
+
+ return -EINVAL;
+ }
+
+ /* substream->stream is SNDRV_PCM_STREAM_CAPTURE */
+ } else {
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A4_TOP_MAN3,
+ SMA1307_SCK_RATE_MASK
+ |
+ SMA1307_DATA_WIDTH_MASK,
+ SMA1307_SCK_32FS |
+ SMA1307_DATA_16BIT);
+ break;
+
+ case SNDRV_PCM_FORMAT_S24_LE:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A4_TOP_MAN3,
+ SMA1307_SCK_RATE_MASK
+ |
+ SMA1307_DATA_WIDTH_MASK,
+ SMA1307_SCK_64FS |
+ SMA1307_DATA_24BIT);
+ break;
+
+ case SNDRV_PCM_FORMAT_S32_LE:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A4_TOP_MAN3,
+ SMA1307_SCK_RATE_MASK
+ |
+ SMA1307_DATA_WIDTH_MASK,
+ SMA1307_SCK_64FS |
+ SMA1307_DATA_24BIT);
+ break;
+ default:
+ dev_err(component->dev,
+ "%s: not support data bit : %d\n", __func__,
+ params_format(params));
+ return -EINVAL;
+ }
+ }
+
+ switch (sma1307->format) {
+ case SND_SOC_DAIFMT_I2S:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_I2S_MODE_MASK,
+ SMA1307_STANDARD_I2S);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A4_TOP_MAN3,
+ SMA1307_INTERFACE_MASK,
+ SMA1307_I2S_FORMAT);
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_I2S_MODE_MASK, SMA1307_LJ);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A4_TOP_MAN3,
+ SMA1307_INTERFACE_MASK,
+ SMA1307_LJ_FORMAT);
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ switch (params_width(params)) {
+ case 16:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_I2S_MODE_MASK,
+ SMA1307_RJ_16BIT);
+ break;
+ case 24:
+ case 32:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_I2S_MODE_MASK,
+ SMA1307_RJ_24BIT);
+ break;
+ }
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_I2S_MODE_MASK,
+ SMA1307_STANDARD_I2S);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A4_TOP_MAN3,
+ SMA1307_INTERFACE_MASK,
+ SMA1307_TDM_FORMAT);
+ break;
+ }
+
+ switch (params_width(params)) {
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ dev_err(component->dev,
+ "%s: not support data bit : %d\n", __func__,
+ params_format(params));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sma1307_dai_set_sysclk_amp(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = dai->component;
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ switch (clk_id) {
+ case SMA1307_EXTERNAL_CLOCK_19_2:
+ case SMA1307_EXTERNAL_CLOCK_24_576:
+ case SMA1307_PLL_CLKIN_MCLK:
+ case SMA1307_PLL_CLKIN_BCLK:
+ break;
+ default:
+ dev_err(component->dev, "%s: Invalid clk id: %d\n",
+ __func__, clk_id);
+ return -EINVAL;
+ }
+ sma1307->sys_clk_id = clk_id;
+
+ return 0;
+}
+
+static int sma1307_dai_set_fmt_amp(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+
+ case SND_SOC_DAIFMT_CBC_CFC:
+ dev_dbg(component->dev,
+ "%s: %s\n", __func__, "I2S/TDM Device mode");
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_CONTROLLER_DEVICE_MASK,
+ SMA1307_DEVICE_MODE);
+ break;
+
+ case SND_SOC_DAIFMT_CBP_CFP:
+ dev_dbg(component->dev,
+ "%s: %s\n", __func__, "I2S/TDM Controller mode");
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_CONTROLLER_DEVICE_MASK,
+ SMA1307_CONTROLLER_MODE);
+ break;
+
+ default:
+ dev_err(component->dev,
+ "%s: Unsupported Controller/Device : 0x%x\n",
+ __func__, fmt);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ sma1307->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+ break;
+ default:
+ dev_err(component->dev,
+ "%s: Unsupported Audio Interface Format : 0x%x\n",
+ __func__, fmt);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+
+ case SND_SOC_DAIFMT_IB_NF:
+ dev_dbg(component->dev, "%s: %s\n",
+ __func__, "Invert BCLK + Normal Frame");
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_SCK_RISING_MASK,
+ SMA1307_SCK_RISING_EDGE);
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ dev_dbg(component->dev, "%s: %s\n",
+ __func__, "Invert BCLK + Invert Frame");
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_LEFTPOL_MASK
+ | SMA1307_SCK_RISING_MASK,
+ SMA1307_HIGH_FIRST_CH
+ | SMA1307_SCK_RISING_EDGE);
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ dev_dbg(component->dev, "%s: %s\n",
+ __func__, "Normal BCLK + Invert Frame");
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_LEFTPOL_MASK,
+ SMA1307_HIGH_FIRST_CH);
+ break;
+ case SND_SOC_DAIFMT_NB_NF:
+ dev_dbg(component->dev, "%s: %s\n",
+ __func__, "Normal BCLK + Normal Frame");
+ break;
+ default:
+ dev_err(component->dev,
+ "%s: Unsupported Bit & Frameclock : 0x%x\n",
+ __func__, fmt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sma1307_dai_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ struct snd_soc_component *component = dai->component;
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s: slots = %d, slot_width - %d\n",
+ __func__, slots, slot_width);
+
+ sma1307->frame_size = slot_width * slots;
+
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A4_TOP_MAN3,
+ SMA1307_INTERFACE_MASK, SMA1307_TDM_FORMAT);
+
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A5_TDM1,
+ SMA1307_TDM_TX_MODE_MASK,
+ SMA1307_TDM_TX_MONO);
+
+ switch (slot_width) {
+ case 16:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A6_TDM2,
+ SMA1307_TDM_DL_MASK,
+ SMA1307_TDM_DL_16);
+ break;
+ case 32:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A6_TDM2,
+ SMA1307_TDM_DL_MASK,
+ SMA1307_TDM_DL_32);
+ break;
+ default:
+ dev_err(component->dev, "%s: not support TDM %d slot_width\n",
+ __func__, slot_width);
+ return -EINVAL;
+ }
+
+ switch (slots) {
+ case 4:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A6_TDM2,
+ SMA1307_TDM_N_SLOT_MASK,
+ SMA1307_TDM_N_SLOT_4);
+ break;
+ case 8:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A6_TDM2,
+ SMA1307_TDM_N_SLOT_MASK,
+ SMA1307_TDM_N_SLOT_8);
+ break;
+ default:
+ dev_err(component->dev, "%s: not support TDM %d slots\n",
+ __func__, slots);
+ return -EINVAL;
+ }
+
+ if (sma1307->tdm_slot0_rx < slots)
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A5_TDM1,
+ SMA1307_TDM_SLOT0_RX_POS_MASK,
+ sma1307->tdm_slot0_rx << 3);
+ else
+ dev_err(component->dev, "%s: Incorrect tdm-slot0-rx %d set\n",
+ __func__, sma1307->tdm_slot0_rx);
+
+ if (sma1307->tdm_slot1_rx < slots)
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A5_TDM1,
+ SMA1307_TDM_SLOT1_RX_POS_MASK,
+ sma1307->tdm_slot1_rx);
+ else
+ dev_err(component->dev, "%s: Incorrect tdm-slot1-rx %d set\n",
+ __func__, sma1307->tdm_slot1_rx);
+
+ if (sma1307->tdm_slot0_tx < slots)
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A6_TDM2,
+ SMA1307_TDM_SLOT0_TX_POS_MASK,
+ sma1307->tdm_slot0_tx << 3);
+ else
+ dev_err(component->dev, "%s: Incorrect tdm-slot0-tx %d set\n",
+ __func__, sma1307->tdm_slot0_tx);
+
+ if (sma1307->tdm_slot1_tx < slots)
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A6_TDM2,
+ SMA1307_TDM_SLOT1_TX_POS_MASK,
+ sma1307->tdm_slot1_tx);
+ else
+ dev_err(component->dev, "%s: Incorrect tdm-slot1-tx %d set\n",
+ __func__, sma1307->tdm_slot1_tx);
+
+ return 0;
+}
+
+static int sma1307_dai_mute_stream(struct snd_soc_dai *dai, int mute,
+ int stream)
+{
+ struct snd_soc_component *component = dai->component;
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ if (stream == SNDRV_PCM_STREAM_CAPTURE)
+ return 0;
+ if (mute) {
+ dev_dbg(component->dev, "%s: %s\n", __func__, "MUTE");
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_0E_MUTE_VOL_CTRL,
+ SMA1307_SPK_MUTE_MASK,
+ SMA1307_SPK_MUTE);
+ } else {
+ if (!sma1307->force_mute_status) {
+ dev_dbg(component->dev, "%s: %s\n", __func__,
+ "UNMUTE");
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_0E_MUTE_VOL_CTRL,
+ SMA1307_SPK_MUTE_MASK,
+ SMA1307_SPK_UNMUTE);
+ } else {
+ dev_dbg(sma1307->dev, "%s: FORCE MUTE!!!\n", __func__);
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops sma1307_dai_ops_amp = {
+ .hw_params = sma1307_dai_hw_params_amp,
+ .set_fmt = sma1307_dai_set_fmt_amp,
+ .set_sysclk = sma1307_dai_set_sysclk_amp,
+ .set_tdm_slot = sma1307_dai_set_tdm_slot,
+ .mute_stream = sma1307_dai_mute_stream,
+};
+
+#define SMA1307_RATES_PLAYBACK SNDRV_PCM_RATE_8000_96000
+#define SMA1307_RATES_CAPTURE SNDRV_PCM_RATE_8000_48000
+#define SMA1307_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver sma1307_dai[] = {
+ {
+ .name = "sma1307-amplifier",
+ .id = 0,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SMA1307_RATES_PLAYBACK,
+ .formats = SMA1307_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SMA1307_RATES_CAPTURE,
+ .formats = SMA1307_FORMATS,
+ },
+ .ops = &sma1307_dai_ops_amp,
+ },
+};
+
+static void sma1307_check_fault_worker(struct work_struct *work)
+{
+ struct sma1307_priv *sma1307 =
+ container_of(work, struct sma1307_priv, check_fault_work.work);
+ unsigned int status1_val, status2_val;
+ char *envp[3] = { NULL, NULL, NULL };
+
+ if (sma1307->tsdw_cnt)
+ regmap_read(sma1307->regmap,
+ SMA1307_0A_SPK_VOL, &sma1307->cur_vol);
+ else
+ regmap_read(sma1307->regmap,
+ SMA1307_0A_SPK_VOL, &sma1307->init_vol);
+
+ regmap_read(sma1307->regmap, SMA1307_FA_STATUS1, &status1_val);
+ regmap_read(sma1307->regmap, SMA1307_FB_STATUS2, &status2_val);
+
+ if (~status1_val & SMA1307_OT1_OK_STATUS) {
+ dev_crit(sma1307->dev,
+ "%s: OT1(Over Temperature Level 1)\n", __func__);
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=OT1");
+ if (sma1307->sw_ot1_prot) {
+ /* Volume control (Current Volume -3dB) */
+ if ((sma1307->cur_vol + 6) <= 0xFA) {
+ sma1307->cur_vol += 6;
+ regmap_write(sma1307->regmap,
+ SMA1307_0A_SPK_VOL,
+ sma1307->cur_vol);
+ envp[1] = kasprintf(GFP_KERNEL,
+ "VOLUME=0x%02X", sma1307->cur_vol);
+ }
+ }
+ sma1307->tsdw_cnt++;
+ } else if (sma1307->tsdw_cnt) {
+ regmap_write(sma1307->regmap,
+ SMA1307_0A_SPK_VOL, sma1307->init_vol);
+ sma1307->tsdw_cnt = 0;
+ sma1307->cur_vol = sma1307->init_vol;
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=OT1_CLEAR");
+ envp[1] = kasprintf(GFP_KERNEL,
+ "VOLUME=0x%02X", sma1307->cur_vol);
+ }
+
+ if (~status1_val & SMA1307_OT2_OK_STATUS) {
+ dev_crit(sma1307->dev,
+ "%s: OT2(Over Temperature Level 2)\n", __func__);
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=OT2");
+ }
+ if (status1_val & SMA1307_UVLO_STATUS) {
+ dev_crit(sma1307->dev,
+ "%s: UVLO(Under Voltage Lock Out)\n", __func__);
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=UVLO");
+ }
+ if (status1_val & SMA1307_OVP_BST_STATUS) {
+ dev_crit(sma1307->dev,
+ "%s: OVP_BST(Over Voltage Protection)\n", __func__);
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=OVP_BST");
+ }
+ if (status2_val & SMA1307_OCP_SPK_STATUS) {
+ dev_crit(sma1307->dev,
+ "%s: OCP_SPK(Over Current Protect SPK)\n", __func__);
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=OCP_SPK");
+ }
+ if (status2_val & SMA1307_OCP_BST_STATUS) {
+ dev_crit(sma1307->dev,
+ "%s: OCP_BST(Over Current Protect Boost)\n", __func__);
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=OCP_BST");
+ }
+ if (status2_val & SMA1307_CLK_MON_STATUS) {
+ dev_crit(sma1307->dev,
+ "%s: CLK_FAULT(No clock input)\n", __func__);
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=CLK_FAULT");
+ }
+
+ if (envp[0] != NULL) {
+ if (kobject_uevent_env(sma1307->kobj, KOBJ_CHANGE, envp))
+ dev_err(sma1307->dev,
+ "%s: Error sending uevent\n", __func__);
+ kfree(envp[0]);
+ kfree(envp[1]);
+ }
+
+ if (sma1307->check_fault_status) {
+ if (sma1307->check_fault_period > 0)
+ queue_delayed_work(system_freezable_wq,
+ &sma1307->check_fault_work,
+ sma1307->check_fault_period * HZ);
+ else
+ queue_delayed_work(system_freezable_wq,
+ &sma1307->check_fault_work,
+ CHECK_PERIOD_TIME * HZ);
+ }
+}
+
+static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *file)
+{
+ const struct firmware *fw;
+ int *data, size, offset, num_mode;
+ int ret;
+
+ ret = request_firmware(&fw, file, sma1307->dev);
+
+ if (ret) {
+ dev_err(sma1307->dev, "%s: failed to read \"%s\": %pe\n",
+ __func__, setting_file, ERR_PTR(ret));
+ sma1307->set.status = false;
+ return;
+ } else if ((fw->size) < SMA1307_SETTING_HEADER_SIZE) {
+ dev_err(sma1307->dev, "%s: Invalid file\n", __func__);
+ release_firmware(fw);
+ sma1307->set.status = false;
+ return;
+ }
+
+ data = kzalloc(fw->size, GFP_KERNEL);
+ size = fw->size >> 2;
+ memcpy(data, fw->data, fw->size);
+
+ release_firmware(fw);
+
+ /* HEADER */
+ sma1307->set.header_size = SMA1307_SETTING_HEADER_SIZE;
+ sma1307->set.checksum = data[sma1307->set.header_size - 2];
+ sma1307->set.num_mode = data[sma1307->set.header_size - 1];
+ num_mode = sma1307->set.num_mode;
+ sma1307->set.header = devm_kzalloc(sma1307->dev,
+ sma1307->set.header_size,
+ GFP_KERNEL);
+ memcpy(sma1307->set.header, data,
+ sma1307->set.header_size * sizeof(int));
+
+ if ((sma1307->set.checksum >> 8) != SMA1307_SETTING_CHECKSUM) {
+ dev_err(sma1307->dev, "%s: failed by dismatch \"%s\"\n",
+ __func__, setting_file);
+ sma1307->set.status = false;
+ return;
+ }
+
+ /* DEFAULT */
+ sma1307->set.def_size = SMA1307_SETTING_DEFAULT_SIZE;
+ sma1307->set.def
+ = devm_kzalloc(sma1307->dev,
+ sma1307->set.def_size * sizeof(int), GFP_KERNEL);
+ memcpy(sma1307->set.def,
+ &data[sma1307->set.header_size],
+ sma1307->set.def_size * sizeof(int));
+
+ /* MODE */
+ offset = sma1307->set.header_size + sma1307->set.def_size;
+ sma1307->set.mode_size = DIV_ROUND_CLOSEST(size - offset, num_mode + 1);
+ for (int i = 0; i < num_mode; i++) {
+ sma1307->set.mode_set[i]
+ = devm_kzalloc(sma1307->dev,
+ sma1307->set.mode_size * 2 * sizeof(int),
+ GFP_KERNEL);
+ for (int j = 0; j < sma1307->set.mode_size; j++) {
+ sma1307->set.mode_set[i][2 * j]
+ = data[offset + ((num_mode + 1) * j)];
+ sma1307->set.mode_set[i][2 * j + 1]
+ = data[offset + ((num_mode + 1) * j + i + 1)];
+ }
+ }
+
+ kfree(data);
+ sma1307->set.status = true;
+
+}
+
+static void sma1307_reset(struct snd_soc_component *component)
+{
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ unsigned int status = 0;
+
+ regmap_read(sma1307->regmap, SMA1307_FF_DEVICE_INDEX, &status);
+
+ sma1307->rev_num = status & SMA1307_REV_NUM_STATUS;
+ dev_dbg(component->dev, "%s: SMA1307 Revision %d\n",
+ __func__, sma1307->rev_num);
+ regmap_read(sma1307->regmap, SMA1307_99_OTP_TRM2, &sma1307->otp_trm2);
+ regmap_read(sma1307->regmap, SMA1307_9A_OTP_TRM3, &sma1307->otp_trm3);
+
+ if ((sma1307->otp_trm2 & SMA1307_OTP_STAT_MASK) != SMA1307_OTP_STAT_1)
+ dev_warn(component->dev, "%s: SMA1307 OTP Status Fail\n",
+ __func__);
+
+ /* Register Initial Value Setting */
+ sma1307_setting_loaded(sma1307, setting_file);
+ if (sma1307->set.status)
+ sma1307_set_binary(component);
+ else
+ sma1307_set_default(component);
+
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_93_INT_CTRL,
+ SMA1307_DIS_INT_MASK, SMA1307_HIGH_Z_INT);
+ regmap_write(sma1307->regmap, SMA1307_0A_SPK_VOL, sma1307->init_vol);
+}
+
+static void sma1307_set_binary(struct snd_soc_component *component)
+{
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ int i = 0, mode = 0;
+
+ for (i = 0; i < (sma1307->set.def_size); i++) {
+ if (sma1307_writeable_register(sma1307->dev, i)
+ && ((i < SMA1307_97_OTP_TRM0)
+ || (i > SMA1307_9A_OTP_TRM3))) {
+ regmap_write(sma1307->regmap, i, sma1307->set.def[i]);
+
+ }
+ }
+ for (i = 0; i < (sma1307->set.mode_size); i++) {
+ if (sma1307_writeable_register(sma1307->dev, i)
+ && ((i < SMA1307_97_OTP_TRM0)
+ || (i > SMA1307_9A_OTP_TRM3))) {
+ mode = sma1307->binary_mode;
+ regmap_write(sma1307->regmap,
+ sma1307->set.mode_set[mode][2 * i],
+ sma1307->set.mode_set[mode][2 * i +
+ 1]);
+ }
+ }
+}
+
+static void sma1307_set_default(struct snd_soc_component *component)
+{
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ int i = 0;
+
+ for (i = 0; i < (unsigned int)ARRAY_SIZE(sma1307_reg_def); i++)
+ regmap_write(sma1307->regmap,
+ sma1307_reg_def[i].reg,
+ sma1307_reg_def[i].def);
+
+ if (!strcmp(sma1307->name, DEVICE_NAME_SMA1307AQ))
+ sma1307->data->init(sma1307->regmap);
+}
+
+static int sma1307_probe(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+
+ snd_soc_dapm_sync(dapm);
+
+ sma1307_amp_component = component;
+
+ snd_soc_add_component_controls(component, sma1307_binary_mode_control,
+ ARRAY_SIZE(sma1307_binary_mode_control));
+ sma1307_reset(component);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver sma1307_component = {
+ .probe = sma1307_probe,
+ .controls = sma1307_snd_controls,
+ .num_controls = ARRAY_SIZE(sma1307_snd_controls),
+ .dapm_widgets = sma1307_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sma1307_dapm_widgets),
+ .dapm_routes = sma1307_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(sma1307_audio_map),
+};
+
+static const struct regmap_config sma_i2c_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = SMA1307_FF_DEVICE_INDEX,
+ .readable_reg = sma1307_readable_register,
+ .writeable_reg = sma1307_writeable_register,
+ .volatile_reg = sma1307_volatile_register,
+
+ .reg_defaults = sma1307_reg_def,
+ .num_reg_defaults = ARRAY_SIZE(sma1307_reg_def),
+};
+
+static void sma1307aq_init(struct regmap *regmap)
+{
+ /* Guidelines for driving 4ohm load */
+ /* Brown Out Protection */
+ regmap_write(regmap, SMA1307_02_BROWN_OUT_PROT1, 0x62);
+ regmap_write(regmap, SMA1307_03_BROWN_OUT_PROT2, 0x5D);
+ regmap_write(regmap, SMA1307_04_BROWN_OUT_PROT3, 0x57);
+ regmap_write(regmap, SMA1307_05_BROWN_OUT_PROT8, 0x54);
+ regmap_write(regmap, SMA1307_06_BROWN_OUT_PROT9, 0x51);
+ regmap_write(regmap,
+ SMA1307_07_BROWN_OUT_PROT10, 0x4D);
+ regmap_write(regmap,
+ SMA1307_08_BROWN_OUT_PROT11, 0x4B);
+ regmap_write(regmap, SMA1307_27_BROWN_OUT_PROT4, 0x3C);
+ regmap_write(regmap, SMA1307_28_BROWN_OUT_PROT5, 0x5B);
+ regmap_write(regmap,
+ SMA1307_29_BROWN_OUT_PROT12, 0x78);
+ regmap_write(regmap,
+ SMA1307_2A_BROWN_OUT_PROT13, 0x96);
+ regmap_write(regmap,
+ SMA1307_2B_BROWN_OUT_PROT14, 0xB4);
+ regmap_write(regmap,
+ SMA1307_2C_BROWN_OUT_PROT15, 0xD3);
+ /* FDPEC Gain */
+ regmap_write(regmap, SMA1307_35_FDPEC_CTRL0, 0x16);
+ /* FLT Vdd */
+ regmap_write(regmap, SMA1307_92_FDPEC_CTRL1, 0xA0);
+ /* Boost Max */
+ regmap_write(regmap, SMA1307_AB_BOOST_CTRL4, 0x0F);
+}
+
+static const struct sma1307_data sma1307aq_data = {
+ .name = DEVICE_NAME_SMA1307AQ,
+ .init = sma1307aq_init,
+};
+
+static int sma1307_i2c_probe(struct i2c_client *client)
+{
+ struct sma1307_priv *sma1307;
+ const struct sma1307_data *data;
+ int ret = 0;
+ unsigned int device_info;
+
+ sma1307 = devm_kzalloc(&client->dev,
+ sizeof(*sma1307), GFP_KERNEL);
+ if (!sma1307)
+ return -ENOMEM;
+
+ sma1307->regmap = devm_regmap_init_i2c(client, &sma_i2c_regmap);
+ if (IS_ERR(sma1307->regmap)) {
+ return dev_err_probe(&client->dev, PTR_ERR(sma1307->regmap),
+ "%s: failed to allocate register map\n", __func__);
+ }
+
+ data = device_get_match_data(&client->dev);
+ if (!data)
+ return -ENODEV;
+
+ sma1307->data = data;
+
+ /* set initial value as normal AMP IC status */
+ sma1307->name = client->name;
+ sma1307->format = SND_SOC_DAIFMT_I2S;
+ sma1307->sys_clk_id = SMA1307_PLL_CLKIN_BCLK;
+ sma1307->num_of_pll_matches = ARRAY_SIZE(sma1307_pll_matches);
+
+ sma1307->check_fault_period = CHECK_PERIOD_TIME;
+ sma1307->check_fault_status = true;
+ sma1307->init_vol = 0x32;
+ sma1307->cur_vol = sma1307->init_vol;
+ sma1307->sw_ot1_prot = true;
+
+ mutex_init(&sma1307->default_lock);
+
+ INIT_DELAYED_WORK(&sma1307->check_fault_work,
+ sma1307_check_fault_worker);
+
+ sma1307->dev = &client->dev;
+ sma1307->kobj = &client->dev.kobj;
+
+ i2c_set_clientdata(client, sma1307);
+
+ sma1307->pll_matches = sma1307_pll_matches;
+
+ regmap_read(sma1307->regmap,
+ SMA1307_FF_DEVICE_INDEX, &device_info);
+
+ if ((device_info & 0xF8) != SMA1307_DEVICE_ID) {
+ dev_err(&client->dev,
+ "%s: device initialization error (0x%02X)",
+ __func__, device_info);
+ return -ENODEV;
+ }
+ dev_dbg(&client->dev, "%s: chip version 0x%02X\n",
+ __func__, device_info);
+
+ i2c_set_clientdata(client, sma1307);
+
+ ret = devm_snd_soc_register_component(&client->dev,
+ &sma1307_component, sma1307_dai,
+ 1);
+
+ if (ret) {
+ dev_err(&client->dev, "%s: failed to register component\n",
+ __func__);
+
+ return ret;
+ }
+
+ return ret;
+}
+
+static void sma1307_i2c_remove(struct i2c_client *client)
+{
+ struct sma1307_priv *sma1307 =
+ (struct sma1307_priv *)i2c_get_clientdata(client);
+
+ cancel_delayed_work_sync(&sma1307->check_fault_work);
+}
+
+static const struct i2c_device_id sma1307_i2c_id[] = {
+ { "sma1307a", 0 },
+ { "sma1307aq", 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, sma1307_i2c_id);
+
+static const struct of_device_id sma1307_of_match[] = {
+ {
+ .compatible = "irondevice,sma1307a",
+ },
+ {
+ .compatible = "irondevice,sma1307aq",
+ .data = &sma1307aq_data //AEC-Q100 Qualificated
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, sma1307_of_match);
+
+static struct i2c_driver sma1307_i2c_driver = {
+ .driver = {
+ .name = "sma1307",
+ .of_match_table = sma1307_of_match,
+ },
+ .probe = sma1307_i2c_probe,
+ .remove = sma1307_i2c_remove,
+ .id_table = sma1307_i2c_id,
+};
+
+module_i2c_driver(sma1307_i2c_driver);
+
+MODULE_DESCRIPTION("ALSA SoC SMA1307 driver");
+MODULE_AUTHOR("Gyuhwa Park, <[email protected]>");
+MODULE_AUTHOR("KS Jo, <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sma1307.h b/sound/soc/codecs/sma1307.h
new file mode 100644
index 000000000000..44aab52a32f9
--- /dev/null
+++ b/sound/soc/codecs/sma1307.h
@@ -0,0 +1,444 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * sma1307.h -- sma1307 ALSA SoC Audio driver
+ *
+ * Copyright 2024 Iron Device Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _SMA1307_H
+#define _SMA1307_H
+
+#include <sound/soc.h>
+
+enum sma1307_fault {
+ SMA1307_FAULT_OT1,
+ SMA1307_FAULT_OT2,
+ SMA1307_FAULT_UVLO,
+ SMA1307_FAULT_OVP_BST,
+ SMA1307_FAULT_OCP_SPK,
+ SMA1307_FAULT_OCP_BST,
+ SMA1307_FAULT_CLK
+};
+
+enum sma1307_mode {
+ SMA1307_MONO_MODE,
+ SMA1307_LEFT_MODE,
+ SMA1307_RIGHT_MODE,
+};
+
+enum sma1307_sdo_mode {
+ SMA1307_OUT_DATA_ONE_48K,
+ SMA1307_OUT_DATA_TWO_48K,
+ SMA1307_OUT_DATA_TWO_24K,
+ SMA1307_OUT_CLK_PLL,
+ SMA1307_OUT_CLK_OSC
+};
+
+enum sma1307_sdo_source {
+ SMA1307_OUT_DISABLE,
+ SMA1307_OUT_FORMAT_C,
+ SMA1307_OUT_MIXER_OUT,
+ SMA1307_OUT_AFTER_DSP,
+ SMA1307_OUT_VRMS2_AVG,
+ SMA1307_OUT_BATTERY,
+ SMA1307_OUT_TEMP,
+ SMA1307_OUT_AFTER_DELAY
+};
+
+struct sma1307_setting_file {
+ bool status;
+ char *header;
+ int *def;
+ int *mode_set[5];
+ int checksum;
+ int num_mode;
+ size_t header_size;
+ size_t def_size;
+ size_t mode_size;
+};
+
+#define SMA1307_I2C_ADDR_00 0x1e
+#define SMA1307_I2C_ADDR_01 0x3e
+#define SMA1307_I2C_ADDR_10 0x5e
+#define SMA1307_I2C_ADDR_11 0x7e
+
+#define DEVICE_NAME_SMA1307A "sma1307a"
+#define DEVICE_NAME_SMA1307AQ "sma1307aq"
+
+#define SMA1307_EXTERNAL_CLOCK_19_2 0x00
+#define SMA1307_EXTERNAL_CLOCK_24_576 0x01
+#define SMA1307_PLL_CLKIN_MCLK 0x02
+#define SMA1307_PLL_CLKIN_BCLK 0x03
+
+#define SMA1307_OFFSET_DEFAULT_MODE 0x00
+#define SMA1307_OFFSET_BURNING_MODE 0x01
+
+#define SMA1307_SETTING_HEADER_SIZE 0x08
+#define SMA1307_SETTING_DEFAULT_SIZE 0xC0
+
+#define SMA1307_DEFAULT_SET 0x00
+#define SMA1307_BINARY_FILE_SET 0x01
+
+/* Controls Name */
+#define SMA1307_REG_CTRL_NAME "Register Byte Control"
+#define SMA1307_VOL_CTRL_NAME "Speaker Volume"
+#define SMA1307_FORCE_MUTE_CTRL_NAME "Force Mute Switch"
+#define SMA1307_TDM_RX0_POS_NAME "TDM RX Slot0 Position"
+#define SMA1307_TDM_RX1_POS_NAME "TDM RX Slot1 Position"
+#define SMA1307_TDM_TX0_POS_NAME "TDM TX Slot0 Position"
+#define SMA1307_TDM_TX1_POS_NAME "TDM TX Slot1 Position"
+#define SMA1307_OT1_SW_PROT_CTRL_NAME "OT1 SW Protection Switch"
+#define SMA1307_RESET_CTRL_NAME "Reset Switch"
+#define SMA1307_CHECK_FAULT_STATUS_NAME "Check Fault Status"
+#define SMA1307_CHECK_FAULT_PERIOD_NAME "Check Fault Period"
+
+/* DAPM Name */
+#define SMA1307_AIF_IN_NAME "AIF IN Source"
+#define SMA1307_AIF_OUT0_NAME "AIF OUT0 Source"
+#define SMA1307_AIF_OUT1_NAME "AIF OUT1 Source"
+
+/*
+ * SMA1307 Register Definition
+ */
+
+/* SMA1307 Register Addresses */
+#define SMA1307_00_SYSTEM_CTRL 0x00
+#define SMA1307_01_INPUT_CTRL1 0x01
+#define SMA1307_02_BROWN_OUT_PROT1 0x02
+#define SMA1307_03_BROWN_OUT_PROT2 0x03
+#define SMA1307_04_BROWN_OUT_PROT3 0x04
+#define SMA1307_05_BROWN_OUT_PROT8 0x05
+#define SMA1307_06_BROWN_OUT_PROT9 0x06
+#define SMA1307_07_BROWN_OUT_PROT10 0x07
+#define SMA1307_08_BROWN_OUT_PROT11 0x08
+#define SMA1307_09_OUTPUT_CTRL 0x09
+#define SMA1307_0A_SPK_VOL 0x0A
+#define SMA1307_0B_BST_TEST 0x0B
+#define SMA1307_0C_BOOST_CTRL8 0x0C
+#define SMA1307_0D_SPK_TEST 0x0D
+#define SMA1307_0E_MUTE_VOL_CTRL 0x0E
+#define SMA1307_0F_VBAT_TEMP_SENSING 0x0F
+
+#define SMA1307_10_SYSTEM_CTRL1 0x10
+#define SMA1307_11_SYSTEM_CTRL2 0x11
+#define SMA1307_12_SYSTEM_CTRL3 0x12
+#define SMA1307_13_DELAY 0x13
+#define SMA1307_14_MODULATOR 0x14
+#define SMA1307_15_BASS_SPK1 0x15
+#define SMA1307_16_BASS_SPK2 0x16
+#define SMA1307_17_BASS_SPK3 0x17
+#define SMA1307_18_BASS_SPK4 0x18
+#define SMA1307_19_BASS_SPK5 0x19
+#define SMA1307_1A_BASS_SPK6 0x1A
+#define SMA1307_1B_BASS_SPK7 0x1B
+#define SMA1307_1C_BROWN_OUT_PROT20 0x1C
+#define SMA1307_1D_BROWN_OUT_PROT0 0x1D
+#define SMA1307_1E_TONE_GENERATOR 0x1E
+#define SMA1307_1F_TONE_FINE_VOLUME 0x1F
+
+#define SMA1307_22_COMP_HYS_SEL 0x22
+#define SMA1307_23_COMPLIM1 0x23
+#define SMA1307_24_COMPLIM2 0x24
+#define SMA1307_25_COMPLIM3 0x25
+#define SMA1307_26_COMPLIM4 0x26
+#define SMA1307_27_BROWN_OUT_PROT4 0x27
+#define SMA1307_28_BROWN_OUT_PROT5 0x28
+#define SMA1307_29_BROWN_OUT_PROT12 0x29
+#define SMA1307_2A_BROWN_OUT_PROT13 0x2A
+#define SMA1307_2B_BROWN_OUT_PROT14 0x2B
+#define SMA1307_2C_BROWN_OUT_PROT15 0x2C
+#define SMA1307_2D_BROWN_OUT_PROT6 0x2D
+#define SMA1307_2E_BROWN_OUT_PROT7 0x2E
+#define SMA1307_2F_BROWN_OUT_PROT16 0x2F
+
+#define SMA1307_30_BROWN_OUT_PROT17 0x30
+#define SMA1307_31_BROWN_OUT_PROT18 0x31
+#define SMA1307_32_BROWN_OUT_PROT19 0x32
+#define SMA1307_34_OCP_SPK 0x34
+#define SMA1307_35_FDPEC_CTRL0 0x35
+#define SMA1307_36_PROTECTION 0x36
+#define SMA1307_37_SLOPECTRL 0x37
+#define SMA1307_38_POWER_METER 0x38
+#define SMA1307_39_PMT_NZ_VAL 0x39
+#define SMA1307_3B_TEST1 0x3B
+#define SMA1307_3C_TEST2 0x3C
+#define SMA1307_3D_TEST3 0x3D
+#define SMA1307_3E_IDLE_MODE_CTRL 0x3E
+#define SMA1307_3F_ATEST2 0x3F
+#define SMA1307_8B_PLL_POST_N 0x8B
+#define SMA1307_8C_PLL_N 0x8C
+#define SMA1307_8D_PLL_A_SETTING 0x8D
+#define SMA1307_8E_PLL_P_CP 0x8E
+#define SMA1307_8F_ANALOG_TEST 0x8F
+
+#define SMA1307_90_CRESTLIM1 0x90
+#define SMA1307_91_CRESTLIM2 0x91
+#define SMA1307_92_FDPEC_CTRL1 0x92
+#define SMA1307_93_INT_CTRL 0x93
+#define SMA1307_94_BOOST_CTRL9 0x94
+#define SMA1307_95_BOOST_CTRL10 0x95
+#define SMA1307_96_BOOST_CTRL11 0x96
+#define SMA1307_97_OTP_TRM0 0x97
+#define SMA1307_98_OTP_TRM1 0x98
+#define SMA1307_99_OTP_TRM2 0x99
+#define SMA1307_9A_OTP_TRM3 0x9A
+
+#define SMA1307_A0_PAD_CTRL0 0xA0
+#define SMA1307_A1_PAD_CTRL1 0xA1
+#define SMA1307_A2_TOP_MAN1 0xA2
+#define SMA1307_A3_TOP_MAN2 0xA3
+#define SMA1307_A4_TOP_MAN3 0xA4
+#define SMA1307_A5_TDM1 0xA5
+#define SMA1307_A6_TDM2 0xA6
+#define SMA1307_A7_CLK_MON 0xA7
+#define SMA1307_A8_BOOST_CTRL1 0xA8
+#define SMA1307_A9_BOOST_CTRL2 0xA9
+#define SMA1307_AA_BOOST_CTRL3 0xAA
+#define SMA1307_AB_BOOST_CTRL4 0xAB
+#define SMA1307_AC_BOOST_CTRL5 0xAC
+#define SMA1307_AD_BOOST_CTRL6 0xAD
+#define SMA1307_AE_BOOST_CTRL7 0xAE
+#define SMA1307_AF_LPF 0xAF
+
+#define SMA1307_B0_RMS_TC1 0xB0
+#define SMA1307_B1_RMS_TC2 0xB1
+#define SMA1307_B2_AVG_TC1 0xB2
+#define SMA1307_B3_AVG_TC2 0xB3
+#define SMA1307_B4_PRVALUE1 0xB4
+#define SMA1307_B5_PRVALUE2 0xB5
+#define SMA1307_B8_SPK_NG_CTRL1 0xB8
+#define SMA1307_B9_SPK_NG_CTRL2 0xB9
+#define SMA1307_BA_DGC1 0xBA
+#define SMA1307_BB_DGC2 0xBB
+#define SMA1307_BC_DGC3 0xBC
+#define SMA1307_BD_MCBS_CTRL1 0xBD
+#define SMA1307_BE_MCBS_CTRL2 0xBE
+
+/* Status Register Read Only */
+#define SMA1307_F5_READY_FOR_V_SAR 0xF5
+#define SMA1307_F7_READY_FOR_T_SAR 0xF7
+#define SMA1307_F8_STATUS_T1 0xF8
+#define SMA1307_F9_STATUS_T2 0xF9
+#define SMA1307_FA_STATUS1 0xFA
+#define SMA1307_FB_STATUS2 0xFB
+#define SMA1307_FC_STATUS3 0xFC
+#define SMA1307_FD_STATUS4 0xFD
+#define SMA1307_FE_STATUS5 0xFE
+#define SMA1307_FF_DEVICE_INDEX 0xFF
+
+/* SMA1307 Registers Bit Fields */
+/* Power On/Off */
+#define SMA1307_POWER_MASK BIT(0)
+#define SMA1307_POWER_OFF 0
+#define SMA1307_POWER_ON BIT(0)
+
+/* Reset */
+#define SMA1307_RESET_MASK BIT(1)
+#define SMA1307_RESET_ON BIT(1)
+
+/* Left Polarity */
+#define SMA1307_LEFTPOL_MASK BIT(3)
+#define SMA1307_LOW_FIRST_CH 0
+#define SMA1307_HIGH_FIRST_CH BIT(3)
+
+/* SCK Falling/Rising */
+#define SMA1307_SCK_RISING_MASK BIT(2)
+#define SMA1307_SCK_FALLING_EDGE 0
+#define SMA1307_SCK_RISING_EDGE BIT(2)
+
+/* SPK Mute */
+#define SMA1307_SPK_MUTE_MASK BIT(0)
+#define SMA1307_SPK_UNMUTE 0
+#define SMA1307_SPK_MUTE BIT(0)
+
+/* SPK Mode */
+#define SMA1307_SPK_MODE_MASK (BIT(2)|BIT(3)|BIT(4))
+#define SMA1307_SPK_OFF 0
+#define SMA1307_SPK_MONO BIT(2)
+#define SMA1307_SPK_STEREO BIT(4)
+
+/* Mono Mix */
+#define SMA1307_MONOMIX_MASK BIT(0)
+#define SMA1307_MONOMIX_OFF 0
+#define SMA1307_MONOMIX_ON BIT(0)
+
+/* LR Data Swap */
+#define SMA1307_LR_DATA_SW_MASK BIT(4)
+#define SMA1307_LR_DATA_SW_NORMAL 0
+#define SMA1307_LR_DATA_SW_SWAP BIT(4)
+
+/* PLL On/Off */
+#define SMA1307_PLL_MASK BIT(6)
+#define SMA1307_PLL_ON 0
+#define SMA1307_PLL_OFF BIT(6)
+
+/* Input Format */
+#define SMA1307_I2S_MODE_MASK (BIT(4)|BIT(5)|BIT(6))
+#define SMA1307_STANDARD_I2S 0
+#define SMA1307_LJ BIT(4)
+#define SMA1307_RJ_16BIT BIT(6)
+#define SMA1307_RJ_18BIT (BIT(4)|BIT(6))
+#define SMA1307_RJ_20BIT (BIT(5)|BIT(6))
+#define SMA1307_RJ_24BIT (BIT(4)|BIT(5)|BIT(6))
+
+/* Controller / Device Setting */
+#define SMA1307_CONTROLLER_DEVICE_MASK BIT(7)
+#define SMA1307_DEVICE_MODE 0
+#define SMA1307_CONTROLLER_MODE BIT(7)
+
+/* Port Config */
+#define SMA1307_PORT_CONFIG_MASK (BIT(6)|BIT(7))
+#define SMA1307_INPUT_PORT_ONLY 0
+#define SMA1307_OUTPUT_PORT_ENABLE BIT(7)
+
+/* SDO Output */
+#define SMA1307_SDO_OUTPUT_MASK BIT(3)
+#define SMA1307_LOGIC_OUTPUT 0
+#define SMA1307_HIGH_Z_OUTPUT BIT(3)
+
+#define SMA1307_DATA_CLK_SEL_MASK (BIT(6)|BIT(7))
+#define SMA1307_SDO_DATA 0
+#define SMA1307_SDO_CLK_PLL BIT(6)
+#define SMA1307_SDO_CLK_OSC (BIT(6)|BIT(7))
+
+/* SDO Output2 */
+#define SMA1307_SDO_OUTPUT2_MASK BIT(0)
+#define SMA1307_ONE_SDO_PER_CH 0
+#define SMA1307_TWO_SDO_PER_CH BIT(0)
+
+/* SDO Output3 */
+#define SMA1307_SDO_OUTPUT3_MASK BIT(2)
+#define SMA1307_SDO_OUTPUT3_DIS 0
+#define SMA1307_TWO_SDO_PER_CH_24K BIT(2)
+
+/* SDO OUT1 Select*/
+#define SMA1307_SDO_OUT1_SEL_MASK (BIT(3)|BIT(4)|BIT(5))
+#define SMA1307_SDO1_DISABLE 0
+#define SMA1307_SDO1_FORMAT_C BIT(3)
+#define SMA1307_SDO1_MONO_MIX BIT(4)
+#define SMA1307_SDO1_AFTER_DSP (BIT(3)|BIT(4))
+#define SMA1307_SDO1_VRMS2_AVG BIT(5)
+#define SMA1307_SDO1_VBAT_MON (BIT(3)|BIT(5))
+#define SMA1307_SDO1_TEMP_MON (BIT(4)|BIT(5))
+#define SMA1307_SDO1_AFTER_DELAY (BIT(3)|BIT(4)|BIT(5))
+
+/* SDO OUT0 Select*/
+#define SMA1307_SDO_OUT0_SEL_MASK (BIT(0)|BIT(1)|BIT(2))
+#define SMA1307_SDO0_DISABLE 0
+#define SMA1307_SDO0_FORMAT_C BIT(0)
+#define SMA1307_SDO0_MONO_MIX BIT(1)
+#define SMA1307_SDO0_AFTER_DSP (BIT(0)|BIT(1))
+#define SMA1307_SDO0_VRMS2_AVG BIT(2)
+#define SMA1307_SDO0_VBAT_MON (BIT(0)|BIT(2))
+#define SMA1307_SDO0_TEMP_MON (BIT(1)|BIT(2))
+#define SMA1307_SDO0_AFTER_DELAY (BIT(0)|BIT(1)|BIT(2))
+
+/* INTERRUPT Operation */
+#define SMA1307_SEL_INT_MASK BIT(2)
+#define SMA1307_INT_CLEAR_AUTO 0
+#define SMA1307_INT_CLEAR_MANUAL BIT(2)
+
+/* INTERRUPT CLEAR */
+#define SMA1307_CLR_INT_MASK BIT(1)
+#define SMA1307_INT_READY 0
+#define SMA1307_INT_CLEAR BIT(1)
+
+/* INTERRUPT Disable */
+#define SMA1307_DIS_INT_MASK BIT(0)
+#define SMA1307_NORMAL_INT 0
+#define SMA1307_HIGH_Z_INT BIT(0)
+
+/* Interface Control */
+#define SMA1307_INTERFACE_MASK (BIT(5)|BIT(6)|BIT(7))
+#define SMA1307_LJ_FORMAT BIT(5)
+#define SMA1307_I2S_FORMAT (BIT(5)|BIT(6))
+#define SMA1307_TDM_FORMAT BIT(7)
+
+#define SMA1307_SCK_RATE_MASK (BIT(3)|BIT(4))
+#define SMA1307_SCK_64FS 0
+#define SMA1307_SCK_32FS BIT(4)
+
+#define SMA1307_DATA_WIDTH_MASK (BIT(1)|BIT(2))
+#define SMA1307_DATA_24BIT 0
+#define SMA1307_DATA_16BIT (BIT(1)|BIT(2))
+
+#define SMA1307_TDM_TX_MODE_MASK BIT(6)
+#define SMA1307_TDM_TX_MONO 0
+#define SMA1307_TDM_TX_STEREO BIT(6)
+
+#define SMA1307_TDM_SLOT0_RX_POS_MASK (BIT(3)|BIT(4)|BIT(5))
+#define SMA1307_TDM_SLOT0_RX_POS_0 0
+#define SMA1307_TDM_SLOT0_RX_POS_1 BIT(3)
+#define SMA1307_TDM_SLOT0_RX_POS_2 BIT(4)
+#define SMA1307_TDM_SLOT0_RX_POS_3 (BIT(3)|BIT(4))
+#define SMA1307_TDM_SLOT0_RX_POS_4 BIT(5)
+#define SMA1307_TDM_SLOT0_RX_POS_5 (BIT(3)|BIT(5))
+#define SMA1307_TDM_SLOT0_RX_POS_6 (BIT(4)|BIT(5))
+#define SMA1307_TDM_SLOT0_RX_POS_7 (BIT(3)|BIT(4)|BIT(5))
+
+#define SMA1307_TDM_SLOT1_RX_POS_MASK (BIT(0)|BIT(1)|BIT(2))
+#define SMA1307_TDM_SLOT1_RX_POS_0 0
+#define SMA1307_TDM_SLOT1_RX_POS_1 BIT(0)
+#define SMA1307_TDM_SLOT1_RX_POS_2 BIT(1)
+#define SMA1307_TDM_SLOT1_RX_POS_3 (BIT(0)|BIT(1))
+#define SMA1307_TDM_SLOT1_RX_POS_4 BIT(2)
+#define SMA1307_TDM_SLOT1_RX_POS_5 (BIT(0)|BIT(2))
+#define SMA1307_TDM_SLOT1_RX_POS_6 (BIT(1)|BIT(2))
+#define SMA1307_TDM_SLOT1_RX_POS_7 (BIT(0)|BIT(1)|BIT(2))
+
+/* TDM2 FORMAT : 0xA6 */
+#define SMA1307_TDM_DL_MASK BIT(7)
+#define SMA1307_TDM_DL_16 0
+#define SMA1307_TDM_DL_32 BIT(7)
+
+#define SMA1307_TDM_N_SLOT_MASK BIT(6)
+#define SMA1307_TDM_N_SLOT_4 0
+#define SMA1307_TDM_N_SLOT_8 BIT(6)
+
+#define SMA1307_TDM_SLOT0_TX_POS_MASK (BIT(3)|BIT(4)|BIT(5))
+#define SMA1307_TDM_SLOT0_TX_POS_0 0
+#define SMA1307_TDM_SLOT0_TX_POS_1 BIT(3)
+#define SMA1307_TDM_SLOT0_TX_POS_2 BIT(4)
+#define SMA1307_TDM_SLOT0_TX_POS_3 (BIT(3)|BIT(4))
+#define SMA1307_TDM_SLOT0_TX_POS_4 BIT(5)
+#define SMA1307_TDM_SLOT0_TX_POS_5 (BIT(3)|BIT(5))
+#define SMA1307_TDM_SLOT0_TX_POS_6 (BIT(4)|BIT(5))
+#define SMA1307_TDM_SLOT0_TX_POS_7 (BIT(3)|BIT(4)|BIT(5))
+
+#define SMA1307_TDM_SLOT1_TX_POS_MASK (BIT(0)|BIT(1)|BIT(2))
+#define SMA1307_TDM_SLOT1_TX_POS_0 0
+#define SMA1307_TDM_SLOT1_TX_POS_1 BIT(0)
+#define SMA1307_TDM_SLOT1_TX_POS_2 BIT(1)
+#define SMA1307_TDM_SLOT1_TX_POS_3 (BIT(0)|BIT(1))
+#define SMA1307_TDM_SLOT1_TX_POS_4 BIT(2)
+#define SMA1307_TDM_SLOT1_TX_POS_5 (BIT(0)|BIT(2))
+#define SMA1307_TDM_SLOT1_TX_POS_6 (BIT(1)|BIT(2))
+#define SMA1307_TDM_SLOT1_TX_POS_7 (BIT(0)|BIT(1)|BIT(2))
+
+/* OTP STATUS */
+#define SMA1307_OTP_STAT_MASK BIT(6)
+#define SMA1307_OTP_STAT_0 0
+#define SMA1307_OTP_STAT_1 BIT(6)
+
+/* STATUS */
+#define SMA1307_OT1_OK_STATUS BIT(7)
+#define SMA1307_OT2_OK_STATUS BIT(6)
+#define SMA1307_UVLO_STATUS BIT(5)
+#define SMA1307_OVP_BST_STATUS BIT(4)
+#define SMA1307_POWER_FLAG BIT(3)
+
+#define SMA1307_SCAN_CHK BIT(7)
+#define SMA1307_OCP_SPK_STATUS BIT(5)
+#define SMA1307_OCP_BST_STATUS BIT(4)
+#define SMA1307_BOP_STATE (BIT(1)|BIT(2)|BIT(3))
+#define SMA1307_CLK_MON_STATUS BIT(0)
+
+#define SMA1307_DEVICE_ID (BIT(3)|BIT(4))
+#define SMA1307_REV_NUM_STATUS (BIT(0)|BIT(1))
+#define SMA1307_REV_NUM_REV0 0
+#define SMA1307_REV_NUM_REV1 BIT(0)
+
+#endif
diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c
index 310123d2bb5f..c9766979b1d7 100644
--- a/sound/soc/codecs/spdif_receiver.c
+++ b/sound/soc/codecs/spdif_receiver.c
@@ -36,7 +36,7 @@ static const struct snd_soc_dapm_route dir_routes[] = {
SNDRV_PCM_FMTBIT_S32_LE | \
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
-static struct snd_soc_component_driver soc_codec_spdif_dir = {
+static const struct snd_soc_component_driver soc_codec_spdif_dir = {
.dapm_widgets = dir_widgets,
.num_dapm_widgets = ARRAY_SIZE(dir_widgets),
.dapm_routes = dir_routes,
diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c
index db51a46e689d..2409fd834f84 100644
--- a/sound/soc/codecs/spdif_transmitter.c
+++ b/sound/soc/codecs/spdif_transmitter.c
@@ -36,7 +36,7 @@ static const struct snd_soc_dapm_route dit_routes[] = {
{ "spdif-out", NULL, "Playback" },
};
-static struct snd_soc_component_driver soc_codec_spdif_dit = {
+static const struct snd_soc_component_driver soc_codec_spdif_dit = {
.dapm_widgets = dit_widgets,
.num_dapm_widgets = ARRAY_SIZE(dit_widgets),
.dapm_routes = dit_routes,
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
index 0aeb88abbf52..61d9c220b6a4 100644
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -374,7 +374,7 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw)
out:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(tasdevice_rca_parser, SND_SOC_TAS2781_FMWLIB);
+EXPORT_SYMBOL_NS_GPL(tasdevice_rca_parser, "SND_SOC_TAS2781_FMWLIB");
/* fixed m68k compiling issue: mapping table can save code field */
static unsigned char map_dev_idx(struct tasdevice_fw *tas_fmw,
@@ -862,7 +862,7 @@ void tasdevice_select_cfg_blk(void *pContext, int conf_no,
__func__, length, blk_data[j]->block_size);
}
}
-EXPORT_SYMBOL_NS_GPL(tasdevice_select_cfg_blk, SND_SOC_TAS2781_FMWLIB);
+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)
@@ -1943,7 +1943,7 @@ out:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(tas2781_load_calibration, SND_SOC_TAS2781_FMWLIB);
+EXPORT_SYMBOL_NS_GPL(tas2781_load_calibration, "SND_SOC_TAS2781_FMWLIB");
static int tasdevice_dspfw_ready(const struct firmware *fmw,
void *context)
@@ -2051,7 +2051,7 @@ int tasdevice_dsp_parser(void *context)
out:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(tasdevice_dsp_parser, SND_SOC_TAS2781_FMWLIB);
+EXPORT_SYMBOL_NS_GPL(tasdevice_dsp_parser, "SND_SOC_TAS2781_FMWLIB");
static void tas2781_clear_calfirmware(struct tasdevice_fw *tas_fmw)
{
@@ -2104,7 +2104,7 @@ void tasdevice_calbin_remove(void *context)
tasdev->cali_data_fmw = NULL;
}
}
-EXPORT_SYMBOL_NS_GPL(tasdevice_calbin_remove, SND_SOC_TAS2781_FMWLIB);
+EXPORT_SYMBOL_NS_GPL(tasdevice_calbin_remove, "SND_SOC_TAS2781_FMWLIB");
void tasdevice_config_info_remove(void *context)
{
@@ -2131,7 +2131,7 @@ void tasdevice_config_info_remove(void *context)
}
kfree(ci);
}
-EXPORT_SYMBOL_NS_GPL(tasdevice_config_info_remove, SND_SOC_TAS2781_FMWLIB);
+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)
@@ -2311,8 +2311,7 @@ int tasdevice_select_tuningprm_cfg(void *context, int prm_no,
out:
return prog_status;
}
-EXPORT_SYMBOL_NS_GPL(tasdevice_select_tuningprm_cfg,
- SND_SOC_TAS2781_FMWLIB);
+EXPORT_SYMBOL_NS_GPL(tasdevice_select_tuningprm_cfg, "SND_SOC_TAS2781_FMWLIB");
int tasdevice_prmg_load(void *context, int prm_no)
{
@@ -2357,7 +2356,7 @@ int tasdevice_prmg_load(void *context, int prm_no)
out:
return prog_status;
}
-EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_load, SND_SOC_TAS2781_FMWLIB);
+EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_load, "SND_SOC_TAS2781_FMWLIB");
void tasdevice_tuning_switch(void *context, int state)
{
@@ -2393,8 +2392,7 @@ void tasdevice_tuning_switch(void *context, int state)
TASDEVICE_BIN_BLK_PRE_SHUTDOWN);
}
}
-EXPORT_SYMBOL_NS_GPL(tasdevice_tuning_switch,
- SND_SOC_TAS2781_FMWLIB);
+EXPORT_SYMBOL_NS_GPL(tasdevice_tuning_switch, "SND_SOC_TAS2781_FMWLIB");
MODULE_DESCRIPTION("Texas Firmware Support");
MODULE_AUTHOR("Shenghao Ding, TI, <[email protected]>");
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 12d093437ba9..fb8cd2284fe8 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -370,7 +370,7 @@ static void sngl_calib_start(struct tasdevice_priv *tas_priv, int i,
tasdevice_dev_read(tas_priv, i, p[j].reg,
(int *)&p[j].val[0]);
} else {
- switch (p[j].reg) {
+ switch (tas2781_cali_start_reg[j].reg) {
case 0: {
if (!reg[0])
continue;
@@ -650,7 +650,6 @@ static int tasdev_tf_data_get(struct snd_kcontrol *kcontrol,
(struct soc_bytes_ext *) kcontrol->private_value;
unsigned char *dst = ucontrol->value.bytes.data;
unsigned int reg;
- int rc = -1;
if (tas_priv->chip_id == TAS2781)
reg = TAS2781_RUNTIME_RE_REG_TF;
@@ -659,9 +658,7 @@ static int tasdev_tf_data_get(struct snd_kcontrol *kcontrol,
guard(mutex)(&tas_priv->codec_lock);
dst[0] = bytes_ext->max;
- rc = calib_data_get(tas_priv, reg, &dst[1]);
-
- return rc;
+ return calib_data_get(tas_priv, reg, &dst[1]);
}
static int tasdev_re_data_get(struct snd_kcontrol *kcontrol,
@@ -673,7 +670,6 @@ static int tasdev_re_data_get(struct snd_kcontrol *kcontrol,
(struct soc_bytes_ext *) kcontrol->private_value;
unsigned char *dst = ucontrol->value.bytes.data;
unsigned int reg;
- int rc = -1;
if (tas_priv->chip_id == TAS2781)
reg = TAS2781_RUNTIME_RE_REG;
@@ -681,9 +677,7 @@ static int tasdev_re_data_get(struct snd_kcontrol *kcontrol,
reg = TAS2563_RUNTIME_RE_REG;
guard(mutex)(&tas_priv->codec_lock);
dst[0] = bytes_ext->max;
- rc = calib_data_get(tas_priv, reg, &dst[1]);
-
- return rc;
+ return calib_data_get(tas_priv, reg, &dst[1]);
}
static int tasdev_r0_data_get(struct snd_kcontrol *kcontrol,
@@ -696,7 +690,6 @@ static int tasdev_r0_data_get(struct snd_kcontrol *kcontrol,
(struct soc_bytes_ext *) kcontrol->private_value;
unsigned char *dst = ucontrol->value.bytes.data;
unsigned int reg;
- int rc = -1;
guard(mutex)(&tas_priv->codec_lock);
@@ -707,9 +700,7 @@ static int tasdev_r0_data_get(struct snd_kcontrol *kcontrol,
else
return -1;
dst[0] = bytes_ext->max;
- rc = calib_data_get(tas_priv, reg, &dst[1]);
-
- return rc;
+ return calib_data_get(tas_priv, reg, &dst[1]);
}
static int tasdev_XMA1_data_get(struct snd_kcontrol *kcontrol,
@@ -721,13 +712,10 @@ static int tasdev_XMA1_data_get(struct snd_kcontrol *kcontrol,
(struct soc_bytes_ext *) kcontrol->private_value;
unsigned char *dst = ucontrol->value.bytes.data;
unsigned int reg = TASDEVICE_XM_A1_REG;
- int rc = -1;
guard(mutex)(&tas_priv->codec_lock);
dst[0] = bytes_ext->max;
- rc = calib_data_get(tas_priv, reg, &dst[1]);
-
- return rc;
+ return calib_data_get(tas_priv, reg, &dst[1]);
}
static int tasdev_XMA2_data_get(struct snd_kcontrol *kcontrol,
@@ -739,13 +727,10 @@ static int tasdev_XMA2_data_get(struct snd_kcontrol *kcontrol,
(struct soc_bytes_ext *) kcontrol->private_value;
unsigned char *dst = ucontrol->value.bytes.data;
unsigned int reg = TASDEVICE_XM_A2_REG;
- int rc = -1;
guard(mutex)(&tas_priv->codec_lock);
dst[0] = bytes_ext->max;
- rc = calib_data_get(tas_priv, reg, &dst[1]);
-
- return rc;
+ return calib_data_get(tas_priv, reg, &dst[1]);
}
static int tasdev_nop_get(
@@ -1115,14 +1100,12 @@ static int tasdevice_active_num_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
int dev_id = ucontrol->value.integer.value[0];
- int max = tas_priv->ndev - 1, rc;
+ int max = tas_priv->ndev - 1;
dev_id = clamp(dev_id, 0, max);
guard(mutex)(&tas_priv->codec_lock);
- rc = tasdev_chn_switch(tas_priv, dev_id);
-
- return rc;
+ return tasdev_chn_switch(tas_priv, dev_id);
}
static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv)
@@ -1339,10 +1322,8 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv)
i++;
}
- rc = snd_soc_add_component_controls(priv->codec, cali_ctrls,
+ return snd_soc_add_component_controls(priv->codec, cali_ctrls,
nctrls < i ? nctrls : i);
-
- return rc;
}
static void tasdevice_fw_ready(const struct firmware *fmw,
@@ -1765,4 +1746,4 @@ MODULE_AUTHOR("Shenghao Ding <[email protected]>");
MODULE_AUTHOR("Kevin Lu <[email protected]>");
MODULE_DESCRIPTION("ASoC TAS2781 Driver");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_TAS2781_FMWLIB);
+MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");
diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c
index 3b53eba38a0b..4c32500eef3e 100644
--- a/sound/soc/codecs/tas5805m.c
+++ b/sound/soc/codecs/tas5805m.c
@@ -474,7 +474,7 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c)
return ret;
}
- tas5805m = devm_kzalloc(dev, sizeof(struct tas5805m_priv), GFP_KERNEL);
+ tas5805m = devm_kzalloc(dev, sizeof(*tas5805m), GFP_KERNEL);
if (!tas5805m)
return -ENOMEM;
diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c
index bb0500e9d3ea..9be054837f68 100644
--- a/sound/soc/codecs/tas6424.c
+++ b/sound/soc/codecs/tas6424.c
@@ -364,7 +364,7 @@ static int tas6424_set_bias_level(struct snd_soc_component *component,
return 0;
}
-static struct snd_soc_component_driver soc_codec_dev_tas6424 = {
+static const struct snd_soc_component_driver soc_codec_dev_tas6424 = {
.set_bias_level = tas6424_set_bias_level,
.controls = tas6424_snd_controls,
.num_controls = ARRAY_SIZE(tas6424_snd_controls),
diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c
index 7073b9d1cda8..868e8a91e05b 100644
--- a/sound/soc/codecs/tlv320adc3xxx.c
+++ b/sound/soc/codecs/tlv320adc3xxx.c
@@ -961,7 +961,7 @@ static int adc3xxx_gpio_request(struct gpio_chip *chip, unsigned int offset)
if (offset >= ADC3XXX_GPIOS_MAX)
return -EINVAL;
- if (offset >= 0 && offset < ADC3XXX_GPIO_PINS) {
+ if (offset < ADC3XXX_GPIO_PINS) {
/* GPIO1 is offset 0, GPIO2 is offset 1 */
/* We check here that the GPIO pins are either not configured
* in the DT, or that they purposely are set as outputs.
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 9c50ac356c89..e3782762139f 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -555,7 +555,7 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =
* On unmute: restore the register content from the reg_cache
* Outputs handled in this way: Earpiece, PreDrivL/R, CarkitL/R
*/
-#define TWL4030_OUTPUT_PGA(pin_name, reg, mask) \
+#define TWL4030_OUTPUT_PGA(pin_name, reg) \
static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \
struct snd_kcontrol *kcontrol, int event) \
{ \
@@ -575,11 +575,11 @@ static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \
return 0; \
}
-TWL4030_OUTPUT_PGA(earpiece, TWL4030_REG_EAR_CTL, TWL4030_EAR_GAIN);
-TWL4030_OUTPUT_PGA(predrivel, TWL4030_REG_PREDL_CTL, TWL4030_PREDL_GAIN);
-TWL4030_OUTPUT_PGA(predriver, TWL4030_REG_PREDR_CTL, TWL4030_PREDR_GAIN);
-TWL4030_OUTPUT_PGA(carkitl, TWL4030_REG_PRECKL_CTL, TWL4030_PRECKL_GAIN);
-TWL4030_OUTPUT_PGA(carkitr, TWL4030_REG_PRECKR_CTL, TWL4030_PRECKR_GAIN);
+TWL4030_OUTPUT_PGA(earpiece, TWL4030_REG_EAR_CTL);
+TWL4030_OUTPUT_PGA(predrivel, TWL4030_REG_PREDL_CTL);
+TWL4030_OUTPUT_PGA(predriver, TWL4030_REG_PREDR_CTL);
+TWL4030_OUTPUT_PGA(carkitl, TWL4030_REG_PRECKL_CTL);
+TWL4030_OUTPUT_PGA(carkitr, TWL4030_REG_PRECKR_CTL);
static void handsfree_ramp(struct snd_soc_component *component, int reg, int ramp)
{
diff --git a/sound/soc/codecs/uda1342.c b/sound/soc/codecs/uda1342.c
new file mode 100644
index 000000000000..3d49a7869948
--- /dev/null
+++ b/sound/soc/codecs/uda1342.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// uda1342.c -- UDA1342 ALSA SoC Codec driver
+// Based on the WM87xx drivers by Liam Girdwood and Richard Purdie
+//
+// Copyright 2007 Dension Audio Systems Ltd.
+// Copyright 2024 Loongson Technology Co.,Ltd.
+//
+// Modifications by Christian Pellegrin <[email protected]>
+// Further cleanup and restructuring by:
+// Binbin Zhou <[email protected]>
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "uda1342.h"
+
+#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
+
+struct uda1342_priv {
+ int sysclk;
+ int dai_fmt;
+
+ struct snd_pcm_substream *provider_substream;
+ struct snd_pcm_substream *consumer_substream;
+
+ struct regmap *regmap;
+ struct i2c_client *i2c;
+};
+
+static const struct reg_default uda1342_reg_defaults[] = {
+ { 0x00, 0x1042 },
+ { 0x01, 0x0000 },
+ { 0x10, 0x0088 },
+ { 0x11, 0x0000 },
+ { 0x12, 0x0000 },
+ { 0x20, 0x0080 },
+ { 0x21, 0x0080 },
+};
+
+static int uda1342_mute(struct snd_soc_dai *dai, int mute, int direction)
+{
+ struct snd_soc_component *component = dai->component;
+ struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component);
+ unsigned int mask;
+ unsigned int val = 0;
+
+ /* Master mute */
+ mask = BIT(5);
+ if (mute)
+ val = mask;
+
+ return regmap_update_bits(uda1342->regmap, 0x10, mask, val);
+}
+
+static int uda1342_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component);
+ struct snd_pcm_runtime *provider_runtime;
+
+ if (uda1342->provider_substream) {
+ provider_runtime = uda1342->provider_substream->runtime;
+
+ snd_pcm_hw_constraint_single(substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE, provider_runtime->rate);
+ snd_pcm_hw_constraint_single(substream->runtime,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ provider_runtime->sample_bits);
+
+ uda1342->consumer_substream = substream;
+ } else {
+ uda1342->provider_substream = substream;
+ }
+
+ return 0;
+}
+
+static void uda1342_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component);
+
+ if (uda1342->provider_substream == substream)
+ uda1342->provider_substream = uda1342->consumer_substream;
+
+ uda1342->consumer_substream = NULL;
+}
+
+static int uda1342_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 uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component);
+ struct device *dev = &uda1342->i2c->dev;
+ unsigned int hw_params = 0;
+
+ if (substream == uda1342->consumer_substream)
+ return 0;
+
+ /* set SYSCLK / fs ratio */
+ switch (uda1342->sysclk / params_rate(params)) {
+ case 512:
+ break;
+ case 384:
+ hw_params |= BIT(4);
+ break;
+ case 256:
+ hw_params |= BIT(5);
+ break;
+ default:
+ dev_err(dev, "unsupported frequency\n");
+ return -EINVAL;
+ }
+
+ /* set DAI format and word length */
+ switch (uda1342->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ switch (params_width(params)) {
+ case 16:
+ hw_params |= BIT(1);
+ break;
+ case 18:
+ hw_params |= BIT(2);
+ break;
+ case 20:
+ hw_params |= BIT(2) | BIT(1);
+ break;
+ default:
+ dev_err(dev, "unsupported format (right)\n");
+ return -EINVAL;
+ }
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ hw_params |= BIT(3);
+ break;
+ default:
+ dev_err(dev, "unsupported format\n");
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(uda1342->regmap, 0x0,
+ STATUS0_DAIFMT_MASK | STATUS0_SYSCLK_MASK, hw_params);
+}
+
+static int uda1342_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component);
+ struct device *dev = &uda1342->i2c->dev;
+
+ /*
+ * Anything between 256fs*8Khz and 512fs*48Khz should be acceptable
+ * because the codec is slave. Of course limitations of the clock
+ * master (the IIS controller) apply.
+ * We'll error out on set_hw_params if it's not OK
+ */
+ if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
+ uda1342->sysclk = freq;
+ return 0;
+ }
+
+ dev_err(dev, "unsupported sysclk\n");
+
+ return -EINVAL;
+}
+
+static int uda1342_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component);
+
+ /* codec supports only full consumer mode */
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_BC_FC) {
+ dev_err(&uda1342->i2c->dev, "unsupported consumer mode.\n");
+ return -EINVAL;
+ }
+
+ /* We can't setup DAI format here as it depends on the word bit num */
+ /* so let's just store the value for later */
+ uda1342->dai_fmt = fmt;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new uda1342_snd_controls[] = {
+ SOC_SINGLE("Master Playback Volume", 0x11, 0, 0x3F, 1),
+ SOC_SINGLE("Analog1 Volume", 0x12, 0, 0x1F, 1),
+};
+
+/* Common DAPM widgets */
+static const struct snd_soc_dapm_widget uda1342_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("VINL1"),
+ SND_SOC_DAPM_INPUT("VINR1"),
+ SND_SOC_DAPM_INPUT("VINL2"),
+ SND_SOC_DAPM_INPUT("VINR2"),
+
+ SND_SOC_DAPM_DAC("DAC", "Playback", 0, 1, 0),
+ SND_SOC_DAPM_ADC("ADC", "Capture", 0, 9, 0),
+
+ SND_SOC_DAPM_OUTPUT("VOUTL"),
+ SND_SOC_DAPM_OUTPUT("VOUTR"),
+};
+
+static const struct snd_soc_dapm_route uda1342_dapm_routes[] = {
+ { "ADC", NULL, "VINL1" },
+ { "ADC", NULL, "VINR1" },
+ { "ADC", NULL, "VINL2" },
+ { "ADC", NULL, "VINR2" },
+ { "VOUTL", NULL, "DAC" },
+ { "VOUTR", NULL, "DAC" },
+};
+
+static const struct snd_soc_dai_ops uda1342_dai_ops = {
+ .startup = uda1342_startup,
+ .shutdown = uda1342_shutdown,
+ .hw_params = uda1342_hw_params,
+ .mute_stream = uda1342_mute,
+ .set_sysclk = uda1342_set_dai_sysclk,
+ .set_fmt = uda1342_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver uda1342_dai = {
+ .name = "uda1342-hifi",
+ /* playback capabilities */
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = UDA134X_FORMATS,
+ },
+ /* capture capabilities */
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = UDA134X_FORMATS,
+ },
+ /* pcm operations */
+ .ops = &uda1342_dai_ops,
+};
+
+static const struct snd_soc_component_driver soc_component_dev_uda1342 = {
+ .controls = uda1342_snd_controls,
+ .num_controls = ARRAY_SIZE(uda1342_snd_controls),
+ .dapm_widgets = uda1342_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(uda1342_dapm_widgets),
+ .dapm_routes = uda1342_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(uda1342_dapm_routes),
+ .suspend_bias_off = 1,
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static const struct regmap_config uda1342_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = 0x21,
+ .reg_defaults = uda1342_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(uda1342_reg_defaults),
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static int uda1342_i2c_probe(struct i2c_client *i2c)
+{
+ struct uda1342_priv *uda1342;
+
+ uda1342 = devm_kzalloc(&i2c->dev, sizeof(*uda1342), GFP_KERNEL);
+ if (!uda1342)
+ return -ENOMEM;
+
+ uda1342->regmap = devm_regmap_init_i2c(i2c, &uda1342_regmap);
+ if (IS_ERR(uda1342->regmap))
+ return PTR_ERR(uda1342->regmap);
+
+ i2c_set_clientdata(i2c, uda1342);
+ uda1342->i2c = i2c;
+
+ return devm_snd_soc_register_component(&i2c->dev,
+ &soc_component_dev_uda1342,
+ &uda1342_dai, 1);
+}
+
+static int uda1342_suspend(struct device *dev)
+{
+ struct uda1342_priv *uda1342 = dev_get_drvdata(dev);
+
+ regcache_cache_only(uda1342->regmap, true);
+
+ return 0;
+}
+
+static int uda1342_resume(struct device *dev)
+{
+ struct uda1342_priv *uda1342 = dev_get_drvdata(dev);
+
+ regcache_mark_dirty(uda1342->regmap);
+ regcache_sync(uda1342->regmap);
+
+ return 0;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(uda1342_pm_ops,
+ uda1342_suspend, uda1342_resume, NULL);
+
+static const struct i2c_device_id uda1342_i2c_id[] = {
+ { "uda1342", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, uda1342_i2c_id);
+
+static const struct of_device_id uda1342_of_match[] = {
+ { .compatible = "nxp,uda1342" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, uda1342_of_match);
+
+static struct i2c_driver uda1342_i2c_driver = {
+ .driver = {
+ .name = "uda1342",
+ .of_match_table = uda1342_of_match,
+ .pm = pm_sleep_ptr(&uda1342_pm_ops),
+ },
+ .probe = uda1342_i2c_probe,
+ .id_table = uda1342_i2c_id,
+};
+module_i2c_driver(uda1342_i2c_driver);
+
+MODULE_DESCRIPTION("UDA1342 ALSA soc codec driver");
+MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <[email protected]>");
+MODULE_AUTHOR("Binbin Zhou <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/uda1342.h b/sound/soc/codecs/uda1342.h
new file mode 100644
index 000000000000..ff6aea0a8b01
--- /dev/null
+++ b/sound/soc/codecs/uda1342.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Audio support for NXP UDA1342
+ *
+ * Copyright (c) 2005 Giorgio Padrin <[email protected]>
+ * Copyright (c) 2024 Binbin Zhou <[email protected]>
+ */
+
+#ifndef _UDA1342_H
+#define _UDA1342_H
+
+#define UDA1342_CLK 0x00
+#define UDA1342_IFACE 0x01
+#define UDA1342_PM 0x02
+#define UDA1342_AMIX 0x03
+#define UDA1342_HP 0x04
+#define UDA1342_MVOL 0x11
+#define UDA1342_MIXVOL 0x12
+#define UDA1342_MODE 0x12
+#define UDA1342_DEEMP 0x13
+#define UDA1342_MIXER 0x14
+#define UDA1342_INTSTAT 0x18
+#define UDA1342_DEC 0x20
+#define UDA1342_PGA 0x21
+#define UDA1342_ADC 0x22
+#define UDA1342_AGC 0x23
+#define UDA1342_DECSTAT 0x28
+#define UDA1342_RESET 0x7f
+
+/* Register flags */
+#define R00_EN_ADC 0x0800
+#define R00_EN_DEC 0x0400
+#define R00_EN_DAC 0x0200
+#define R00_EN_INT 0x0100
+#define R00_DAC_CLK 0x0010
+#define R01_SFORI_I2S 0x0000
+#define R01_SFORI_LSB16 0x0100
+#define R01_SFORI_LSB18 0x0200
+#define R01_SFORI_LSB20 0x0300
+#define R01_SFORI_MSB 0x0500
+#define R01_SFORI_MASK 0x0700
+#define R01_SFORO_I2S 0x0000
+#define R01_SFORO_LSB16 0x0001
+#define R01_SFORO_LSB18 0x0002
+#define R01_SFORO_LSB20 0x0003
+#define R01_SFORO_LSB24 0x0004
+#define R01_SFORO_MSB 0x0005
+#define R01_SFORO_MASK 0x0007
+#define R01_SEL_SOURCE 0x0040
+#define R01_SIM 0x0010
+#define R02_PON_PLL 0x8000
+#define R02_PON_HP 0x2000
+#define R02_PON_DAC 0x0400
+#define R02_PON_BIAS 0x0100
+#define R02_EN_AVC 0x0080
+#define R02_PON_AVC 0x0040
+#define R02_PON_LNA 0x0010
+#define R02_PON_PGAL 0x0008
+#define R02_PON_ADCL 0x0004
+#define R02_PON_PGAR 0x0002
+#define R02_PON_ADCR 0x0001
+#define R13_MTM 0x4000
+#define R14_SILENCE 0x0080
+#define R14_SDET_ON 0x0040
+#define R21_MT_ADC 0x8000
+#define R22_SEL_LNA 0x0008
+#define R22_SEL_MIC 0x0004
+#define R22_SKIP_DCFIL 0x0002
+#define R23_AGC_EN 0x0001
+
+#define UDA1342_DAI_DUPLEX 0 /* playback and capture on single DAI */
+#define UDA1342_DAI_PLAYBACK 1 /* playback DAI */
+#define UDA1342_DAI_CAPTURE 2 /* capture DAI */
+
+#define STATUS0_DAIFMT_MASK (~(7 << 1))
+#define STATUS0_SYSCLK_MASK (~(3 << 4))
+
+#endif /* _UDA1342_H */
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 373a31ddccb2..a2521e16c099 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -5177,4 +5177,3 @@ static struct slim_driver wcd9335_slim_driver = {
module_slim_driver(wcd9335_slim_driver);
MODULE_DESCRIPTION("WCD9335 slim driver");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("slim:217:1a0:*");
diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c
index 08fb13a334a4..c9d5e67bf66e 100644
--- a/sound/soc/codecs/wcd937x.c
+++ b/sound/soc/codecs/wcd937x.c
@@ -7,7 +7,6 @@
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index e69283195f36..91c8697c29c3 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -2098,4 +2098,4 @@ static const struct cs_dsp_client_ops wm_adsp2_client_ops = {
MODULE_DESCRIPTION("Cirrus Logic ASoC DSP Support");
MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(FW_CS_DSP);
+MODULE_IMPORT_NS("FW_CS_DSP");