summaryrefslogtreecommitdiff
path: root/sound/soc/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/Kconfig61
-rw-r--r--sound/soc/codecs/Makefile6
-rw-r--r--sound/soc/codecs/ab8500-codec.c12
-rw-r--r--sound/soc/codecs/ad1836.c6
-rw-r--r--sound/soc/codecs/ad193x.c10
-rw-r--r--sound/soc/codecs/adau1761.c34
-rw-r--r--sound/soc/codecs/adau7118-hw.c2
-rw-r--r--sound/soc/codecs/adav80x.c8
-rw-r--r--sound/soc/codecs/ak4613.c83
-rw-r--r--sound/soc/codecs/arizona-jack.c117
-rw-r--r--sound/soc/codecs/arizona.c26
-rw-r--r--sound/soc/codecs/aw87390.c17
-rw-r--r--sound/soc/codecs/aw88081.c27
-rw-r--r--sound/soc/codecs/aw88166.c32
-rw-r--r--sound/soc/codecs/aw88261.c35
-rw-r--r--sound/soc/codecs/aw88261.h6
-rw-r--r--sound/soc/codecs/aw88395/aw88395.c32
-rw-r--r--sound/soc/codecs/aw88395/aw88395_device.c40
-rw-r--r--sound/soc/codecs/aw88399-lib.c1409
-rw-r--r--sound/soc/codecs/aw88399.c1358
-rw-r--r--sound/soc/codecs/aw88399.h582
-rw-r--r--sound/soc/codecs/bt-sco.c10
-rw-r--r--sound/soc/codecs/cpcap.c130
-rw-r--r--sound/soc/codecs/cros_ec_codec.c26
-rw-r--r--sound/soc/codecs/cs-amp-lib.c11
-rw-r--r--sound/soc/codecs/cs35l32.c10
-rw-r--r--sound/soc/codecs/cs35l33.c14
-rw-r--r--sound/soc/codecs/cs35l34.c14
-rw-r--r--sound/soc/codecs/cs35l56-i2c.c10
-rw-r--r--sound/soc/codecs/cs35l56-sdw.c71
-rw-r--r--sound/soc/codecs/cs35l56-shared.c69
-rw-r--r--sound/soc/codecs/cs35l56-spi.c10
-rw-r--r--sound/soc/codecs/cs35l56.c58
-rw-r--r--sound/soc/codecs/cs35l56.h11
-rw-r--r--sound/soc/codecs/cs40l50-codec.c4
-rw-r--r--sound/soc/codecs/cs42l42-sdw.c14
-rw-r--r--sound/soc/codecs/cs42l42.c54
-rw-r--r--sound/soc/codecs/cs42l43-jack.c138
-rw-r--r--sound/soc/codecs/cs42l43.c20
-rw-r--r--sound/soc/codecs/cs42l84.c10
-rw-r--r--sound/soc/codecs/cs43130.c72
-rw-r--r--sound/soc/codecs/cs4349.c8
-rw-r--r--sound/soc/codecs/cs47l15.c11
-rw-r--r--sound/soc/codecs/cs47l35.c11
-rw-r--r--sound/soc/codecs/cs47l85.c11
-rw-r--r--sound/soc/codecs/cs47l90.c11
-rw-r--r--sound/soc/codecs/cs47l92.c11
-rw-r--r--sound/soc/codecs/cs48l32.c26
-rw-r--r--sound/soc/codecs/cx2072x.c127
-rw-r--r--sound/soc/codecs/da7213.c37
-rw-r--r--sound/soc/codecs/da7219.c62
-rw-r--r--sound/soc/codecs/es8316.c44
-rw-r--r--sound/soc/codecs/es8326.c30
-rw-r--r--sound/soc/codecs/es8328.c5
-rw-r--r--sound/soc/codecs/es8389.c236
-rw-r--r--sound/soc/codecs/es8389.h11
-rw-r--r--sound/soc/codecs/es9356.c33
-rw-r--r--sound/soc/codecs/fs-amp-lib.c3
-rw-r--r--sound/soc/codecs/fs210x.c89
-rw-r--r--sound/soc/codecs/hdac_hda.c7
-rw-r--r--sound/soc/codecs/hdac_hdmi.c127
-rw-r--r--sound/soc/codecs/hdmi-codec.c15
-rw-r--r--sound/soc/codecs/idt821034.c144
-rw-r--r--sound/soc/codecs/lochnagar-sc.c8
-rw-r--r--sound/soc/codecs/lpass-macro-common.c12
-rw-r--r--sound/soc/codecs/lpass-rx-macro.c137
-rw-r--r--sound/soc/codecs/lpass-tx-macro.c128
-rw-r--r--sound/soc/codecs/lpass-va-macro.c137
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.c138
-rw-r--r--sound/soc/codecs/madera.c51
-rw-r--r--sound/soc/codecs/max98090.c9
-rw-r--r--sound/soc/codecs/max98095.c35
-rw-r--r--sound/soc/codecs/max98363.c7
-rw-r--r--sound/soc/codecs/max98373-i2c.c9
-rw-r--r--sound/soc/codecs/max98373-sdw.c7
-rw-r--r--sound/soc/codecs/max98388.c8
-rw-r--r--sound/soc/codecs/max98390.c24
-rw-r--r--sound/soc/codecs/max98396.c24
-rw-r--r--sound/soc/codecs/max9860.c2
-rw-r--r--sound/soc/codecs/max98927.c8
-rw-r--r--sound/soc/codecs/ml26124.c4
-rw-r--r--sound/soc/codecs/msm8916-wcd-analog.c144
-rw-r--r--sound/soc/codecs/mt6357.c4
-rw-r--r--sound/soc/codecs/mt6359-accdet.c13
-rw-r--r--sound/soc/codecs/ntpfw.c21
-rw-r--r--sound/soc/codecs/ntpfw.h11
-rw-r--r--sound/soc/codecs/pcm1681.c7
-rw-r--r--sound/soc/codecs/pcm1754.c6
-rw-r--r--sound/soc/codecs/pcm1789.c7
-rw-r--r--sound/soc/codecs/pcm179x.c6
-rw-r--r--sound/soc/codecs/pcm186x.c9
-rw-r--r--sound/soc/codecs/pcm3060.c8
-rw-r--r--sound/soc/codecs/pcm512x.c68
-rw-r--r--sound/soc/codecs/pcm6240.c41
-rw-r--r--sound/soc/codecs/peb2466.c23
-rw-r--r--sound/soc/codecs/pm4125-sdw.c10
-rw-r--r--sound/soc/codecs/pm4125.c3
-rw-r--r--sound/soc/codecs/rt1017-sdca-sdw.c7
-rw-r--r--sound/soc/codecs/rt1017-sdca-sdw.h10
-rw-r--r--sound/soc/codecs/rt1316-sdw.c9
-rw-r--r--sound/soc/codecs/rt1318-sdw.c9
-rw-r--r--sound/soc/codecs/rt1318.c4
-rw-r--r--sound/soc/codecs/rt1320-sdw.c882
-rw-r--r--sound/soc/codecs/rt1320-sdw.h19
-rw-r--r--sound/soc/codecs/rt274.c8
-rw-r--r--sound/soc/codecs/rt286.c12
-rw-r--r--sound/soc/codecs/rt298.c12
-rw-r--r--sound/soc/codecs/rt5514-spi.c21
-rw-r--r--sound/soc/codecs/rt5514.c16
-rw-r--r--sound/soc/codecs/rt5575-spi.c3
-rw-r--r--sound/soc/codecs/rt5645.c176
-rw-r--r--sound/soc/codecs/rt5665.c15
-rw-r--r--sound/soc/codecs/rt5668.c10
-rw-r--r--sound/soc/codecs/rt5677-spi.c36
-rw-r--r--sound/soc/codecs/rt5677.c100
-rw-r--r--sound/soc/codecs/rt5682-sdw.c44
-rw-r--r--sound/soc/codecs/rt5682.c5
-rw-r--r--sound/soc/codecs/rt5682s.c17
-rw-r--r--sound/soc/codecs/rt700-sdw.c20
-rw-r--r--sound/soc/codecs/rt700-sdw.h11
-rw-r--r--sound/soc/codecs/rt711-sdca-sdw.c29
-rw-r--r--sound/soc/codecs/rt711-sdca-sdw.h6
-rw-r--r--sound/soc/codecs/rt711-sdca.c5
-rw-r--r--sound/soc/codecs/rt711-sdw.c24
-rw-r--r--sound/soc/codecs/rt711-sdw.h10
-rw-r--r--sound/soc/codecs/rt711.c50
-rw-r--r--sound/soc/codecs/rt712-sdca-dmic.c17
-rw-r--r--sound/soc/codecs/rt712-sdca-dmic.h6
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.c45
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.h11
-rw-r--r--sound/soc/codecs/rt712-sdca.c5
-rw-r--r--sound/soc/codecs/rt715-sdca-sdw.h12
-rw-r--r--sound/soc/codecs/rt715-sdw.h32
-rw-r--r--sound/soc/codecs/rt721-sdca-sdw.c44
-rw-r--r--sound/soc/codecs/rt721-sdca-sdw.h28
-rw-r--r--sound/soc/codecs/rt721-sdca.c5
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.c37
-rw-r--r--sound/soc/codecs/rt722-sdca.c16
-rw-r--r--sound/soc/codecs/rt766-sdca-sdw.c339
-rw-r--r--sound/soc/codecs/rt766-sdca-sdw.h61
-rw-r--r--sound/soc/codecs/rt766-sdca.c1378
-rw-r--r--sound/soc/codecs/rt766-sdca.h140
-rw-r--r--sound/soc/codecs/rt9120.c9
-rw-r--r--sound/soc/codecs/sgtl5000.c2
-rw-r--r--sound/soc/codecs/sigmadsp.c30
-rw-r--r--sound/soc/codecs/sma1303.c2
-rw-r--r--sound/soc/codecs/sma1307.c6
-rw-r--r--sound/soc/codecs/sta32x.c21
-rw-r--r--sound/soc/codecs/sta350.c20
-rw-r--r--sound/soc/codecs/sti-sas.c2
-rw-r--r--sound/soc/codecs/tac5xx2-sdw.c90
-rw-r--r--sound/soc/codecs/tas2552.c24
-rw-r--r--sound/soc/codecs/tas2764.c2
-rw-r--r--sound/soc/codecs/tas2780.c2
-rw-r--r--sound/soc/codecs/tas2781-comlib-i2c.c5
-rw-r--r--sound/soc/codecs/tas2781-fmwlib.c65
-rw-r--r--sound/soc/codecs/tas2781-i2c.c253
-rw-r--r--sound/soc/codecs/tas2783-sdw.c310
-rw-r--r--sound/soc/codecs/tas5805m.c30
-rw-r--r--sound/soc/codecs/tas675x.c18
-rw-r--r--sound/soc/codecs/tlv320aic26.c6
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c8
-rw-r--r--sound/soc/codecs/tlv320aic32x4-clk.c68
-rw-r--r--sound/soc/codecs/tlv320aic32x4-i2c.c21
-rw-r--r--sound/soc/codecs/tlv320aic32x4-spi.c25
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c480
-rw-r--r--sound/soc/codecs/tlv320aic32x4.h32
-rw-r--r--sound/soc/codecs/tlv320dac33.c87
-rw-r--r--sound/soc/codecs/tscs42xx.c61
-rw-r--r--sound/soc/codecs/tscs454.c107
-rw-r--r--sound/soc/codecs/twl6040.c5
-rw-r--r--sound/soc/codecs/uda1342.c9
-rw-r--r--sound/soc/codecs/wcd9335.c4
-rw-r--r--sound/soc/codecs/wcd934x.c48
-rw-r--r--sound/soc/codecs/wcd937x-sdw.c8
-rw-r--r--sound/soc/codecs/wcd937x.c25
-rw-r--r--sound/soc/codecs/wcd938x-sdw.c8
-rw-r--r--sound/soc/codecs/wcd938x.c22
-rw-r--r--sound/soc/codecs/wcd939x-sdw.c8
-rw-r--r--sound/soc/codecs/wcd939x.c20
-rw-r--r--sound/soc/codecs/wm0010.c86
-rw-r--r--sound/soc/codecs/wm2000.c35
-rw-r--r--sound/soc/codecs/wm2200.c10
-rw-r--r--sound/soc/codecs/wm5100.c10
-rw-r--r--sound/soc/codecs/wm5102.c23
-rw-r--r--sound/soc/codecs/wm8731.c9
-rw-r--r--sound/soc/codecs/wm8903.c9
-rw-r--r--sound/soc/codecs/wm8940.c2
-rw-r--r--sound/soc/codecs/wm8958-dsp2.c10
-rw-r--r--sound/soc/codecs/wm8962.c22
-rw-r--r--sound/soc/codecs/wm8994.c30
-rw-r--r--sound/soc/codecs/wm9712.c5
-rw-r--r--sound/soc/codecs/wm9713.c5
-rw-r--r--sound/soc/codecs/wm_adsp.c77
-rw-r--r--sound/soc/codecs/wsa881x.c8
-rw-r--r--sound/soc/codecs/wsa883x.c19
-rw-r--r--sound/soc/codecs/wsa884x.c18
-rw-r--r--sound/soc/codecs/wsa885x.c1533
-rw-r--r--sound/soc/codecs/zl38060.c11
199 files changed, 9123 insertions, 5335 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index e4d139108d72..f9a47e262a77 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -238,6 +238,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RT715_SDCA_SDW
imply SND_SOC_RT721_SDCA_SDW
imply SND_SOC_RT722_SDCA_SDW
+ imply SND_SOC_RT766_SDCA_SDW
imply SND_SOC_RT1308_SDW
imply SND_SOC_RT1316_SDW
imply SND_SOC_RT1318
@@ -367,6 +368,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_WSA881X
imply SND_SOC_WSA883X
imply SND_SOC_WSA884X
+ imply SND_SOC_WSA885X
imply SND_SOC_ZL38060
help
Normally ASoC codec drivers are only built if a machine driver which
@@ -615,8 +617,8 @@ config SND_SOC_AK4613
depends on I2C
config SND_SOC_AK4619
- tristate "AKM AK4619 CODEC"
- depends on I2C
+ tristate "AKM AK4619 CODEC"
+ depends on I2C
config SND_SOC_AK4642
tristate "AKM AK4642 CODEC"
@@ -726,6 +728,10 @@ config SND_SOC_AW87390
sound quality, which is a new high efficiency, low
noise, constant large volume, 6th Smart K audio amplifier.
+config SND_SOC_AW88399_LIB
+ tristate
+ select SND_SOC_AW88395_LIB
+
config SND_SOC_AW88399
tristate "Soc Audio for awinic aw88399"
depends on I2C
@@ -733,6 +739,7 @@ config SND_SOC_AW88399
select REGMAP_I2C
select GPIOLIB
select SND_SOC_AW88395_LIB
+ select SND_SOC_AW88399_LIB
help
This option enables support for aw88399 Smart PA.
The awinic AW88399 is an I2S/TDM input, high efficiency
@@ -889,6 +896,7 @@ config SND_SOC_CS35L56_SDW
tristate "Cirrus Logic CS35L56 CODEC (SDW)"
depends on SOUNDWIRE
select REGMAP_SOUNDWIRE
+ select IRQ_DOMAIN
select SND_SOC_CS35L56
select SND_SOC_CS35L56_SHARED
help
@@ -1201,16 +1209,16 @@ config SND_SOC_JZ4725B_CODEC
will be called snd-soc-jz4725b-codec.
config SND_SOC_JZ4760_CODEC
- depends on MACH_INGENIC || COMPILE_TEST
- depends on OF
- select REGMAP
- tristate "Ingenic JZ4760 internal CODEC"
- help
- Enable support for the internal CODEC found in the JZ4760 SoC
- from Ingenic.
+ depends on MACH_INGENIC || COMPILE_TEST
+ depends on OF
+ select REGMAP
+ tristate "Ingenic JZ4760 internal CODEC"
+ help
+ Enable support for the internal CODEC found in the JZ4760 SoC
+ from Ingenic.
- This driver can also be built as a module. If so, the module
- will be called snd-soc-jz4760-codec.
+ This driver can also be built as a module. If so, the module
+ will be called snd-soc-jz4760-codec.
config SND_SOC_JZ4770_CODEC
depends on MACH_INGENIC || COMPILE_TEST
@@ -1888,7 +1896,7 @@ config SND_SOC_RT5670
depends on I2C
config SND_SOC_RT5677
- tristate
+ tristate "Realtek RT5677 Codec"
depends on I2C
select REGMAP_I2C
select REGMAP_IRQ
@@ -1978,6 +1986,15 @@ config SND_SOC_RT715_SDCA_SDW
select REGMAP_SOUNDWIRE
select REGMAP_SOUNDWIRE_MBQ
+config SND_SOC_RT766_SDCA_SDW
+ tristate "Realtek RT766 SDCA Codec - SDW"
+ depends on SOUNDWIRE
+ depends on SND_SOC_SDCA
+ select SND_SOC_SDCA_HID
+ select SND_SOC_SDCA_IRQ
+ select REGMAP_SOUNDWIRE
+ select REGMAP_SOUNDWIRE_MBQ
+
config SND_SOC_RT9120
tristate "Richtek RT9120 Stereo Class-D Amplifier"
depends on I2C
@@ -2297,8 +2314,8 @@ config SND_SOC_TLV320ADC3XXX
depends on I2C
depends on GPIOLIB
help
- Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101
- ADCs.
+ Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101
+ ADCs.
config SND_SOC_TLV320AIC23
tristate
@@ -2771,6 +2788,16 @@ config SND_SOC_WSA884X
This enables support for Qualcomm WSA8840/WSA8845/WSA8845H Class-D
Smart Speaker Amplifier.
+config SND_SOC_WSA885X
+ tristate "WSA885X Codec"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This enables support for Qualcomm WSA885X Stereo Smart Speaker
+ Amplifier. The codec driver programs the amplifier register
+ map and exposes the DAI and mixer controls used by Qualcomm
+ audio machine drivers.
+
config SND_SOC_ZL38060
tristate "Microsemi ZL38060 Connected Home Audio Processor"
depends on SPI_MASTER
@@ -2894,28 +2921,32 @@ config SND_SOC_TPA6130A2
depends on I2C
config SND_SOC_LPASS_MACRO_COMMON
- tristate
+ tristate
config SND_SOC_LPASS_WSA_MACRO
depends on COMMON_CLK
+ depends on PM_CLK
select REGMAP_MMIO
select SND_SOC_LPASS_MACRO_COMMON
tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)"
config SND_SOC_LPASS_VA_MACRO
depends on COMMON_CLK
+ depends on PM_CLK
select REGMAP_MMIO
select SND_SOC_LPASS_MACRO_COMMON
tristate "Qualcomm VA Macro in LPASS(Low Power Audio SubSystem)"
config SND_SOC_LPASS_RX_MACRO
depends on COMMON_CLK
+ depends on PM_CLK
select REGMAP_MMIO
select SND_SOC_LPASS_MACRO_COMMON
tristate "Qualcomm RX Macro in LPASS(Low Power Audio SubSystem)"
config SND_SOC_LPASS_TX_MACRO
depends on COMMON_CLK
+ depends on PM_CLK
select REGMAP_MMIO
select SND_SOC_LPASS_MACRO_COMMON
tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)"
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index aa0396e5b575..3d122ace75ad 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -55,6 +55,7 @@ snd-soc-aw88395-y := aw88395/aw88395.o
snd-soc-aw88166-y := aw88166.o
snd-soc-aw88261-y := aw88261.o
snd-soc-aw88399-y := aw88399.o
+snd-soc-aw88399-lib-y := aw88399-lib.o
snd-soc-bd28623-y := bd28623.o
snd-soc-bt-sco-y := bt-sco.o
snd-soc-chv3-codec-y := chv3-codec.o
@@ -284,6 +285,7 @@ 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-rt766-sdca-y := rt766-sdca.o rt766-sdca-sdw.o
snd-soc-rt9120-y := rt9120.o
snd-soc-rt9123-y := rt9123.o
snd-soc-rt9123p-y := rt9123p.o
@@ -426,6 +428,7 @@ snd-soc-wm-hubs-y := wm_hubs.o
snd-soc-wsa881x-y := wsa881x.o
snd-soc-wsa883x-y := wsa883x.o
snd-soc-wsa884x-y := wsa884x.o
+snd-soc-wsa885x-y := wsa885x.o
snd-soc-zl38060-y := zl38060.o
# Amp
snd-soc-max9877-y := max9877.o
@@ -496,6 +499,7 @@ obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o
obj-$(CONFIG_SND_SOC_AW88166) +=snd-soc-aw88166.o
obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o
obj-$(CONFIG_SND_SOC_AW88399) += snd-soc-aw88399.o
+obj-$(CONFIG_SND_SOC_AW88399_LIB) += snd-soc-aw88399-lib.o
obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
obj-$(CONFIG_SND_SOC_CHV3_CODEC) += snd-soc-chv3-codec.o
@@ -724,6 +728,7 @@ 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_RT766_SDCA_SDW) += snd-soc-rt766-sdca.o
obj-$(CONFIG_SND_SOC_RT9120) += snd-soc-rt9120.o
obj-$(CONFIG_SND_SOC_RT9123) += snd-soc-rt9123.o
obj-$(CONFIG_SND_SOC_RT9123P) += snd-soc-rt9123p.o
@@ -876,6 +881,7 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o
obj-$(CONFIG_SND_SOC_WSA883X) += snd-soc-wsa883x.o
obj-$(CONFIG_SND_SOC_WSA884X) += snd-soc-wsa884x.o
+obj-$(CONFIG_SND_SOC_WSA885X) += snd-soc-wsa885x.o
obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o
# Amp
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 6e8ef9cd1b31..2cf96cbdd294 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -14,6 +14,7 @@
* for ST-Ericsson.
*/
+#include <linux/cleanup.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -989,9 +990,8 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
- mutex_lock(&drvdata->ctrl_lock);
+ guard(mutex)(&drvdata->ctrl_lock);
ucontrol->value.enumerated.item[0] = drvdata->sid_status;
- mutex_unlock(&drvdata->ctrl_lock);
return 0;
}
@@ -1014,7 +1014,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
return -EIO;
}
- mutex_lock(&drvdata->ctrl_lock);
+ guard(mutex)(&drvdata->ctrl_lock);
sidconf = snd_soc_component_read(component, AB8500_SIDFIRCONF);
if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) {
@@ -1025,7 +1025,8 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
} else {
status = -EBUSY;
}
- goto out;
+ dev_dbg(component->dev, "%s: Exit\n", __func__);
+ return status;
}
snd_soc_component_write(component, AB8500_SIDFIRADR, 0);
@@ -1043,9 +1044,6 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
drvdata->sid_status = SID_FIR_CONFIGURED;
-out:
- mutex_unlock(&drvdata->ctrl_lock);
-
dev_dbg(component->dev, "%s: Exit\n", __func__);
return status;
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index 8afeadcaf8b0..dbea83bd49b6 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -193,9 +193,15 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static const u64 ad1836_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
static const struct snd_soc_dai_ops ad1836_dai_ops = {
.hw_params = ad1836_hw_params,
.set_fmt = ad1836_set_dai_fmt,
+ .auto_selectable_formats = &ad1836_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
#define AD183X_DAI(_name, num_dacs, num_adcs) \
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index b93531c3a9a4..9841c779b175 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -394,6 +394,14 @@ static int ad193x_startup(struct snd_pcm_substream *substream,
&constr);
}
+static const u64 ad193x_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_NB_IF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
static const struct snd_soc_dai_ops ad193x_dai_ops = {
.startup = ad193x_startup,
.hw_params = ad193x_hw_params,
@@ -401,6 +409,8 @@ static const struct snd_soc_dai_ops ad193x_dai_ops = {
.set_tdm_slot = ad193x_set_tdm_slot,
.set_sysclk = ad193x_set_dai_sysclk,
.set_fmt = ad193x_set_dai_fmt,
+ .auto_selectable_formats = &ad193x_selectable_formats,
+ .num_auto_selectable_formats = 1,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c
index a70c46dd5d76..27ce03b0fb91 100644
--- a/sound/soc/codecs/adau1761.c
+++ b/sound/soc/codecs/adau1761.c
@@ -68,23 +68,33 @@
#define ADAU1761_FIRMWARE "adau1761.bin"
static const struct reg_default adau1761_reg_defaults[] = {
- { ADAU1761_DEJITTER, 0x03 },
+ { ADAU17X1_CLOCK_CONTROL, 0x00 },
+ { ADAU17X1_PLL_CONTROL, 0x00 },
{ ADAU1761_DIGMIC_JACKDETECT, 0x00 },
+ { ADAU17X1_REC_POWER_MGMT, 0x00 },
{ ADAU1761_REC_MIXER_LEFT0, 0x00 },
{ ADAU1761_REC_MIXER_LEFT1, 0x00 },
{ ADAU1761_REC_MIXER_RIGHT0, 0x00 },
{ ADAU1761_REC_MIXER_RIGHT1, 0x00 },
{ ADAU1761_LEFT_DIFF_INPUT_VOL, 0x00 },
+ { ADAU1761_RIGHT_DIFF_INPUT_VOL, 0x00 },
+ { ADAU17X1_MICBIAS, 0x00 },
{ ADAU1761_ALC_CTRL0, 0x00 },
{ ADAU1761_ALC_CTRL1, 0x00 },
{ ADAU1761_ALC_CTRL2, 0x00 },
{ ADAU1761_ALC_CTRL3, 0x00 },
- { ADAU1761_RIGHT_DIFF_INPUT_VOL, 0x00 },
- { ADAU1761_PLAY_LR_MIXER_LEFT, 0x00 },
+ { ADAU17X1_SERIAL_PORT0, 0x00 },
+ { ADAU17X1_SERIAL_PORT1, 0x00 },
+ { ADAU17X1_CONVERTER0, 0x00 },
+ { ADAU17X1_CONVERTER1, 0x00 },
+ { ADAU17X1_ADC_CONTROL, 0x00 },
+ { ADAU17X1_LEFT_INPUT_DIGITAL_VOL, 0x00 },
+ { ADAU17X1_RIGHT_INPUT_DIGITAL_VOL, 0x00 },
{ ADAU1761_PLAY_MIXER_LEFT0, 0x00 },
{ ADAU1761_PLAY_MIXER_LEFT1, 0x00 },
{ ADAU1761_PLAY_MIXER_RIGHT0, 0x00 },
{ ADAU1761_PLAY_MIXER_RIGHT1, 0x00 },
+ { ADAU1761_PLAY_LR_MIXER_LEFT, 0x00 },
{ ADAU1761_PLAY_LR_MIXER_RIGHT, 0x00 },
{ ADAU1761_PLAY_MIXER_MONO, 0x00 },
{ ADAU1761_PLAY_HP_LEFT_VOL, 0x00 },
@@ -93,20 +103,6 @@ static const struct reg_default adau1761_reg_defaults[] = {
{ ADAU1761_PLAY_LINE_RIGHT_VOL, 0x00 },
{ ADAU1761_PLAY_MONO_OUTPUT_VOL, 0x00 },
{ ADAU1761_POP_CLICK_SUPPRESS, 0x00 },
- { ADAU1761_JACK_DETECT_PIN, 0x00 },
- { ADAU1761_CLK_ENABLE0, 0x00 },
- { ADAU1761_CLK_ENABLE1, 0x00 },
- { ADAU17X1_CLOCK_CONTROL, 0x00 },
- { ADAU17X1_PLL_CONTROL, 0x00 },
- { ADAU17X1_REC_POWER_MGMT, 0x00 },
- { ADAU17X1_MICBIAS, 0x00 },
- { ADAU17X1_SERIAL_PORT0, 0x00 },
- { ADAU17X1_SERIAL_PORT1, 0x00 },
- { ADAU17X1_CONVERTER0, 0x00 },
- { ADAU17X1_CONVERTER1, 0x00 },
- { ADAU17X1_LEFT_INPUT_DIGITAL_VOL, 0x00 },
- { ADAU17X1_RIGHT_INPUT_DIGITAL_VOL, 0x00 },
- { ADAU17X1_ADC_CONTROL, 0x00 },
{ ADAU17X1_PLAY_POWER_MGMT, 0x00 },
{ ADAU17X1_DAC_CONTROL0, 0x00 },
{ ADAU17X1_DAC_CONTROL1, 0x00 },
@@ -114,12 +110,16 @@ static const struct reg_default adau1761_reg_defaults[] = {
{ ADAU17X1_SERIAL_PORT_PAD, 0xaa },
{ ADAU17X1_CONTROL_PORT_PAD0, 0xaa },
{ ADAU17X1_CONTROL_PORT_PAD1, 0x00 },
+ { ADAU1761_JACK_DETECT_PIN, 0x00 },
+ { ADAU1761_DEJITTER, 0x03 },
{ ADAU17X1_DSP_SAMPLING_RATE, 0x01 },
{ ADAU17X1_SERIAL_INPUT_ROUTE, 0x00 },
{ ADAU17X1_SERIAL_OUTPUT_ROUTE, 0x00 },
{ ADAU17X1_DSP_ENABLE, 0x00 },
{ ADAU17X1_DSP_RUN, 0x00 },
{ ADAU17X1_SERIAL_SAMPLING_RATE, 0x00 },
+ { ADAU1761_CLK_ENABLE0, 0x00 },
+ { ADAU1761_CLK_ENABLE1, 0x00 },
};
static const DECLARE_TLV_DB_SCALE(adau1761_sing_in_tlv, -1500, 300, 1);
diff --git a/sound/soc/codecs/adau7118-hw.c b/sound/soc/codecs/adau7118-hw.c
index 92b226b8b4bb..4342eb7dd9e5 100644
--- a/sound/soc/codecs/adau7118-hw.c
+++ b/sound/soc/codecs/adau7118-hw.c
@@ -22,7 +22,7 @@ static const struct of_device_id adau7118_of_match[] = {
MODULE_DEVICE_TABLE(of, adau7118_of_match);
static const struct platform_device_id adau7118_id[] = {
- { .name = "adau7118" },
+ { .name = "adau7118" },
{ }
};
MODULE_DEVICE_TABLE(platform, adau7118_id);
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index 8a89187f9c78..e97c72ac9b2b 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -743,11 +743,19 @@ static void adav80x_dai_shutdown(struct snd_pcm_substream *substream,
adav80x->rate = 0;
}
+static const u64 adav80x_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
static const struct snd_soc_dai_ops adav80x_dai_ops = {
.set_fmt = adav80x_set_dai_fmt,
.hw_params = adav80x_hw_params,
.startup = adav80x_dai_startup,
.shutdown = adav80x_dai_shutdown,
+ .auto_selectable_formats = &adav80x_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
#define ADAV80X_PLAYBACK_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index 3e0696b5abf5..be5306d07d40 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -95,6 +95,7 @@
* see
* AK4613_ENABLE_TDM_TEST
*/
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -384,7 +385,7 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
struct device *dev = component->dev;
- mutex_lock(&priv->lock);
+ guard(mutex)(&priv->lock);
priv->cnt--;
if (priv->cnt < 0) {
dev_err(dev, "unexpected counter error\n");
@@ -392,7 +393,6 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
}
if (!priv->cnt)
priv->ctrl1 = 0;
- mutex_unlock(&priv->lock);
}
static void ak4613_hw_constraints(struct ak4613_priv *priv,
@@ -507,10 +507,9 @@ static int ak4613_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
- mutex_lock(&priv->lock);
+ guard(mutex)(&priv->lock);
ak4613_hw_constraints(priv, substream);
priv->cnt++;
- mutex_unlock(&priv->lock);
return 0;
}
@@ -599,45 +598,47 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
*/
ret = -EINVAL;
- mutex_lock(&priv->lock);
- if (priv->cnt > 1) {
- /*
- * If it was already working, use current priv->ctrl1
- */
- ret = 0;
- } else {
- /*
- * It is not yet working,
- */
- unsigned int channel = params_channels(params);
- u8 tdm;
-
- /* STEREO or TDM */
- if (channel == 2)
- tdm = AK4613_CONFIG_MODE_STEREO;
- else
- tdm = AK4613_CONFIG_GET(priv, MODE);
-
- for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) {
- const struct ak4613_interface *iface = ak4613_iface + i;
-
- if ((iface->fmt == fmt) && (iface->width == width)) {
- /*
- * Ctrl1
- * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
- * |TDM1|TDM0|DIF2|DIF1|DIF0|ATS1|ATS0|SMUTE|
- * < tdm > < iface->dif >
- */
- priv->ctrl1 = (tdm << 6) | (iface->dif << 3);
- ret = 0;
- break;
+ scoped_guard(mutex, &priv->lock) {
+ if (priv->cnt > 1) {
+ /*
+ * If it was already working, use current priv->ctrl1
+ */
+ ret = 0;
+ } else {
+ /*
+ * It is not yet working,
+ */
+ unsigned int channel = params_channels(params);
+ u8 tdm;
+
+ /* STEREO or TDM */
+ if (channel == 2)
+ tdm = AK4613_CONFIG_MODE_STEREO;
+ else
+ tdm = AK4613_CONFIG_GET(priv, MODE);
+
+ for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) {
+ const struct ak4613_interface *iface = ak4613_iface + i;
+
+ if (iface->fmt == fmt && iface->width == width) {
+ /*
+ * Ctrl1
+ * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
+ * |TDM1|TDM0|DIF2|DIF1|DIF0|ATS1|ATS0|SMUTE|
+ * < tdm > < iface->dif >
+ */
+ priv->ctrl1 = (tdm << 6) | (iface->dif << 3);
+ ret = 0;
+ break;
+ }
}
}
}
- mutex_unlock(&priv->lock);
- if (ret < 0)
- goto hw_params_end;
+ if (ret < 0) {
+ dev_warn(dev, "unsupported data width/format combination\n");
+ return ret;
+ }
snd_soc_component_update_bits(component, CTRL1, FMT_MASK, priv->ctrl1);
snd_soc_component_update_bits(component, CTRL2, DFS_MASK, ctrl2);
@@ -645,10 +646,6 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
snd_soc_component_update_bits(component, ICTRL, ICTRL_MASK, priv->ic);
snd_soc_component_update_bits(component, OCTRL, OCTRL_MASK, priv->oc);
-hw_params_end:
- if (ret < 0)
- dev_warn(dev, "unsupported data width/format combination\n");
-
return ret;
}
diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c
index a9063bac2752..819d080b1188 100644
--- a/sound/soc/codecs/arizona-jack.c
+++ b/sound/soc/codecs/arizona-jack.c
@@ -5,6 +5,7 @@
* Copyright (C) 2012-2014 Wolfson Microelectronics plc
*/
+#include <linux/cleanup.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -707,15 +708,13 @@ static void arizona_micd_timeout_work(struct work_struct *work)
struct arizona_priv,
micd_timeout_work.work);
- mutex_lock(&info->lock);
+ guard(mutex)(&info->lock);
dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
info->detecting = false;
arizona_identify_headphone(info);
-
- mutex_unlock(&info->lock);
}
static int arizona_micd_adc_read(struct arizona_priv *info)
@@ -921,12 +920,11 @@ static void arizona_micd_detect(struct work_struct *work)
cancel_delayed_work_sync(&info->micd_timeout_work);
- mutex_lock(&info->lock);
+ guard(mutex)(&info->lock);
/* If the cable was removed while measuring ignore the result */
if (!(info->jack->status & SND_JACK_MECHANICAL)) {
dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
- mutex_unlock(&info->lock);
return;
}
@@ -936,7 +934,6 @@ static void arizona_micd_detect(struct work_struct *work)
arizona_button_reading(info);
pm_runtime_mark_last_busy(arizona->dev);
- mutex_unlock(&info->lock);
}
static irqreturn_t arizona_micdet(int irq, void *data)
@@ -948,10 +945,10 @@ static irqreturn_t arizona_micdet(int irq, void *data)
cancel_delayed_work_sync(&info->micd_detect_work);
cancel_delayed_work_sync(&info->micd_timeout_work);
- mutex_lock(&info->lock);
- if (!info->detecting)
- debounce = 0;
- mutex_unlock(&info->lock);
+ scoped_guard(mutex, &info->lock) {
+ if (!info->detecting)
+ debounce = 0;
+ }
if (debounce)
queue_delayed_work(system_power_efficient_wq,
@@ -969,9 +966,8 @@ static void arizona_hpdet_work(struct work_struct *work)
struct arizona_priv,
hpdet_work.work);
- mutex_lock(&info->lock);
+ guard(mutex)(&info->lock);
arizona_start_hpdet_acc_id(info);
- mutex_unlock(&info->lock);
}
static int arizona_hpdet_wait(struct arizona_priv *info)
@@ -1018,9 +1014,9 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
- pm_runtime_get_sync(arizona->dev);
+ guard(pm_runtime_active_auto)(arizona->dev);
- mutex_lock(&info->lock);
+ guard(mutex)(&info->lock);
if (info->micd_clamp) {
mask = ARIZONA_MICD_CLAMP_STS;
@@ -1036,8 +1032,6 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
if (ret) {
dev_err(arizona->dev, "Failed to read jackdet status: %d\n", ret);
- mutex_unlock(&info->lock);
- pm_runtime_put_autosuspend(arizona->dev);
return IRQ_NONE;
}
@@ -1056,62 +1050,61 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
&info->micd_timeout_work,
msecs_to_jiffies(micd_timeout));
}
+ } else {
+ info->last_jackdet = val;
- goto out;
- }
- info->last_jackdet = val;
+ if (info->last_jackdet == present) {
+ dev_dbg(arizona->dev, "Detected jack\n");
+ snd_soc_jack_report(info->jack, SND_JACK_MECHANICAL, SND_JACK_MECHANICAL);
- if (info->last_jackdet == present) {
- dev_dbg(arizona->dev, "Detected jack\n");
- snd_soc_jack_report(info->jack, SND_JACK_MECHANICAL, SND_JACK_MECHANICAL);
+ info->detecting = true;
+ info->mic = false;
+ info->jack_flips = 0;
- info->detecting = true;
- info->mic = false;
- info->jack_flips = 0;
+ if (!arizona->pdata.hpdet_acc_id) {
+ arizona_start_mic(info);
+ } else {
+ queue_delayed_work(system_power_efficient_wq,
+ &info->hpdet_work,
+ msecs_to_jiffies(HPDET_DEBOUNCE));
+ }
- if (!arizona->pdata.hpdet_acc_id) {
- arizona_start_mic(info);
+ if (info->micd_clamp || !arizona->pdata.jd_invert)
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_JACK_DETECT_DEBOUNCE,
+ ARIZONA_MICD_CLAMP_DB |
+ ARIZONA_JD1_DB, 0);
} else {
- queue_delayed_work(system_power_efficient_wq,
- &info->hpdet_work,
- msecs_to_jiffies(HPDET_DEBOUNCE));
- }
+ dev_dbg(arizona->dev, "Detected jack removal\n");
- if (info->micd_clamp || !arizona->pdata.jd_invert)
- regmap_update_bits(arizona->regmap,
- ARIZONA_JACK_DETECT_DEBOUNCE,
- ARIZONA_MICD_CLAMP_DB |
- ARIZONA_JD1_DB, 0);
- } else {
- dev_dbg(arizona->dev, "Detected jack removal\n");
-
- arizona_stop_mic(info);
+ arizona_stop_mic(info);
- info->num_hpdet_res = 0;
- for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
- info->hpdet_res[i] = 0;
- info->mic = false;
- info->hpdet_done = false;
- info->hpdet_retried = false;
+ info->num_hpdet_res = 0;
+ for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
+ info->hpdet_res[i] = 0;
+ info->mic = false;
+ info->hpdet_done = false;
+ info->hpdet_retried = false;
- snd_soc_jack_report(info->jack, 0, ARIZONA_JACK_MASK | info->micd_button_mask);
+ snd_soc_jack_report(info->jack, 0,
+ ARIZONA_JACK_MASK | info->micd_button_mask);
- /*
- * If the jack was removed during a headphone detection we
- * need to wait for the headphone detection to finish, as
- * it can not be aborted. We don't want to be able to start
- * a new headphone detection from a fresh insert until this
- * one is finished.
- */
- arizona_hpdet_wait(info);
+ /*
+ * If the jack was removed during a headphone detection we
+ * need to wait for the headphone detection to finish, as
+ * it can not be aborted. We don't want to be able to start
+ * a new headphone detection from a fresh insert until this
+ * one is finished.
+ */
+ arizona_hpdet_wait(info);
- regmap_update_bits(arizona->regmap,
- ARIZONA_JACK_DETECT_DEBOUNCE,
- ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
- ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_JACK_DETECT_DEBOUNCE,
+ ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
+ ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
+ }
}
-out:
/* Clear trig_sts to make sure DCVDD is not forced up */
regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
@@ -1119,10 +1112,6 @@ out:
ARIZONA_JD1_FALL_TRIG_STS |
ARIZONA_JD1_RISE_TRIG_STS);
- mutex_unlock(&info->lock);
-
- pm_runtime_put_autosuspend(arizona->dev);
-
return IRQ_HANDLED;
}
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 8c683b0bb74c..4411165c3734 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -7,6 +7,7 @@
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*/
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/gcd.h>
#include <linux/module.h>
@@ -1158,17 +1159,16 @@ int arizona_dvfs_up(struct snd_soc_component *component, unsigned int flags)
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
int ret = 0;
- mutex_lock(&priv->dvfs_lock);
+ guard(mutex)(&priv->dvfs_lock);
if (!priv->dvfs_cached && !priv->dvfs_reqs) {
ret = arizona_dvfs_enable(component);
if (ret)
- goto err;
+ return ret;
}
priv->dvfs_reqs |= flags;
-err:
- mutex_unlock(&priv->dvfs_lock);
+
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_up);
@@ -1179,7 +1179,7 @@ int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags)
unsigned int old_reqs;
int ret = 0;
- mutex_lock(&priv->dvfs_lock);
+ guard(mutex)(&priv->dvfs_lock);
old_reqs = priv->dvfs_reqs;
priv->dvfs_reqs &= ~flags;
@@ -1187,7 +1187,6 @@ int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags)
if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
ret = arizona_dvfs_disable(component);
- mutex_unlock(&priv->dvfs_lock);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_down);
@@ -1199,7 +1198,7 @@ int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
int ret = 0;
- mutex_lock(&priv->dvfs_lock);
+ guard(mutex)(&priv->dvfs_lock);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
@@ -1222,7 +1221,6 @@ int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
break;
}
- mutex_unlock(&priv->dvfs_lock);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
@@ -1657,13 +1655,11 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_component *component,
{ 0x80, 0x0 },
};
- mutex_lock(&arizona->dac_comp_lock);
-
- dac_comp[1].def = arizona->dac_comp_coeff;
- if (rate >= 176400)
- dac_comp[2].def = arizona->dac_comp_enabled;
-
- mutex_unlock(&arizona->dac_comp_lock);
+ scoped_guard(mutex, &arizona->dac_comp_lock) {
+ dac_comp[1].def = arizona->dac_comp_coeff;
+ if (rate >= 176400)
+ dac_comp[2].def = arizona->dac_comp_enabled;
+ }
regmap_multi_reg_write(arizona->regmap,
dac_comp,
diff --git a/sound/soc/codecs/aw87390.c b/sound/soc/codecs/aw87390.c
index 020213e0ca4b..5555c45dffcc 100644
--- a/sound/soc/codecs/aw87390.c
+++ b/sound/soc/codecs/aw87390.c
@@ -7,6 +7,7 @@
// Author: Weidong Wang <wangweidong.a@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/i2c.h>
#include <linux/firmware.h>
#include <linux/regmap.h>
@@ -225,11 +226,10 @@ static int aw87390_profile_set(struct snd_kcontrol *kcontrol,
struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec);
int ret;
- mutex_lock(&aw87390->lock);
+ guard(mutex)(&aw87390->lock);
ret = aw87390_dev_set_profile_index(aw87390->aw_pa, ucontrol->value.integer.value[0]);
if (ret) {
dev_dbg(codec->dev, "profile index does not change\n");
- mutex_unlock(&aw87390->lock);
return 0;
}
@@ -238,8 +238,6 @@ static int aw87390_profile_set(struct snd_kcontrol *kcontrol,
aw87390_power_on(aw87390->aw_pa);
}
- mutex_unlock(&aw87390->lock);
-
return 1;
}
@@ -250,7 +248,7 @@ static const struct snd_kcontrol_new aw87390_controls[] = {
static int aw87390_request_firmware_file(struct aw87390 *aw87390)
{
- const struct firmware *cont = NULL;
+ const struct firmware *cont __free(firmware) = NULL;
int ret;
aw87390->aw_pa->fw_status = AW87390_DEV_FW_FAILED;
@@ -265,14 +263,11 @@ static int aw87390_request_firmware_file(struct aw87390 *aw87390)
aw87390->aw_cfg = devm_kzalloc(aw87390->aw_pa->dev,
struct_size(aw87390->aw_cfg, data, cont->size), GFP_KERNEL);
- if (!aw87390->aw_cfg) {
- release_firmware(cont);
+ if (!aw87390->aw_cfg)
return -ENOMEM;
- }
aw87390->aw_cfg->len = cont->size;
memcpy(aw87390->aw_cfg->data, cont->data, cont->size);
- release_firmware(cont);
ret = aw88395_dev_load_acf_check(aw87390->aw_pa, aw87390->aw_cfg);
if (ret) {
@@ -280,14 +275,12 @@ static int aw87390_request_firmware_file(struct aw87390 *aw87390)
return ret;
}
- mutex_lock(&aw87390->lock);
+ guard(mutex)(&aw87390->lock);
ret = aw88395_dev_cfg_load(aw87390->aw_pa, aw87390->aw_cfg);
if (ret)
dev_err(aw87390->aw_pa->dev, "aw_dev acf parse failed\n");
- mutex_unlock(&aw87390->lock);
-
return ret;
}
diff --git a/sound/soc/codecs/aw88081.c b/sound/soc/codecs/aw88081.c
index d5e886a8f106..3247ba5c71b8 100644
--- a/sound/soc/codecs/aw88081.c
+++ b/sound/soc/codecs/aw88081.c
@@ -7,6 +7,7 @@
// Author: Weidong Wang <wangweidong.a@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
@@ -763,9 +764,8 @@ static void aw88081_startup_work(struct work_struct *work)
struct aw88081 *aw88081 =
container_of(work, struct aw88081, start_work.work);
- mutex_lock(&aw88081->lock);
+ guard(mutex)(&aw88081->lock);
aw88081_start_pa(aw88081);
- mutex_unlock(&aw88081->lock);
}
static void aw88081_start(struct aw88081 *aw88081, bool sync_start)
@@ -942,11 +942,10 @@ static int aw88081_profile_set(struct snd_kcontrol *kcontrol,
int ret;
/* pa stop or stopping just set profile */
- mutex_lock(&aw88081->lock);
+ guard(mutex)(&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;
}
@@ -955,8 +954,6 @@ static int aw88081_profile_set(struct snd_kcontrol *kcontrol,
aw88081_start(aw88081, AW88081_SYNC_START);
}
- mutex_unlock(&aw88081->lock);
-
return 1;
}
@@ -1136,7 +1133,7 @@ static int aw88081_dev_init(struct aw88081 *aw88081, struct aw_container *aw_cfg
static int aw88081_request_firmware_file(struct aw88081 *aw88081)
{
- const struct firmware *cont = NULL;
+ const struct firmware *cont __free(firmware) = NULL;
struct aw_container *aw_cfg;
int ret;
@@ -1150,26 +1147,21 @@ static int aw88081_request_firmware_file(struct aw88081 *aw88081)
AW88081_ACF_FILE, cont ? cont->size : 0);
aw_cfg = devm_kzalloc(aw88081->aw_pa->dev, struct_size(aw_cfg, data, cont->size), GFP_KERNEL);
- if (!aw_cfg) {
- release_firmware(cont);
+ if (!aw_cfg)
return -ENOMEM;
- }
+
aw_cfg->len = (int)cont->size;
memcpy(aw_cfg->data, cont->data, cont->size);
aw88081->aw_cfg = aw_cfg;
- 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);
+ guard(mutex)(&aw88081->lock);
- return ret;
+ return aw88081_dev_init(aw88081, aw88081->aw_cfg);
}
static int aw88081_playback_event(struct snd_soc_dapm_widget *w,
@@ -1178,7 +1170,7 @@ static int aw88081_playback_event(struct snd_soc_dapm_widget *w,
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);
+ guard(mutex)(&aw88081->lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
aw88081_start(aw88081, AW88081_ASYNC_START);
@@ -1189,7 +1181,6 @@ static int aw88081_playback_event(struct snd_soc_dapm_widget *w,
default:
break;
}
- mutex_unlock(&aw88081->lock);
return 0;
}
diff --git a/sound/soc/codecs/aw88166.c b/sound/soc/codecs/aw88166.c
index 3f15f4ac51f7..d2a138211c59 100644
--- a/sound/soc/codecs/aw88166.c
+++ b/sound/soc/codecs/aw88166.c
@@ -7,6 +7,7 @@
// Author: Weidong Wang <wangweidong.a@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/crc32.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
@@ -1173,9 +1174,8 @@ static void aw88166_startup_work(struct work_struct *work)
struct aw88166 *aw88166 =
container_of(work, struct aw88166, start_work.work);
- mutex_lock(&aw88166->lock);
+ guard(mutex)(&aw88166->lock);
aw88166_start_pa(aw88166);
- mutex_unlock(&aw88166->lock);
}
static void aw88166_start(struct aw88166 *aw88166, bool sync_start)
@@ -1413,11 +1413,10 @@ static int aw88166_profile_set(struct snd_kcontrol *kcontrol,
struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
int ret;
- mutex_lock(&aw88166->lock);
+ guard(mutex)(&aw88166->lock);
ret = aw88166_dev_set_profile_index(aw88166->aw_pa, ucontrol->value.integer.value[0]);
if (ret) {
dev_dbg(codec->dev, "profile index does not change");
- mutex_unlock(&aw88166->lock);
return 0;
}
@@ -1426,8 +1425,6 @@ static int aw88166_profile_set(struct snd_kcontrol *kcontrol,
aw88166_start(aw88166, AW88166_SYNC_START);
}
- mutex_unlock(&aw88166->lock);
-
return 1;
}
@@ -1573,7 +1570,7 @@ static int aw88166_dev_init(struct aw88166 *aw88166, struct aw_container *aw_cfg
static int aw88166_request_firmware_file(struct aw88166 *aw88166)
{
- const struct firmware *cont = NULL;
+ const struct firmware *cont __free(firmware) = NULL;
const char *fw_name;
int ret;
@@ -1593,13 +1590,11 @@ static int aw88166_request_firmware_file(struct aw88166 *aw88166)
aw88166->aw_cfg = devm_kzalloc(aw88166->aw_pa->dev,
struct_size(aw88166->aw_cfg, data, cont->size), GFP_KERNEL);
- if (!aw88166->aw_cfg) {
- release_firmware(cont);
+ if (!aw88166->aw_cfg)
return -ENOMEM;
- }
+
aw88166->aw_cfg->len = (int)cont->size;
memcpy(aw88166->aw_cfg->data, cont->data, cont->size);
- release_firmware(cont);
ret = aw88395_dev_load_acf_check(aw88166->aw_pa, aw88166->aw_cfg);
if (ret) {
@@ -1607,12 +1602,12 @@ static int aw88166_request_firmware_file(struct aw88166 *aw88166)
return ret;
}
- mutex_lock(&aw88166->lock);
- /* aw device init */
- ret = aw88166_dev_init(aw88166, aw88166->aw_cfg);
- if (ret)
- dev_err(aw88166->aw_pa->dev, "dev init failed\n");
- mutex_unlock(&aw88166->lock);
+ scoped_guard(mutex, &aw88166->lock) {
+ /* aw device init */
+ ret = aw88166_dev_init(aw88166, aw88166->aw_cfg);
+ if (ret)
+ dev_err(aw88166->aw_pa->dev, "dev init failed\n");
+ }
return ret;
}
@@ -1639,7 +1634,7 @@ static int aw88166_playback_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component);
- mutex_lock(&aw88166->lock);
+ guard(mutex)(&aw88166->lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
aw88166_start(aw88166, AW88166_ASYNC_START);
@@ -1650,7 +1645,6 @@ static int aw88166_playback_event(struct snd_soc_dapm_widget *w,
default:
break;
}
- mutex_unlock(&aw88166->lock);
return 0;
}
diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c
index 549783d3e75e..b8d06534bc8f 100644
--- a/sound/soc/codecs/aw88261.c
+++ b/sound/soc/codecs/aw88261.c
@@ -8,6 +8,7 @@
// Author: Weidong Wang <wangweidong.a@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/i2c.h>
#include <linux/firmware.h>
#include <linux/bitops.h>
@@ -206,10 +207,10 @@ static int aw88261_dev_check_sysst(struct aw_device *aw_dev)
return ret;
check_val = reg_val & (~AW88261_BIT_SYSST_CHECK_MASK)
- & AW88261_BIT_SYSST_CHECK;
- if (check_val != AW88261_BIT_SYSST_CHECK) {
+ & AW88261_BIT_PLL_CHECK;
+ if (check_val != AW88261_BIT_PLL_CHECK) {
dev_dbg(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x",
- reg_val, AW88261_BIT_SYSST_CHECK);
+ reg_val, AW88261_BIT_PLL_CHECK);
usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
} else {
return 0;
@@ -960,11 +961,10 @@ static int aw88261_profile_set(struct snd_kcontrol *kcontrol,
int ret;
/* pa stop or stopping just set profile */
- mutex_lock(&aw88261->lock);
+ guard(mutex)(&aw88261->lock);
ret = aw88261_dev_set_profile_index(aw88261->aw_pa, ucontrol->value.integer.value[0]);
if (ret) {
dev_dbg(codec->dev, "profile index does not change");
- mutex_unlock(&aw88261->lock);
return 0;
}
@@ -973,8 +973,6 @@ static int aw88261_profile_set(struct snd_kcontrol *kcontrol,
aw88261_start(aw88261);
}
- mutex_unlock(&aw88261->lock);
-
return 1;
}
@@ -1038,7 +1036,7 @@ static int aw88261_playback_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
- mutex_lock(&aw88261->lock);
+ guard(mutex)(&aw88261->lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
aw88261_start(aw88261);
@@ -1049,7 +1047,6 @@ static int aw88261_playback_event(struct snd_soc_dapm_widget *w,
default:
break;
}
- mutex_unlock(&aw88261->lock);
return 0;
}
@@ -1152,7 +1149,7 @@ static int aw88261_dev_init(struct aw88261 *aw88261, struct aw_container *aw_cfg
static int aw88261_request_firmware_file(struct aw88261 *aw88261)
{
- const struct firmware *cont = NULL;
+ const struct firmware *cont __free(firmware) = NULL;
struct aw_container *aw_cfg;
const char *fw_name;
int ret;
@@ -1172,13 +1169,11 @@ static int aw88261_request_firmware_file(struct aw88261 *aw88261)
fw_name, cont ? cont->size : 0);
aw_cfg = devm_kzalloc(aw88261->aw_pa->dev, struct_size(aw_cfg, data, cont->size), GFP_KERNEL);
- if (!aw_cfg) {
- release_firmware(cont);
+ if (!aw_cfg)
return -ENOMEM;
- }
+
aw_cfg->len = (int)cont->size;
memcpy(aw_cfg->data, cont->data, cont->size);
- release_firmware(cont);
aw88261->aw_cfg = aw_cfg;
@@ -1188,12 +1183,12 @@ static int aw88261_request_firmware_file(struct aw88261 *aw88261)
return ret;
}
- mutex_lock(&aw88261->lock);
- /* aw device init */
- ret = aw88261_dev_init(aw88261, aw88261->aw_cfg);
- if (ret)
- dev_err(aw88261->aw_pa->dev, "dev init failed");
- mutex_unlock(&aw88261->lock);
+ scoped_guard(mutex, &aw88261->lock) {
+ /* aw device init */
+ ret = aw88261_dev_init(aw88261, aw88261->aw_cfg);
+ if (ret)
+ dev_err(aw88261->aw_pa->dev, "dev init failed");
+ }
return ret;
}
diff --git a/sound/soc/codecs/aw88261.h b/sound/soc/codecs/aw88261.h
index 270ccf375f36..f16f9f8c40a2 100644
--- a/sound/soc/codecs/aw88261.h
+++ b/sound/soc/codecs/aw88261.h
@@ -194,12 +194,6 @@
AW88261_OTHS_OT_VALUE | \
AW88261_PLLS_LOCKED_VALUE))
-#define AW88261_BIT_SYSST_CHECK \
- (AW88261_BSTS_FINISHED_VALUE | \
- AW88261_SWS_SWITCHING_VALUE | \
- AW88261_CLKS_STABLE_VALUE | \
- AW88261_PLLS_LOCKED_VALUE)
-
#define AW88261_ULS_HMUTE_START_BIT (14)
#define AW88261_ULS_HMUTE_BITS_LEN (1)
#define AW88261_ULS_HMUTE_MASK \
diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c
index ee0e8bd8c54c..2f4108624d13 100644
--- a/sound/soc/codecs/aw88395/aw88395.c
+++ b/sound/soc/codecs/aw88395/aw88395.c
@@ -8,6 +8,7 @@
// Author: Weidong Wang <wangweidong.a@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/firmware.h>
@@ -51,9 +52,8 @@ static void aw88395_startup_work(struct work_struct *work)
struct aw88395 *aw88395 =
container_of(work, struct aw88395, start_work.work);
- mutex_lock(&aw88395->lock);
+ guard(mutex)(&aw88395->lock);
aw88395_start_pa(aw88395);
- mutex_unlock(&aw88395->lock);
}
static void aw88395_start(struct aw88395 *aw88395, bool sync_start)
@@ -224,11 +224,10 @@ static int aw88395_profile_set(struct snd_kcontrol *kcontrol,
int ret;
/* pa stop or stopping just set profile */
- mutex_lock(&aw88395->lock);
+ guard(mutex)(&aw88395->lock);
ret = aw88395_dev_set_profile_index(aw88395->aw_pa, ucontrol->value.integer.value[0]);
if (ret < 0) {
dev_dbg(codec->dev, "profile index does not change");
- mutex_unlock(&aw88395->lock);
return 0;
}
@@ -237,8 +236,6 @@ static int aw88395_profile_set(struct snd_kcontrol *kcontrol,
aw88395_start(aw88395, AW88395_SYNC_START);
}
- mutex_unlock(&aw88395->lock);
-
return 1;
}
@@ -366,7 +363,7 @@ static int aw88395_playback_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component);
- mutex_lock(&aw88395->lock);
+ guard(mutex)(&aw88395->lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
aw88395_start(aw88395, AW88395_ASYNC_START);
@@ -377,7 +374,6 @@ static int aw88395_playback_event(struct snd_soc_dapm_widget *w,
default:
break;
}
- mutex_unlock(&aw88395->lock);
return 0;
}
@@ -461,7 +457,7 @@ static void aw88395_hw_reset(struct aw88395 *aw88395)
static int aw88395_request_firmware_file(struct aw88395 *aw88395)
{
- const struct firmware *cont = NULL;
+ const struct firmware *cont __free(firmware) = NULL;
struct aw_container *aw_cfg;
int ret;
@@ -477,13 +473,11 @@ static int aw88395_request_firmware_file(struct aw88395 *aw88395)
AW88395_ACF_FILE, cont ? cont->size : 0);
aw_cfg = devm_kzalloc(aw88395->aw_pa->dev, struct_size(aw_cfg, data, cont->size), GFP_KERNEL);
- if (!aw_cfg) {
- release_firmware(cont);
+ if (!aw_cfg)
return -ENOMEM;
- }
+
aw_cfg->len = (int)cont->size;
memcpy(aw_cfg->data, cont->data, cont->size);
- release_firmware(cont);
aw88395->aw_cfg = aw_cfg;
@@ -495,12 +489,12 @@ static int aw88395_request_firmware_file(struct aw88395 *aw88395)
dev_dbg(aw88395->aw_pa->dev, "%s : bin load success\n", __func__);
- mutex_lock(&aw88395->lock);
- /* aw device init */
- ret = aw88395_dev_init(aw88395->aw_pa, aw88395->aw_cfg);
- if (ret < 0)
- dev_err(aw88395->aw_pa->dev, "dev init failed");
- mutex_unlock(&aw88395->lock);
+ scoped_guard(mutex, &aw88395->lock) {
+ /* aw device init */
+ ret = aw88395_dev_init(aw88395->aw_pa, aw88395->aw_cfg);
+ if (ret < 0)
+ dev_err(aw88395->aw_pa->dev, "dev init failed");
+ }
return ret;
}
diff --git a/sound/soc/codecs/aw88395/aw88395_device.c b/sound/soc/codecs/aw88395/aw88395_device.c
index 79c3135a4110..12d42d27560d 100644
--- a/sound/soc/codecs/aw88395/aw88395_device.c
+++ b/sound/soc/codecs/aw88395/aw88395_device.c
@@ -8,6 +8,7 @@
// Author: Ben Yi <yijiangtao@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/crc32.h>
#include <linux/i2c.h>
#include <linux/minmax.h>
@@ -70,7 +71,7 @@ int aw_dev_dsp_write(struct aw_device *aw_dev,
u32 reg_value;
int ret;
- mutex_lock(&aw_dev->dsp_lock);
+ guard(mutex)(&aw_dev->dsp_lock);
switch (data_type) {
case AW_DSP_16_DATA:
ret = aw_dev_dsp_write_16bit(aw_dev, dsp_addr, dsp_data);
@@ -93,7 +94,6 @@ int aw_dev_dsp_write(struct aw_device *aw_dev,
/* clear dsp chip select state*/
if (regmap_read(aw_dev->regmap, AW88395_ID_REG, &reg_value))
dev_err(aw_dev->dev, "%s fail to clear chip state. Err=%d\n", __func__, ret);
- mutex_unlock(&aw_dev->dsp_lock);
return ret;
}
@@ -156,7 +156,7 @@ int aw_dev_dsp_read(struct aw_device *aw_dev,
u32 reg_value;
int ret;
- mutex_lock(&aw_dev->dsp_lock);
+ guard(mutex)(&aw_dev->dsp_lock);
switch (data_type) {
case AW_DSP_16_DATA:
ret = aw_dev_dsp_read_16bit(aw_dev, dsp_addr, dsp_data);
@@ -179,7 +179,6 @@ int aw_dev_dsp_read(struct aw_device *aw_dev,
/* clear dsp chip select state*/
if (regmap_read(aw_dev->regmap, AW88395_ID_REG, &reg_value))
dev_err(aw_dev->dev, "%s fail to clear chip state. Err=%d\n", __func__, ret);
- mutex_unlock(&aw_dev->dsp_lock);
return ret;
}
@@ -1110,42 +1109,36 @@ static int aw_dev_dsp_update_container(struct aw_device *aw_dev,
#ifdef AW88395_DSP_I2C_WRITES
u32 tmp_len;
- mutex_lock(&aw_dev->dsp_lock);
+ guard(mutex)(&aw_dev->dsp_lock);
ret = regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, base);
if (ret)
- goto error_operation;
+ return ret;
for (i = 0; i < len; i += AW88395_MAX_RAM_WRITE_BYTE_SIZE) {
tmp_len = min(len - i, AW88395_MAX_RAM_WRITE_BYTE_SIZE);
ret = regmap_raw_write(aw_dev->regmap, AW88395_DSPMDAT_REG,
&data[i], tmp_len);
if (ret)
- goto error_operation;
+ return ret;
}
- mutex_unlock(&aw_dev->dsp_lock);
#else
__be16 reg_val;
- mutex_lock(&aw_dev->dsp_lock);
+ guard(mutex)(&aw_dev->dsp_lock);
/* i2c write */
ret = regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, base);
if (ret)
- goto error_operation;
+ return ret;
for (i = 0; i < len; i += 2) {
reg_val = cpu_to_be16p((u16 *)(data + i));
ret = regmap_write(aw_dev->regmap, AW88395_DSPMDAT_REG,
(u16)reg_val);
if (ret)
- goto error_operation;
+ return ret;
}
- mutex_unlock(&aw_dev->dsp_lock);
#endif
return 0;
-
-error_operation:
- mutex_unlock(&aw_dev->dsp_lock);
- return ret;
}
static int aw_dev_dsp_update_fw(struct aw_device *aw_dev,
@@ -1231,14 +1224,14 @@ static int aw_dev_check_sram(struct aw_device *aw_dev)
{
unsigned int reg_val;
- mutex_lock(&aw_dev->dsp_lock);
+ guard(mutex)(&aw_dev->dsp_lock);
/* check the odd bits of reg 0x40 */
regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, AW88395_DSP_ODD_NUM_BIT_TEST);
regmap_read(aw_dev->regmap, AW88395_DSPMADD_REG, &reg_val);
if (reg_val != AW88395_DSP_ODD_NUM_BIT_TEST) {
dev_err(aw_dev->dev, "check reg 0x40 odd bit failed, read[0x%x] != write[0x%x]",
reg_val, AW88395_DSP_ODD_NUM_BIT_TEST);
- goto error;
+ return -EPERM;
}
/* check the even bits of reg 0x40 */
@@ -1247,7 +1240,7 @@ static int aw_dev_check_sram(struct aw_device *aw_dev)
if (reg_val != AW88395_DSP_EVEN_NUM_BIT_TEST) {
dev_err(aw_dev->dev, "check reg 0x40 even bit failed, read[0x%x] != write[0x%x]",
reg_val, AW88395_DSP_EVEN_NUM_BIT_TEST);
- goto error;
+ return -EPERM;
}
/* check dsp_fw_base_addr */
@@ -1256,7 +1249,7 @@ static int aw_dev_check_sram(struct aw_device *aw_dev)
if (reg_val != AW88395_DSP_EVEN_NUM_BIT_TEST) {
dev_err(aw_dev->dev, "check dsp fw addr failed, read[0x%x] != write[0x%x]",
reg_val, AW88395_DSP_EVEN_NUM_BIT_TEST);
- goto error;
+ return -EPERM;
}
/* check dsp_cfg_base_addr */
@@ -1265,15 +1258,10 @@ static int aw_dev_check_sram(struct aw_device *aw_dev)
if (reg_val != AW88395_DSP_ODD_NUM_BIT_TEST) {
dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]",
reg_val, AW88395_DSP_ODD_NUM_BIT_TEST);
- goto error;
+ return -EPERM;
}
- mutex_unlock(&aw_dev->dsp_lock);
return 0;
-
-error:
- mutex_unlock(&aw_dev->dsp_lock);
- return -EPERM;
}
int aw88395_dev_fw_update(struct aw_device *aw_dev, bool up_dsp_fw_en, bool force_up_en)
diff --git a/sound/soc/codecs/aw88399-lib.c b/sound/soc/codecs/aw88399-lib.c
new file mode 100644
index 000000000000..809c2faa0c0c
--- /dev/null
+++ b/sound/soc/codecs/aw88399-lib.c
@@ -0,0 +1,1409 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88399-lib.c -- AW88399 Common functions for ASoC and HDA audio drivers
+//
+// Copyright (c) 2023 AWINIC Technology CO., LTD
+//
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/minmax.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/aw88399.h>
+#include "aw88395/aw88395_device.h"
+
+const struct regmap_config aw88399_remap_config = {
+ .val_bits = 16,
+ .reg_bits = 8,
+ .max_register = AW88399_REG_MAX,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+EXPORT_SYMBOL_GPL(aw88399_remap_config);
+
+static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd)
+{
+ int ret;
+
+ if (pwd)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_PWDN_MASK, AW88399_PWDN_POWER_DOWN_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_PWDN_MASK, AW88399_PWDN_WORKING_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+}
+
+static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSINT_REG, &reg_val);
+ if (ret)
+ dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret);
+ else
+ *int_status = reg_val;
+
+ dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status);
+}
+
+static void aw_dev_clear_int_status(struct aw_device *aw_dev)
+{
+ u16 int_status;
+
+ /* read int status and clear */
+ aw_dev_get_int_status(aw_dev, &int_status);
+ /* make sure int status is clear */
+ aw_dev_get_int_status(aw_dev, &int_status);
+ if (int_status)
+ dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status);
+}
+
+static int aw_dev_get_iis_status(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+ if ((reg_val & AW88399_BIT_PLL_CHECK) != AW88399_BIT_PLL_CHECK) {
+ dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int aw_dev_check_mode1_pll(struct aw_device *aw_dev)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode1 iis signal check error");
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ return 0;
+ }
+ }
+
+ return -EPERM;
+}
+
+static int aw_dev_check_mode2_pll(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret, i;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_PLLCTRL2_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_val &= (~AW88399_CCO_MUX_MASK);
+ if (reg_val == AW88399_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, AW88399_PLLCTRL2_REG,
+ ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_DIVIDED_VALUE);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 iis signal check error");
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+
+ /* change mode1 */
+ regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG,
+ ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_BYPASS_VALUE);
+ if (ret == 0) {
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error");
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+int aw_dev_check_syspll(struct aw_device *aw_dev)
+{
+ int ret;
+
+ ret = aw_dev_check_mode1_pll(aw_dev);
+ if (ret) {
+ dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
+ ret = aw_dev_check_mode2_pll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 check iis failed");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aw_dev_check_syspll);
+
+static int aw_dev_check_sysst(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int check_val;
+ unsigned int reg_val;
+ int ret, i;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_PWMCTRL3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ if (reg_val & (~AW88399_NOISE_GATE_EN_MASK))
+ check_val = AW88399_BIT_SYSST_NOSWS_CHECK;
+ else
+ check_val = AW88399_BIT_SYSST_SWS_CHECK;
+
+ /*
+ * On some hardware the BSTS (boost-finished) status bit does not
+ * reliably assert even when audio output is working normally.
+ * Allow per-instance bypass when flagged by the side-codec driver.
+ */
+ if (aw88399->bsts_unreliable)
+ check_val &= ~AW88399_BSTS_FINISHED_VALUE;
+
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ if ((reg_val & (~AW88399_BIT_SYSST_CHECK_MASK) & check_val) != check_val) {
+ dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x",
+ i, reg_val, AW88399_BIT_SYSST_NOSWS_CHECK);
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ return 0;
+ }
+ }
+
+ return -EPERM;
+}
+
+static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd)
+{
+ int ret;
+
+ if (amppd)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_AMPPD_MASK, AW88399_AMPPD_POWER_DOWN_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_AMPPD_MASK, AW88399_AMPPD_WORKING_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+}
+
+void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable)
+{
+ int ret;
+
+ if (is_enable)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_DSPBY_MASK, AW88399_DSPBY_WORKING_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_DSPBY_MASK, AW88399_DSPBY_BYPASS_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed\n", __func__);
+}
+EXPORT_SYMBOL_GPL(aw_dev_dsp_enable);
+
+static int aw88399_dev_get_icalk(struct aw88399 *aw88399, int16_t *icalk)
+{
+ uint16_t icalkh_val, icalkl_val, icalk_val;
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH4_REG, &reg_val);
+ if (ret)
+ return ret;
+ icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_REG, &reg_val);
+ if (ret)
+ return ret;
+ icalkl_val = reg_val & (~AW88399_EF_ISN_GESLP_L_MASK);
+
+ if (aw88399->check_val == AW_EF_AND_CHECK)
+ icalk_val = icalkh_val & icalkl_val;
+ else
+ icalk_val = icalkh_val | icalkl_val;
+
+ if (icalk_val & (~AW88399_EF_ISN_GESLP_SIGN_MASK))
+ icalk_val = icalk_val | AW88399_EF_ISN_GESLP_SIGN_NEG;
+ *icalk = (int16_t)icalk_val;
+
+ return 0;
+}
+
+static int aw88399_dev_get_vcalk(struct aw88399 *aw88399, int16_t *vcalk)
+{
+ uint16_t vcalkh_val, vcalkl_val, vcalk_val;
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ vcalkl_val = reg_val & (~AW88399_EF_VSN_GESLP_L_MASK);
+
+ if (aw88399->check_val == AW_EF_AND_CHECK)
+ vcalk_val = vcalkh_val & vcalkl_val;
+ else
+ vcalk_val = vcalkh_val | vcalkl_val;
+
+ if (vcalk_val & AW88399_EF_VSN_GESLP_SIGN_MASK)
+ vcalk_val = vcalk_val | AW88399_EF_VSN_GESLP_SIGN_NEG;
+ *vcalk = (int16_t)vcalk_val;
+
+ return 0;
+}
+
+static int aw88399_dev_get_internal_vcalk(struct aw88399 *aw88399, int16_t *vcalk)
+{
+ uint16_t vcalkh_val, vcalkl_val, vcalk_val;
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH2_REG, &reg_val);
+ if (ret)
+ return ret;
+ vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_REG, &reg_val);
+ if (ret)
+ return ret;
+ vcalkl_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_L_MASK);
+
+ if (aw88399->check_val == AW_EF_AND_CHECK)
+ vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) &
+ (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT);
+ else
+ vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) |
+ (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT);
+
+ if (vcalk_val & (~AW88399_TEM4_SIGN_MASK))
+ vcalk_val = vcalk_val | AW88399_TEM4_SIGN_NEG;
+
+ *vcalk = (int16_t)vcalk_val;
+
+ return 0;
+}
+
+static int aw_dev_set_vcalb(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int vsense_select, vsense_value;
+ int32_t ical_k, vcal_k, vcalb;
+ int16_t icalk, vcalk;
+ uint16_t reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_VSNCTRL1_REG, &vsense_value);
+ if (ret)
+ return ret;
+
+ vsense_select = vsense_value & (~AW88399_VDSEL_MASK);
+
+ ret = aw88399_dev_get_icalk(aw88399, &icalk);
+ if (ret) {
+ dev_err(aw_dev->dev, "get icalk failed\n");
+ return ret;
+ }
+
+ ical_k = icalk * AW88399_ICABLK_FACTOR + AW88399_CABL_BASE_VALUE;
+
+ switch (vsense_select) {
+ case AW88399_DEV_VDSEL_VSENSE:
+ ret = aw88399_dev_get_vcalk(aw88399, &vcalk);
+ vcal_k = vcalk * AW88399_VCABLK_FACTOR + AW88399_CABL_BASE_VALUE;
+ vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR *
+ ical_k / vcal_k * aw88399->vcalb_init_val;
+ break;
+ case AW88399_DEV_VDSEL_DAC:
+ ret = aw88399_dev_get_internal_vcalk(aw88399, &vcalk);
+ vcal_k = vcalk * AW88399_VCABLK_DAC_FACTOR + AW88399_CABL_BASE_VALUE;
+ vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_DAC_FACTOR /
+ AW88399_ISCAL_DAC_FACTOR * ical_k /
+ vcal_k * aw88399->vcalb_init_val;
+ break;
+ default:
+ dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__);
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ return ret;
+
+ vcalb = vcalb >> AW88399_VCALB_ADJ_FACTOR;
+ reg_val = (uint32_t)vcalb;
+
+ regmap_write(aw_dev->regmap, AW88399_DSPVCALB_REG, reg_val);
+
+ return 0;
+}
+
+int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc)
+{
+ struct aw_device *aw_dev =
+ container_of(cali_desc, struct aw_device, cali_desc);
+ uint16_t re_lbits, re_hbits;
+ u32 cali_re;
+ int ret;
+
+ if ((aw_dev->cali_desc.cali_re >= AW88399_CALI_RE_MAX) ||
+ (aw_dev->cali_desc.cali_re <= AW88399_CALI_RE_MIN))
+ return -EINVAL;
+
+ cali_re = AW88399_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re +
+ aw_dev->cali_desc.ra), AW88399_DSP_RE_SHIFT);
+
+ re_hbits = (cali_re & (~AW88399_CALI_RE_HBITS_MASK)) >> AW88399_CALI_RE_HBITS_SHIFT;
+ re_lbits = (cali_re & (~AW88399_CALI_RE_LBITS_MASK)) >> AW88399_CALI_RE_LBITS_SHIFT;
+
+ ret = regmap_write(aw_dev->regmap, AW88399_ACR1_REG, re_hbits);
+ if (ret) {
+ dev_err(aw_dev->dev, "set cali re error");
+ return ret;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW88399_ACR2_REG, re_lbits);
+ if (ret)
+ dev_err(aw_dev->dev, "set cali re error");
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(aw_dev_update_cali_re);
+
+static int aw_dev_fw_crc_check(struct aw_device *aw_dev)
+{
+ uint16_t check_val, fw_len_val;
+ unsigned int reg_val;
+ int ret;
+
+ /* calculate fw_end_addr */
+ fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_FW_BASE_ADDR;
+
+ /* write fw_end_addr to crc_end_addr */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_END_ADDR_MASK, fw_len_val);
+ if (ret)
+ return ret;
+ /* enable fw crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_ENABLE_VALUE);
+
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+
+ /* read crc check result */
+ regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT;
+
+ /* disable fw crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_DISABLE_VALUE);
+ if (ret)
+ return ret;
+
+ if (check_val != AW88399_CRC_CHECK_PASS_VAL) {
+ dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x",
+ __func__, check_val, AW88399_CRC_CHECK_PASS_VAL);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int aw_dev_cfg_crc_check(struct aw_device *aw_dev)
+{
+ uint16_t check_val, cfg_len_val;
+ unsigned int reg_val;
+ int ret;
+
+ /* calculate cfg end addr */
+ cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_CFG_BASE_ADDR;
+
+ /* write cfg_end_addr to crc_end_addr */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_END_ADDR_MASK, cfg_len_val);
+ if (ret)
+ return ret;
+
+ /* enable cfg crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_ENABLE_VALUE);
+ if (ret)
+ return ret;
+
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+
+ /* read crc check result */
+ ret = regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT;
+
+ /* disable cfg crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_DISABLE_VALUE);
+ if (ret)
+ return ret;
+
+ if (check_val != AW88399_CRC_CHECK_PASS_VAL) {
+ dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x",
+ check_val, AW88399_CRC_CHECK_PASS_VAL);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int aw_dev_hw_crc_check(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ int ret;
+
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_BYPASS_VALUE);
+ if (ret)
+ return ret;
+
+ ret = aw_dev_fw_crc_check(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "fw_crc_check failed\n");
+ goto crc_check_failed;
+ }
+
+ ret = aw_dev_cfg_crc_check(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "cfg_crc_check failed\n");
+ goto crc_check_failed;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW88399_CRCCTRL_REG, aw88399->crc_init_val);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE);
+
+ return ret;
+
+crc_check_failed:
+ regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE);
+ return ret;
+}
+
+static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
+{
+ int ret;
+
+ if (flag)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCTRL3_REG,
+ ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_ENABLE_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_DISABLE_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+}
+
+int aw_dev_get_dsp_status(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_WDT_REG, &reg_val);
+ if (ret)
+ return ret;
+ if (!(reg_val & (~AW88399_WDT_CNT_MASK)))
+ return -EPERM;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aw_dev_get_dsp_status);
+
+static int aw_dev_dsp_check(struct aw_device *aw_dev)
+{
+ int ret, i;
+
+ switch (aw_dev->dsp_cfg) {
+ case AW88399_DEV_DSP_BYPASS:
+ dev_dbg(aw_dev->dev, "dsp bypass");
+ ret = 0;
+ break;
+ case AW88399_DEV_DSP_WORK:
+ aw_dev_dsp_enable(aw_dev, false);
+ aw_dev_dsp_enable(aw_dev, true);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ for (i = 0; i < AW88399_DEV_DSP_CHECK_MAX; i++) {
+ ret = aw_dev_get_dsp_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "dsp wdt status error=%d", ret);
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ }
+ }
+ break;
+ default:
+ dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
+{
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ unsigned int reg_value;
+ u16 real_value;
+ int ret;
+
+ real_value = min((value + vol_desc->init_volume), (unsigned int)AW88399_MUTE_VOL);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL2_REG, &reg_value);
+ if (ret)
+ return ret;
+
+ dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value);
+
+ real_value = (real_value << AW88399_VOL_START_BIT) | (reg_value & AW88399_VOL_MASK);
+
+ ret = regmap_write(aw_dev->regmap, AW88399_SYSCTRL2_REG, real_value);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(aw_dev_set_volume);
+
+static void aw_dev_fade_in(struct aw_device *aw_dev)
+{
+ struct aw_volume_desc *desc = &aw_dev->volume_desc;
+ u16 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) {
+ aw_dev_set_volume(aw_dev, fade_in_vol);
+ return;
+ }
+
+ for (i = AW88399_MUTE_VOL; i >= fade_in_vol; i -= fade_step) {
+ aw_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10);
+ }
+
+ if (i != fade_in_vol)
+ aw_dev_set_volume(aw_dev, fade_in_vol);
+}
+
+static void aw_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) {
+ aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL);
+ return;
+ }
+
+ for (i = desc->ctl_volume; i <= AW88399_MUTE_VOL; i += fade_step) {
+ aw_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+
+ if (i != AW88399_MUTE_VOL) {
+ aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+}
+
+void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute)
+{
+ if (is_mute) {
+ aw_dev_fade_out(aw_dev);
+ regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_HMUTE_MASK, AW88399_HMUTE_ENABLE_VALUE);
+ } else {
+ regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_HMUTE_MASK, AW88399_HMUTE_DISABLE_VALUE);
+ aw_dev_fade_in(aw_dev);
+ }
+}
+EXPORT_SYMBOL_GPL(aw88399_dev_mute);
+
+static void aw88399_dev_set_dither(struct aw88399 *aw88399, bool dither)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+
+ if (dither)
+ regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_ENABLE_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_DISABLE_VALUE);
+}
+
+static int aw88399_dev_start(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ int ret;
+
+ if (aw_dev->status == AW88399_DEV_PW_ON) {
+ dev_dbg(aw_dev->dev, "already power on");
+ return 0;
+ }
+
+ aw88399_dev_set_dither(aw88399, false);
+
+ /* power on */
+ aw_dev_pwd(aw_dev, false);
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+
+ ret = aw_dev_check_syspll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "pll check failed cannot start");
+ goto pll_check_fail;
+ }
+
+ /* amppd on */
+ aw_dev_amppd(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 50);
+
+ /* check i2s status */
+ ret = aw_dev_check_sysst(aw88399);
+ if (ret) {
+ dev_err(aw_dev->dev, "sysst check failed");
+ goto sysst_check_fail;
+ }
+
+ if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) {
+ ret = aw_dev_hw_crc_check(aw88399);
+ if (ret) {
+ dev_err(aw_dev->dev, "dsp crc check failed");
+ goto crc_check_fail;
+ }
+ aw_dev_dsp_enable(aw_dev, false);
+ aw_dev_set_vcalb(aw88399);
+ aw_dev_update_cali_re(&aw_dev->cali_desc);
+
+ ret = aw_dev_dsp_check(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "dsp status check failed");
+ goto dsp_check_fail;
+ }
+ } else {
+ dev_dbg(aw_dev->dev, "start pa with dsp bypass");
+ }
+
+ /* enable tx feedback */
+ aw_dev_i2s_tx_enable(aw_dev, true);
+
+ if (aw88399->dither_st == AW88399_DITHER_EN_ENABLE_VALUE)
+ aw88399_dev_set_dither(aw88399, true);
+
+ /* close mute */
+ aw88399_dev_mute(aw_dev, false);
+ /* clear inturrupt */
+ aw_dev_clear_int_status(aw_dev);
+ aw_dev->status = AW88399_DEV_PW_ON;
+
+ return 0;
+
+dsp_check_fail:
+crc_check_fail:
+ aw_dev_dsp_enable(aw_dev, false);
+sysst_check_fail:
+ aw_dev_clear_int_status(aw_dev);
+ aw_dev_amppd(aw_dev, true);
+pll_check_fail:
+ aw_dev_pwd(aw_dev, true);
+ aw_dev->status = AW88399_DEV_PW_OFF;
+
+ return ret;
+}
+
+static int aw_dev_dsp_update_container(struct aw_device *aw_dev,
+ unsigned char *data, unsigned int len, unsigned short base)
+{
+ u32 tmp_len;
+ int i, ret;
+
+ ret = regmap_write(aw_dev->regmap, AW88399_DSPMADD_REG, base);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < len; i += AW88399_MAX_RAM_WRITE_BYTE_SIZE) {
+ tmp_len = min(len - i, AW88399_MAX_RAM_WRITE_BYTE_SIZE);
+ ret = regmap_raw_write(aw_dev->regmap, AW88399_DSPMDAT_REG,
+ &data[i], tmp_len);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int aw_dev_get_ra(struct aw_cali_desc *cali_desc)
+{
+ struct aw_device *aw_dev =
+ container_of(cali_desc, struct aw_device, cali_desc);
+ u32 dsp_ra;
+ int ret;
+
+ ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_RA,
+ &dsp_ra, AW_DSP_32_DATA);
+ if (ret) {
+ dev_err(aw_dev->dev, "read ra error");
+ return ret;
+ }
+
+ cali_desc->ra = AW88399_DSP_RE_TO_SHOW_RE(dsp_ra,
+ AW88399_DSP_RE_SHIFT);
+
+ return 0;
+}
+
+static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev,
+ unsigned char *data, unsigned int len)
+{
+ int ret;
+
+ dev_dbg(aw_dev->dev, "dsp config len:%d", len);
+
+ if (!len || !data) {
+ dev_err(aw_dev->dev, "dsp config data is null or len is 0");
+ return -EINVAL;
+ }
+
+ ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_CFG_ADDR);
+ if (ret)
+ return ret;
+
+ aw_dev->dsp_cfg_len = len;
+
+ ret = aw_dev_get_ra(&aw_dev->cali_desc);
+
+ return ret;
+}
+
+static int aw_dev_dsp_update_fw(struct aw_device *aw_dev,
+ unsigned char *data, unsigned int len)
+{
+ int ret;
+
+ dev_dbg(aw_dev->dev, "dsp firmware len:%d", len);
+
+ if (!len || !data) {
+ dev_err(aw_dev->dev, "dsp firmware data is null or len is 0");
+ return -EINVAL;
+ }
+
+ aw_dev->dsp_fw_len = len;
+ ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_FW_ADDR);
+
+ return ret;
+}
+
+static int aw_dev_check_sram(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+
+ /* read dsp_rom_check_reg */
+ aw_dev_dsp_read(aw_dev, AW88399_DSP_ROM_CHECK_ADDR, &reg_val, AW_DSP_16_DATA);
+ if (reg_val != AW88399_DSP_ROM_CHECK_DATA) {
+ dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]",
+ reg_val, AW88399_DSP_ROM_CHECK_DATA);
+ return -EPERM;
+ }
+
+ /* check dsp_cfg_base_addr */
+ aw_dev_dsp_write(aw_dev, AW88399_DSP_CFG_ADDR,
+ AW88399_DSP_ODD_NUM_BIT_TEST, AW_DSP_16_DATA);
+ aw_dev_dsp_read(aw_dev, AW88399_DSP_CFG_ADDR, &reg_val, AW_DSP_16_DATA);
+ if (reg_val != AW88399_DSP_ODD_NUM_BIT_TEST) {
+ dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]",
+ reg_val, AW88399_DSP_ODD_NUM_BIT_TEST);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag)
+{
+ int ret;
+
+ switch (flag) {
+ case AW88399_DEV_MEMCLK_PLL:
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_MEM_CLKSEL_MASK,
+ AW88399_MEM_CLKSEL_DAPHCLK_VALUE);
+ if (ret)
+ dev_err(aw_dev->dev, "memclk select pll failed");
+ break;
+ case AW88399_DEV_MEMCLK_OSC:
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_MEM_CLKSEL_MASK,
+ AW88399_MEM_CLKSEL_OSCCLK_VALUE);
+ if (ret)
+ dev_err(aw_dev->dev, "memclk select OSC failed");
+ break;
+ default:
+ dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x", flag);
+ break;
+ }
+}
+
+static void aw_dev_get_cur_mode_st(struct aw_device *aw_dev)
+{
+ struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL_REG, &reg_val);
+ if (ret) {
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+ return;
+ }
+ if ((reg_val & (~AW88399_RCV_MODE_MASK)) == AW88399_RCV_MODE_RECEIVER_VALUE)
+ profctrl_desc->cur_mode = AW88399_RCV_MODE;
+ else
+ profctrl_desc->cur_mode = AW88399_NOT_RCV_MODE;
+}
+
+static int aw_dev_update_reg_container(struct aw88399 *aw88399,
+ unsigned char *data, unsigned int len)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ u16 read_vol, reg_val;
+ int data_len, i, ret;
+ int16_t *reg_data;
+ u8 reg_addr;
+
+ 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 == AW88399_DSPVCALB_REG) {
+ aw88399->vcalb_init_val = reg_val;
+ continue;
+ }
+
+ if (reg_addr == AW88399_SYSCTRL_REG) {
+ if (reg_val & (~AW88399_DSPBY_MASK))
+ aw_dev->dsp_cfg = AW88399_DEV_DSP_BYPASS;
+ else
+ aw_dev->dsp_cfg = AW88399_DEV_DSP_WORK;
+
+ reg_val &= (AW88399_HMUTE_MASK | AW88399_PWDN_MASK |
+ AW88399_DSPBY_MASK);
+ reg_val |= (AW88399_HMUTE_ENABLE_VALUE | AW88399_PWDN_POWER_DOWN_VALUE |
+ AW88399_DSPBY_BYPASS_VALUE);
+ }
+
+ if (reg_addr == AW88399_I2SCTRL3_REG) {
+ reg_val &= AW88399_I2STXEN_MASK;
+ reg_val |= AW88399_I2STXEN_DISABLE_VALUE;
+ }
+
+ if (reg_addr == AW88399_SYSCTRL2_REG) {
+ read_vol = (reg_val & (~AW88399_VOL_MASK)) >>
+ AW88399_VOL_START_BIT;
+ aw_dev->volume_desc.init_volume = read_vol;
+ }
+
+ if (reg_addr == AW88399_DBGCTRL_REG) {
+ if ((reg_val & (~AW88399_EF_DBMD_MASK)) == AW88399_EF_DBMD_OR_VALUE)
+ aw88399->check_val = AW_EF_OR_CHECK;
+ else
+ aw88399->check_val = AW_EF_AND_CHECK;
+
+ aw88399->dither_st = reg_val & (~AW88399_DITHER_EN_MASK);
+ }
+
+ if (reg_addr == AW88399_CRCCTRL_REG)
+ aw88399->crc_init_val = reg_val;
+
+ ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
+ if (ret)
+ return ret;
+ }
+
+ aw_dev_pwd(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+
+ aw_dev_get_cur_mode_st(aw_dev);
+
+ if (aw_dev->prof_cur != aw_dev->prof_index)
+ vol_desc->ctl_volume = 0;
+ else
+ aw_dev_set_volume(aw_dev, vol_desc->ctl_volume);
+
+ return 0;
+}
+
+static int aw_dev_reg_update(struct aw88399 *aw88399,
+ unsigned char *data, unsigned int len)
+{
+ int ret;
+
+ if (!len || !data) {
+ dev_err(aw88399->aw_pa->dev, "reg data is null or len is 0");
+ return -EINVAL;
+ }
+
+ ret = aw_dev_update_reg_container(aw88399, data, len);
+ if (ret)
+ dev_err(aw88399->aw_pa->dev, "reg update failed");
+
+ return ret;
+}
+
+int aw88399_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;
+}
+EXPORT_SYMBOL_GPL(aw88399_dev_get_prof_name);
+
+static int aw88399_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 aw88399_dev_fw_update(struct aw88399 *aw88399, bool up_dsp_fw_en, bool force_up_en)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ struct aw_prof_desc *prof_index_desc;
+ struct aw_sec_data_desc *sec_desc;
+ char *prof_name;
+ int ret;
+
+ if ((aw_dev->prof_cur == aw_dev->prof_index) &&
+ (force_up_en == AW88399_FORCE_UPDATE_OFF)) {
+ dev_dbg(aw_dev->dev, "scene no change, not update");
+ return 0;
+ }
+
+ if (aw_dev->fw_status == AW88399_DEV_FW_FAILED) {
+ dev_err(aw_dev->dev, "fw status[%d] error", aw_dev->fw_status);
+ return -EPERM;
+ }
+
+ ret = aw88399_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name);
+ if (ret)
+ return ret;
+
+ dev_dbg(aw_dev->dev, "start update %s", prof_name);
+
+ ret = aw88399_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 = aw_dev_reg_update(aw88399, 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;
+ }
+
+ aw88399_dev_mute(aw_dev, true);
+
+ if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK)
+ aw_dev_dsp_enable(aw_dev, false);
+
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC);
+
+ ret = aw_dev_check_sram(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "check sram failed");
+ goto error;
+ }
+
+ if (up_dsp_fw_en) {
+ dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver);
+ ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data,
+ sec_desc[AW88395_DATA_TYPE_DSP_FW].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update dsp fw failed");
+ goto error;
+ }
+ }
+
+ /* update dsp config */
+ ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data,
+ sec_desc[AW88395_DATA_TYPE_DSP_CFG].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update dsp cfg failed");
+ goto error;
+ }
+
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
+
+ aw_dev->prof_cur = aw_dev->prof_index;
+
+ return 0;
+
+error:
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
+ return ret;
+}
+
+static void aw88399_start_pa(struct aw88399 *aw88399)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88399_START_RETRIES; i++) {
+ ret = aw88399_dev_start(aw88399);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "aw88399 device start failed. retry = %d", i);
+ ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_ON, true);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "fw update failed");
+ continue;
+ }
+ } else {
+ dev_dbg(aw88399->aw_pa->dev, "start success\n");
+ break;
+ }
+ }
+}
+
+void aw88399_startup_work(struct work_struct *work)
+{
+ struct aw88399 *aw88399 =
+ container_of(work, struct aw88399, start_work.work);
+
+ mutex_lock(&aw88399->lock);
+ aw88399_start_pa(aw88399);
+ mutex_unlock(&aw88399->lock);
+}
+EXPORT_SYMBOL_GPL(aw88399_startup_work);
+
+void aw88399_start(struct aw88399 *aw88399, bool sync_start)
+{
+ int ret;
+
+ if (aw88399->aw_pa->fw_status != AW88399_DEV_FW_OK)
+ return;
+
+ if (aw88399->aw_pa->status == AW88399_DEV_PW_ON)
+ return;
+
+ ret = aw88399_dev_fw_update(aw88399, aw88399->fw_needs_reload ?
+ AW88399_DSP_FW_UPDATE_ON : AW88399_DSP_FW_UPDATE_OFF, true);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "fw update failed.");
+ return;
+ }
+
+ aw88399->fw_needs_reload = false;
+
+ if (sync_start == AW88399_SYNC_START)
+ aw88399_start_pa(aw88399);
+ else
+ queue_delayed_work(system_dfl_wq,
+ &aw88399->start_work,
+ AW88399_START_WORK_DELAY_MS);
+}
+EXPORT_SYMBOL_GPL(aw88399_start);
+
+static int aw_dev_check_sysint(struct aw_device *aw_dev)
+{
+ u16 reg_val;
+
+ aw_dev_get_int_status(aw_dev, &reg_val);
+ if (reg_val & AW88399_BIT_SYSINT_CHECK) {
+ dev_err(aw_dev->dev, "pa stop check fail:0x%04x", reg_val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int aw88399_stop(struct aw_device *aw_dev)
+{
+ struct aw_sec_data_desc *dsp_cfg =
+ &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG];
+ struct aw_sec_data_desc *dsp_fw =
+ &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW];
+ int int_st;
+
+ if (aw_dev->status == AW88399_DEV_PW_OFF) {
+ dev_dbg(aw_dev->dev, "already power off");
+ return 0;
+ }
+
+ aw_dev->status = AW88399_DEV_PW_OFF;
+
+ aw88399_dev_mute(aw_dev, true);
+ usleep_range(AW88399_4000_US, AW88399_4000_US + 100);
+
+ aw_dev_i2s_tx_enable(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 100);
+
+ int_st = aw_dev_check_sysint(aw_dev);
+
+ aw_dev_dsp_enable(aw_dev, false);
+
+ aw_dev_amppd(aw_dev, true);
+
+ if (int_st) {
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC);
+ aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len);
+ aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len);
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
+ }
+
+ aw_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aw88399_stop);
+
+static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg)
+{
+ struct aw_device *aw_dev = aw88399->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;
+ }
+ aw_dev->fade_in_time = AW88399_1000_US / 10;
+ aw_dev->fade_out_time = AW88399_1000_US >> 1;
+ aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id;
+ aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id;
+
+ ret = aw88399_dev_fw_update(aw88399, AW88399_FORCE_UPDATE_ON, AW88399_DSP_FW_UPDATE_ON);
+ if (ret) {
+ dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret);
+ return ret;
+ }
+
+ aw88399_dev_mute(aw_dev, true);
+
+ /* close tx feedback */
+ aw_dev_i2s_tx_enable(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 100);
+
+ /* enable amppd */
+ aw_dev_amppd(aw_dev, true);
+
+ /* close dsp */
+ aw_dev_dsp_enable(aw_dev, false);
+ /* set power down */
+ aw_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+
+int aw88399_request_firmware_file(struct aw88399 *aw88399)
+{
+ const struct firmware *cont __free(firmware) = NULL;
+ int ret;
+
+ aw88399->aw_pa->fw_status = AW88399_DEV_FW_FAILED;
+
+ ret = request_firmware(&cont, AW88399_ACF_FILE, aw88399->aw_pa->dev);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "request [%s] failed!", AW88399_ACF_FILE);
+ return ret;
+ }
+
+ dev_dbg(aw88399->aw_pa->dev, "loaded %s - size: %zu\n",
+ AW88399_ACF_FILE, cont ? cont->size : 0);
+
+ aw88399->aw_cfg = devm_kzalloc(aw88399->aw_pa->dev,
+ struct_size(aw88399->aw_cfg, data, cont->size), GFP_KERNEL);
+ if (!aw88399->aw_cfg)
+ return -ENOMEM;
+
+ aw88399->aw_cfg->len = (int)cont->size;
+ memcpy(aw88399->aw_cfg->data, cont->data, cont->size);
+
+ ret = aw88395_dev_load_acf_check(aw88399->aw_pa, aw88399->aw_cfg);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "load [%s] failed!", AW88399_ACF_FILE);
+ return ret;
+ }
+
+ mutex_lock(&aw88399->lock);
+ /* aw device init */
+ ret = aw88399_dev_init(aw88399, aw88399->aw_cfg);
+ if (ret)
+ dev_err(aw88399->aw_pa->dev, "dev init failed");
+ mutex_unlock(&aw88399->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(aw88399_request_firmware_file);
+
+void aw88399_hw_reset(struct aw88399 *aw88399)
+{
+ if (aw88399->reset_gpio) {
+ gpiod_set_value_cansleep(aw88399->reset_gpio, 1);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ gpiod_set_value_cansleep(aw88399->reset_gpio, 0);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ gpiod_set_value_cansleep(aw88399->reset_gpio, 1);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ }
+}
+EXPORT_SYMBOL_GPL(aw88399_hw_reset);
+
+static void aw88399_parse_channel_dt(struct aw_device *aw_dev)
+{
+ struct device_node *np = aw_dev->dev->of_node;
+ u32 channel_value;
+ int ret;
+
+ ret = of_property_read_u32(np, "awinic,audio-channel", &channel_value);
+ if (ret) {
+ /*
+ * On ACPI systems, DT properties don't exist. Derive channel
+ * from I2C address: 0x34 -> channel 0 (left), 0x35 -> channel 1 (right)
+ */
+ aw_dev->channel = aw_dev->i2c->addr - 0x34;
+ dev_dbg(aw_dev->dev,
+ "DT channel property not found, using I2C address-based channel %d (addr 0x%02x)\n",
+ aw_dev->channel, aw_dev->i2c->addr);
+ return;
+ }
+ aw_dev->channel = channel_value;
+}
+
+int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap)
+{
+ struct aw_device *aw_dev;
+ unsigned int chip_id;
+ int ret;
+
+ ret = regmap_read(regmap, AW88399_ID_REG, &chip_id);
+ if (ret) {
+ dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
+ return ret;
+ }
+ if (chip_id != AW88399_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;
+ aw88399->aw_pa = aw_dev;
+
+ aw_dev->i2c = i2c;
+ aw_dev->dev = &i2c->dev;
+ aw_dev->regmap = regmap;
+ mutex_init(&aw_dev->dsp_lock);
+
+ aw_dev->chip_id = chip_id;
+ aw_dev->acf = NULL;
+ aw_dev->prof_info.prof_desc = NULL;
+ aw_dev->prof_info.count = 0;
+ aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
+ aw_dev->channel = AW88399_DEV_DEFAULT_CH;
+ aw_dev->fw_status = AW88399_DEV_FW_FAILED;
+
+ aw_dev->fade_step = AW88399_VOLUME_STEP_DB;
+ aw_dev->volume_desc.ctl_volume = AW88399_VOL_DEFAULT_VALUE;
+
+ aw88399_parse_channel_dt(aw_dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aw88399_init);
+
+void aw88399_dev_set_channel(struct aw88399 *aw88399, int channel)
+{
+ aw88399->aw_pa->channel = channel;
+}
+EXPORT_SYMBOL_GPL(aw88399_dev_set_channel);
+
+MODULE_DESCRIPTION("AW88399 common device library");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c
index b2ec3503f7e2..e9dab5e7bae3 100644
--- a/sound/soc/codecs/aw88399.c
+++ b/sound/soc/codecs/aw88399.c
@@ -7,1220 +7,16 @@
// Author: Weidong Wang <wangweidong.a@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/crc32.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
-#include <linux/firmware.h>
-#include <linux/minmax.h>
#include <linux/regmap.h>
#include <linux/sort.h>
#include <sound/soc.h>
#include "aw88399.h"
#include "aw88395/aw88395_device.h"
-static const struct regmap_config aw88399_remap_config = {
- .val_bits = 16,
- .reg_bits = 8,
- .max_register = AW88399_REG_MAX,
- .reg_format_endian = REGMAP_ENDIAN_LITTLE,
- .val_format_endian = REGMAP_ENDIAN_BIG,
-};
-
-static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd)
-{
- int ret;
-
- if (pwd)
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_PWDN_MASK, AW88399_PWDN_POWER_DOWN_VALUE);
- else
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_PWDN_MASK, AW88399_PWDN_WORKING_VALUE);
-
- if (ret)
- dev_dbg(aw_dev->dev, "%s failed", __func__);
-}
-
-static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status)
-{
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_SYSINT_REG, &reg_val);
- if (ret)
- dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret);
- else
- *int_status = reg_val;
-
- dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status);
-}
-
-static void aw_dev_clear_int_status(struct aw_device *aw_dev)
-{
- u16 int_status;
-
- /* read int status and clear */
- aw_dev_get_int_status(aw_dev, &int_status);
- /* make sure int status is clear */
- aw_dev_get_int_status(aw_dev, &int_status);
- if (int_status)
- dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status);
-}
-
-static int aw_dev_get_iis_status(struct aw_device *aw_dev)
-{
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, &reg_val);
- if (ret)
- return ret;
- if ((reg_val & AW88399_BIT_PLL_CHECK) != AW88399_BIT_PLL_CHECK) {
- dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int aw_dev_check_mode1_pll(struct aw_device *aw_dev)
-{
- int ret, i;
-
- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
- ret = aw_dev_get_iis_status(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "mode1 iis signal check error");
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- } else {
- return 0;
- }
- }
-
- return -EPERM;
-}
-
-static int aw_dev_check_mode2_pll(struct aw_device *aw_dev)
-{
- unsigned int reg_val;
- int ret, i;
-
- ret = regmap_read(aw_dev->regmap, AW88399_PLLCTRL2_REG, &reg_val);
- if (ret)
- return ret;
-
- reg_val &= (~AW88399_CCO_MUX_MASK);
- if (reg_val == AW88399_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, AW88399_PLLCTRL2_REG,
- ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_DIVIDED_VALUE);
- if (ret)
- return ret;
-
- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
- ret = aw_dev_get_iis_status(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "mode2 iis signal check error");
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- } else {
- break;
- }
- }
-
- /* change mode1 */
- regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG,
- ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_BYPASS_VALUE);
- if (ret == 0) {
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
- ret = aw_dev_get_iis_status(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error");
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- } else {
- break;
- }
- }
- }
-
- return ret;
-}
-
-static int aw_dev_check_syspll(struct aw_device *aw_dev)
-{
- int ret;
-
- ret = aw_dev_check_mode1_pll(aw_dev);
- if (ret) {
- dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
- ret = aw_dev_check_mode2_pll(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "mode2 check iis failed");
- return ret;
- }
- }
-
- return 0;
-}
-
-static int aw_dev_check_sysst(struct aw_device *aw_dev)
-{
- unsigned int check_val;
- unsigned int reg_val;
- int ret, i;
-
- ret = regmap_read(aw_dev->regmap, AW88399_PWMCTRL3_REG, &reg_val);
- if (ret)
- return ret;
-
- if (reg_val & (~AW88399_NOISE_GATE_EN_MASK))
- check_val = AW88399_BIT_SYSST_NOSWS_CHECK;
- else
- check_val = AW88399_BIT_SYSST_SWS_CHECK;
-
- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
- ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, &reg_val);
- if (ret)
- return ret;
-
- if ((reg_val & (~AW88399_BIT_SYSST_CHECK_MASK) & check_val) != check_val) {
- dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x",
- i, reg_val, AW88399_BIT_SYSST_NOSWS_CHECK);
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- } else {
- return 0;
- }
- }
-
- return -EPERM;
-}
-
-static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd)
-{
- int ret;
-
- if (amppd)
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_AMPPD_MASK, AW88399_AMPPD_POWER_DOWN_VALUE);
- else
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_AMPPD_MASK, AW88399_AMPPD_WORKING_VALUE);
-
- if (ret)
- dev_dbg(aw_dev->dev, "%s failed", __func__);
-}
-
-static void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable)
-{
- int ret;
-
- if (is_enable)
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_DSPBY_MASK, AW88399_DSPBY_WORKING_VALUE);
- else
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_DSPBY_MASK, AW88399_DSPBY_BYPASS_VALUE);
-
- if (ret)
- dev_dbg(aw_dev->dev, "%s failed\n", __func__);
-}
-
-static int aw88399_dev_get_icalk(struct aw88399 *aw88399, int16_t *icalk)
-{
- uint16_t icalkh_val, icalkl_val, icalk_val;
- struct aw_device *aw_dev = aw88399->aw_pa;
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRH4_REG, &reg_val);
- if (ret)
- return ret;
- icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK);
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_REG, &reg_val);
- if (ret)
- return ret;
- icalkl_val = reg_val & (~AW88399_EF_ISN_GESLP_L_MASK);
-
- if (aw88399->check_val == AW_EF_AND_CHECK)
- icalk_val = icalkh_val & icalkl_val;
- else
- icalk_val = icalkh_val | icalkl_val;
-
- if (icalk_val & (~AW88399_EF_ISN_GESLP_SIGN_MASK))
- icalk_val = icalk_val | AW88399_EF_ISN_GESLP_SIGN_NEG;
- *icalk = (int16_t)icalk_val;
-
- return 0;
-}
-
-static int aw88399_dev_get_vcalk(struct aw88399 *aw88399, int16_t *vcalk)
-{
- uint16_t vcalkh_val, vcalkl_val, vcalk_val;
- struct aw_device *aw_dev = aw88399->aw_pa;
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRH3_REG, &reg_val);
- if (ret)
- return ret;
-
- vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK);
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_REG, &reg_val);
- if (ret)
- return ret;
-
- vcalkl_val = reg_val & (~AW88399_EF_VSN_GESLP_L_MASK);
-
- if (aw88399->check_val == AW_EF_AND_CHECK)
- vcalk_val = vcalkh_val & vcalkl_val;
- else
- vcalk_val = vcalkh_val | vcalkl_val;
-
- if (vcalk_val & AW88399_EF_VSN_GESLP_SIGN_MASK)
- vcalk_val = vcalk_val | AW88399_EF_VSN_GESLP_SIGN_NEG;
- *vcalk = (int16_t)vcalk_val;
-
- return 0;
-}
-
-static int aw88399_dev_get_internal_vcalk(struct aw88399 *aw88399, int16_t *vcalk)
-{
- uint16_t vcalkh_val, vcalkl_val, vcalk_val;
- struct aw_device *aw_dev = aw88399->aw_pa;
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRH2_REG, &reg_val);
- if (ret)
- return ret;
- vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK);
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_REG, &reg_val);
- if (ret)
- return ret;
- vcalkl_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_L_MASK);
-
- if (aw88399->check_val == AW_EF_AND_CHECK)
- vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) &
- (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT);
- else
- vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) |
- (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT);
-
- if (vcalk_val & (~AW88399_TEM4_SIGN_MASK))
- vcalk_val = vcalk_val | AW88399_TEM4_SIGN_NEG;
-
- *vcalk = (int16_t)vcalk_val;
-
- return 0;
-}
-
-static int aw_dev_set_vcalb(struct aw88399 *aw88399)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- unsigned int vsense_select, vsense_value;
- int32_t ical_k, vcal_k, vcalb;
- int16_t icalk, vcalk;
- uint16_t reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_VSNCTRL1_REG, &vsense_value);
- if (ret)
- return ret;
-
- vsense_select = vsense_value & (~AW88399_VDSEL_MASK);
-
- ret = aw88399_dev_get_icalk(aw88399, &icalk);
- if (ret) {
- dev_err(aw_dev->dev, "get icalk failed\n");
- return ret;
- }
-
- ical_k = icalk * AW88399_ICABLK_FACTOR + AW88399_CABL_BASE_VALUE;
-
- switch (vsense_select) {
- case AW88399_DEV_VDSEL_VSENSE:
- ret = aw88399_dev_get_vcalk(aw88399, &vcalk);
- vcal_k = vcalk * AW88399_VCABLK_FACTOR + AW88399_CABL_BASE_VALUE;
- vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR *
- ical_k / vcal_k * aw88399->vcalb_init_val;
- break;
- case AW88399_DEV_VDSEL_DAC:
- ret = aw88399_dev_get_internal_vcalk(aw88399, &vcalk);
- vcal_k = vcalk * AW88399_VCABLK_DAC_FACTOR + AW88399_CABL_BASE_VALUE;
- vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_DAC_FACTOR /
- AW88399_ISCAL_DAC_FACTOR * ical_k /
- vcal_k * aw88399->vcalb_init_val;
- break;
- default:
- dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__);
- ret = -EINVAL;
- break;
- }
- if (ret)
- return ret;
-
- vcalb = vcalb >> AW88399_VCALB_ADJ_FACTOR;
- reg_val = (uint32_t)vcalb;
-
- regmap_write(aw_dev->regmap, AW88399_DSPVCALB_REG, reg_val);
-
- return 0;
-}
-
-static int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc)
-{
- struct aw_device *aw_dev =
- container_of(cali_desc, struct aw_device, cali_desc);
- uint16_t re_lbits, re_hbits;
- u32 cali_re;
- int ret;
-
- if ((aw_dev->cali_desc.cali_re >= AW88399_CALI_RE_MAX) ||
- (aw_dev->cali_desc.cali_re <= AW88399_CALI_RE_MIN))
- return -EINVAL;
-
- cali_re = AW88399_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re +
- aw_dev->cali_desc.ra), AW88399_DSP_RE_SHIFT);
-
- re_hbits = (cali_re & (~AW88399_CALI_RE_HBITS_MASK)) >> AW88399_CALI_RE_HBITS_SHIFT;
- re_lbits = (cali_re & (~AW88399_CALI_RE_LBITS_MASK)) >> AW88399_CALI_RE_LBITS_SHIFT;
-
- ret = regmap_write(aw_dev->regmap, AW88399_ACR1_REG, re_hbits);
- if (ret) {
- dev_err(aw_dev->dev, "set cali re error");
- return ret;
- }
-
- ret = regmap_write(aw_dev->regmap, AW88399_ACR2_REG, re_lbits);
- if (ret)
- dev_err(aw_dev->dev, "set cali re error");
-
- return ret;
-}
-
-static int aw_dev_fw_crc_check(struct aw_device *aw_dev)
-{
- uint16_t check_val, fw_len_val;
- unsigned int reg_val;
- int ret;
-
- /* calculate fw_end_addr */
- fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_FW_BASE_ADDR;
-
- /* write fw_end_addr to crc_end_addr */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_END_ADDR_MASK, fw_len_val);
- if (ret)
- return ret;
- /* enable fw crc check */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_ENABLE_VALUE);
-
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
-
- /* read crc check result */
- regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, &reg_val);
- if (ret)
- return ret;
-
- check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT;
-
- /* disable fw crc check */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_DISABLE_VALUE);
- if (ret)
- return ret;
-
- if (check_val != AW88399_CRC_CHECK_PASS_VAL) {
- dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x",
- __func__, check_val, AW88399_CRC_CHECK_PASS_VAL);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int aw_dev_cfg_crc_check(struct aw_device *aw_dev)
-{
- uint16_t check_val, cfg_len_val;
- unsigned int reg_val;
- int ret;
-
- /* calculate cfg end addr */
- cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_CFG_BASE_ADDR;
-
- /* write cfg_end_addr to crc_end_addr */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_END_ADDR_MASK, cfg_len_val);
- if (ret)
- return ret;
-
- /* enable cfg crc check */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_ENABLE_VALUE);
- if (ret)
- return ret;
-
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
-
- /* read crc check result */
- ret = regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, &reg_val);
- if (ret)
- return ret;
-
- check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT;
-
- /* disable cfg crc check */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_DISABLE_VALUE);
- if (ret)
- return ret;
-
- if (check_val != AW88399_CRC_CHECK_PASS_VAL) {
- dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x",
- check_val, AW88399_CRC_CHECK_PASS_VAL);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int aw_dev_hw_crc_check(struct aw88399 *aw88399)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- int ret;
-
- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
- ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_BYPASS_VALUE);
- if (ret)
- return ret;
-
- ret = aw_dev_fw_crc_check(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "fw_crc_check failed\n");
- goto crc_check_failed;
- }
-
- ret = aw_dev_cfg_crc_check(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "cfg_crc_check failed\n");
- goto crc_check_failed;
- }
-
- ret = regmap_write(aw_dev->regmap, AW88399_CRCCTRL_REG, aw88399->crc_init_val);
- if (ret)
- return ret;
-
- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
- ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE);
-
- return ret;
-
-crc_check_failed:
- regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
- ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE);
- return ret;
-}
-
-static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
-{
- int ret;
-
- if (flag)
- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCTRL3_REG,
- ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_ENABLE_VALUE);
- else
- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
- ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_DISABLE_VALUE);
-
- if (ret)
- dev_dbg(aw_dev->dev, "%s failed", __func__);
-}
-
-static int aw_dev_get_dsp_status(struct aw_device *aw_dev)
-{
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_WDT_REG, &reg_val);
- if (ret)
- return ret;
- if (!(reg_val & (~AW88399_WDT_CNT_MASK)))
- return -EPERM;
-
- return 0;
-}
-
-static int aw_dev_dsp_check(struct aw_device *aw_dev)
-{
- int ret, i;
-
- switch (aw_dev->dsp_cfg) {
- case AW88399_DEV_DSP_BYPASS:
- dev_dbg(aw_dev->dev, "dsp bypass");
- ret = 0;
- break;
- case AW88399_DEV_DSP_WORK:
- aw_dev_dsp_enable(aw_dev, false);
- aw_dev_dsp_enable(aw_dev, true);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
- for (i = 0; i < AW88399_DEV_DSP_CHECK_MAX; i++) {
- ret = aw_dev_get_dsp_status(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "dsp wdt status error=%d", ret);
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- }
- }
- break;
- default:
- dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg);
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
-{
- struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
- unsigned int reg_value;
- u16 real_value;
- int ret;
-
- real_value = min((value + vol_desc->init_volume), (unsigned int)AW88399_MUTE_VOL);
-
- ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL2_REG, &reg_value);
- if (ret)
- return ret;
-
- dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value);
-
- real_value = (real_value << AW88399_VOL_START_BIT) | (reg_value & AW88399_VOL_MASK);
-
- ret = regmap_write(aw_dev->regmap, AW88399_SYSCTRL2_REG, real_value);
-
- return ret;
-}
-
-static void aw_dev_fade_in(struct aw_device *aw_dev)
-{
- struct aw_volume_desc *desc = &aw_dev->volume_desc;
- u16 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) {
- aw_dev_set_volume(aw_dev, fade_in_vol);
- return;
- }
-
- for (i = AW88399_MUTE_VOL; i >= fade_in_vol; i -= fade_step) {
- aw_dev_set_volume(aw_dev, i);
- usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10);
- }
-
- if (i != fade_in_vol)
- aw_dev_set_volume(aw_dev, fade_in_vol);
-}
-
-static void aw_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) {
- aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL);
- return;
- }
-
- for (i = desc->ctl_volume; i <= AW88399_MUTE_VOL; i += fade_step) {
- aw_dev_set_volume(aw_dev, i);
- usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
- }
-
- if (i != AW88399_MUTE_VOL) {
- aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL);
- usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
- }
-}
-
-static void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute)
-{
- if (is_mute) {
- aw_dev_fade_out(aw_dev);
- regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_HMUTE_MASK, AW88399_HMUTE_ENABLE_VALUE);
- } else {
- regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_HMUTE_MASK, AW88399_HMUTE_DISABLE_VALUE);
- aw_dev_fade_in(aw_dev);
- }
-}
-
-static void aw88399_dev_set_dither(struct aw88399 *aw88399, bool dither)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
-
- if (dither)
- regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
- ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_ENABLE_VALUE);
- else
- regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
- ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_DISABLE_VALUE);
-}
-
-static int aw88399_dev_start(struct aw88399 *aw88399)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- int ret;
-
- if (aw_dev->status == AW88399_DEV_PW_ON) {
- dev_dbg(aw_dev->dev, "already power on");
- return 0;
- }
-
- aw88399_dev_set_dither(aw88399, false);
-
- /* power on */
- aw_dev_pwd(aw_dev, false);
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
-
- ret = aw_dev_check_syspll(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "pll check failed cannot start");
- goto pll_check_fail;
- }
-
- /* amppd on */
- aw_dev_amppd(aw_dev, false);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 50);
-
- /* check i2s status */
- ret = aw_dev_check_sysst(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "sysst check failed");
- goto sysst_check_fail;
- }
-
- if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) {
- ret = aw_dev_hw_crc_check(aw88399);
- if (ret) {
- dev_err(aw_dev->dev, "dsp crc check failed");
- goto crc_check_fail;
- }
- aw_dev_dsp_enable(aw_dev, false);
- aw_dev_set_vcalb(aw88399);
- aw_dev_update_cali_re(&aw_dev->cali_desc);
-
- ret = aw_dev_dsp_check(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "dsp status check failed");
- goto dsp_check_fail;
- }
- } else {
- dev_dbg(aw_dev->dev, "start pa with dsp bypass");
- }
-
- /* enable tx feedback */
- aw_dev_i2s_tx_enable(aw_dev, true);
-
- if (aw88399->dither_st == AW88399_DITHER_EN_ENABLE_VALUE)
- aw88399_dev_set_dither(aw88399, true);
-
- /* close mute */
- aw88399_dev_mute(aw_dev, false);
- /* clear inturrupt */
- aw_dev_clear_int_status(aw_dev);
- aw_dev->status = AW88399_DEV_PW_ON;
-
- return 0;
-
-dsp_check_fail:
-crc_check_fail:
- aw_dev_dsp_enable(aw_dev, false);
-sysst_check_fail:
- aw_dev_clear_int_status(aw_dev);
- aw_dev_amppd(aw_dev, true);
-pll_check_fail:
- aw_dev_pwd(aw_dev, true);
- aw_dev->status = AW88399_DEV_PW_OFF;
-
- return ret;
-}
-
-static int aw_dev_dsp_update_container(struct aw_device *aw_dev,
- unsigned char *data, unsigned int len, unsigned short base)
-{
- u32 tmp_len;
- int i, ret;
-
- ret = regmap_write(aw_dev->regmap, AW88399_DSPMADD_REG, base);
- if (ret)
- return ret;
-
- for (i = 0; i < len; i += AW88399_MAX_RAM_WRITE_BYTE_SIZE) {
- tmp_len = min(len - i, AW88399_MAX_RAM_WRITE_BYTE_SIZE);
- ret = regmap_raw_write(aw_dev->regmap, AW88399_DSPMDAT_REG,
- &data[i], tmp_len);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int aw_dev_get_ra(struct aw_cali_desc *cali_desc)
-{
- struct aw_device *aw_dev =
- container_of(cali_desc, struct aw_device, cali_desc);
- u32 dsp_ra;
- int ret;
-
- ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_RA,
- &dsp_ra, AW_DSP_32_DATA);
- if (ret) {
- dev_err(aw_dev->dev, "read ra error");
- return ret;
- }
-
- cali_desc->ra = AW88399_DSP_RE_TO_SHOW_RE(dsp_ra,
- AW88399_DSP_RE_SHIFT);
-
- return 0;
-}
-
-static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev,
- unsigned char *data, unsigned int len)
-{
- int ret;
-
- dev_dbg(aw_dev->dev, "dsp config len:%d", len);
-
- if (!len || !data) {
- dev_err(aw_dev->dev, "dsp config data is null or len is 0");
- return -EINVAL;
- }
-
- ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_CFG_ADDR);
- if (ret)
- return ret;
-
- aw_dev->dsp_cfg_len = len;
-
- ret = aw_dev_get_ra(&aw_dev->cali_desc);
-
- return ret;
-}
-
-static int aw_dev_dsp_update_fw(struct aw_device *aw_dev,
- unsigned char *data, unsigned int len)
-{
- int ret;
-
- dev_dbg(aw_dev->dev, "dsp firmware len:%d", len);
-
- if (!len || !data) {
- dev_err(aw_dev->dev, "dsp firmware data is null or len is 0");
- return -EINVAL;
- }
-
- aw_dev->dsp_fw_len = len;
- ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_FW_ADDR);
-
- return ret;
-}
-
-static int aw_dev_check_sram(struct aw_device *aw_dev)
-{
- unsigned int reg_val;
-
- /* read dsp_rom_check_reg */
- aw_dev_dsp_read(aw_dev, AW88399_DSP_ROM_CHECK_ADDR, &reg_val, AW_DSP_16_DATA);
- if (reg_val != AW88399_DSP_ROM_CHECK_DATA) {
- dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]",
- reg_val, AW88399_DSP_ROM_CHECK_DATA);
- return -EPERM;
- }
-
- /* check dsp_cfg_base_addr */
- aw_dev_dsp_write(aw_dev, AW88399_DSP_CFG_ADDR,
- AW88399_DSP_ODD_NUM_BIT_TEST, AW_DSP_16_DATA);
- aw_dev_dsp_read(aw_dev, AW88399_DSP_CFG_ADDR, &reg_val, AW_DSP_16_DATA);
- if (reg_val != AW88399_DSP_ODD_NUM_BIT_TEST) {
- dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]",
- reg_val, AW88399_DSP_ODD_NUM_BIT_TEST);
- return -EPERM;
- }
-
- return 0;
-}
-
-static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag)
-{
- int ret;
-
- switch (flag) {
- case AW88399_DEV_MEMCLK_PLL:
- ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
- ~AW88399_MEM_CLKSEL_MASK,
- AW88399_MEM_CLKSEL_DAPHCLK_VALUE);
- if (ret)
- dev_err(aw_dev->dev, "memclk select pll failed");
- break;
- case AW88399_DEV_MEMCLK_OSC:
- ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
- ~AW88399_MEM_CLKSEL_MASK,
- AW88399_MEM_CLKSEL_OSCCLK_VALUE);
- if (ret)
- dev_err(aw_dev->dev, "memclk select OSC failed");
- break;
- default:
- dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x", flag);
- break;
- }
-}
-
-static void aw_dev_get_cur_mode_st(struct aw_device *aw_dev)
-{
- struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc;
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL_REG, &reg_val);
- if (ret) {
- dev_dbg(aw_dev->dev, "%s failed", __func__);
- return;
- }
- if ((reg_val & (~AW88399_RCV_MODE_MASK)) == AW88399_RCV_MODE_RECEIVER_VALUE)
- profctrl_desc->cur_mode = AW88399_RCV_MODE;
- else
- profctrl_desc->cur_mode = AW88399_NOT_RCV_MODE;
-}
-
-static int aw_dev_update_reg_container(struct aw88399 *aw88399,
- unsigned char *data, unsigned int len)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
- u16 read_vol, reg_val;
- int data_len, i, ret;
- int16_t *reg_data;
- u8 reg_addr;
-
- 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 == AW88399_DSPVCALB_REG) {
- aw88399->vcalb_init_val = reg_val;
- continue;
- }
-
- if (reg_addr == AW88399_SYSCTRL_REG) {
- if (reg_val & (~AW88399_DSPBY_MASK))
- aw_dev->dsp_cfg = AW88399_DEV_DSP_BYPASS;
- else
- aw_dev->dsp_cfg = AW88399_DEV_DSP_WORK;
-
- reg_val &= (AW88399_HMUTE_MASK | AW88399_PWDN_MASK |
- AW88399_DSPBY_MASK);
- reg_val |= (AW88399_HMUTE_ENABLE_VALUE | AW88399_PWDN_POWER_DOWN_VALUE |
- AW88399_DSPBY_BYPASS_VALUE);
- }
-
- if (reg_addr == AW88399_I2SCTRL3_REG) {
- reg_val &= AW88399_I2STXEN_MASK;
- reg_val |= AW88399_I2STXEN_DISABLE_VALUE;
- }
-
- if (reg_addr == AW88399_SYSCTRL2_REG) {
- read_vol = (reg_val & (~AW88399_VOL_MASK)) >>
- AW88399_VOL_START_BIT;
- aw_dev->volume_desc.init_volume = read_vol;
- }
-
- if (reg_addr == AW88399_DBGCTRL_REG) {
- if ((reg_val & (~AW88399_EF_DBMD_MASK)) == AW88399_EF_DBMD_OR_VALUE)
- aw88399->check_val = AW_EF_OR_CHECK;
- else
- aw88399->check_val = AW_EF_AND_CHECK;
-
- aw88399->dither_st = reg_val & (~AW88399_DITHER_EN_MASK);
- }
-
- if (reg_addr == AW88399_CRCCTRL_REG)
- aw88399->crc_init_val = reg_val;
-
- ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
- if (ret)
- return ret;
- }
-
- aw_dev_pwd(aw_dev, false);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
-
- aw_dev_get_cur_mode_st(aw_dev);
-
- if (aw_dev->prof_cur != aw_dev->prof_index)
- vol_desc->ctl_volume = 0;
- else
- aw_dev_set_volume(aw_dev, vol_desc->ctl_volume);
-
- return 0;
-}
-
-static int aw_dev_reg_update(struct aw88399 *aw88399,
- unsigned char *data, unsigned int len)
-{
- int ret;
-
- if (!len || !data) {
- dev_err(aw88399->aw_pa->dev, "reg data is null or len is 0");
- return -EINVAL;
- }
-
- ret = aw_dev_update_reg_container(aw88399, data, len);
- if (ret)
- dev_err(aw88399->aw_pa->dev, "reg update failed");
-
- return ret;
-}
-
-static int aw88399_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 aw88399_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 aw88399_dev_fw_update(struct aw88399 *aw88399, bool up_dsp_fw_en, bool force_up_en)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- struct aw_prof_desc *prof_index_desc;
- struct aw_sec_data_desc *sec_desc;
- char *prof_name;
- int ret;
-
- if ((aw_dev->prof_cur == aw_dev->prof_index) &&
- (force_up_en == AW88399_FORCE_UPDATE_OFF)) {
- dev_dbg(aw_dev->dev, "scene no change, not update");
- return 0;
- }
-
- if (aw_dev->fw_status == AW88399_DEV_FW_FAILED) {
- dev_err(aw_dev->dev, "fw status[%d] error", aw_dev->fw_status);
- return -EPERM;
- }
-
- ret = aw88399_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name);
- if (ret)
- return ret;
-
- dev_dbg(aw_dev->dev, "start update %s", prof_name);
-
- ret = aw88399_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 = aw_dev_reg_update(aw88399, 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;
- }
-
- aw88399_dev_mute(aw_dev, true);
-
- if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK)
- aw_dev_dsp_enable(aw_dev, false);
-
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC);
-
- ret = aw_dev_check_sram(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "check sram failed");
- goto error;
- }
-
- if (up_dsp_fw_en) {
- dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver);
- ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data,
- sec_desc[AW88395_DATA_TYPE_DSP_FW].len);
- if (ret) {
- dev_err(aw_dev->dev, "update dsp fw failed");
- goto error;
- }
- }
-
- /* update dsp config */
- ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data,
- sec_desc[AW88395_DATA_TYPE_DSP_CFG].len);
- if (ret) {
- dev_err(aw_dev->dev, "update dsp cfg failed");
- goto error;
- }
-
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
-
- aw_dev->prof_cur = aw_dev->prof_index;
-
- return 0;
-
-error:
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
- return ret;
-}
-
-static void aw88399_start_pa(struct aw88399 *aw88399)
-{
- int ret, i;
-
- for (i = 0; i < AW88399_START_RETRIES; i++) {
- ret = aw88399_dev_start(aw88399);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "aw88399 device start failed. retry = %d", i);
- ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_ON, true);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "fw update failed");
- continue;
- }
- } else {
- dev_dbg(aw88399->aw_pa->dev, "start success\n");
- break;
- }
- }
-}
-
-static void aw88399_startup_work(struct work_struct *work)
-{
- struct aw88399 *aw88399 =
- container_of(work, struct aw88399, start_work.work);
-
- mutex_lock(&aw88399->lock);
- aw88399_start_pa(aw88399);
- mutex_unlock(&aw88399->lock);
-}
-
-static void aw88399_start(struct aw88399 *aw88399, bool sync_start)
-{
- int ret;
-
- if (aw88399->aw_pa->fw_status != AW88399_DEV_FW_OK)
- return;
-
- if (aw88399->aw_pa->status == AW88399_DEV_PW_ON)
- return;
-
- ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_OFF, true);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "fw update failed.");
- return;
- }
-
- if (sync_start == AW88399_SYNC_START)
- aw88399_start_pa(aw88399);
- else
- queue_delayed_work(system_dfl_wq,
- &aw88399->start_work,
- AW88399_START_WORK_DELAY_MS);
-}
-
-static int aw_dev_check_sysint(struct aw_device *aw_dev)
-{
- u16 reg_val;
-
- aw_dev_get_int_status(aw_dev, &reg_val);
- if (reg_val & AW88399_BIT_SYSINT_CHECK) {
- dev_err(aw_dev->dev, "pa stop check fail:0x%04x", reg_val);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int aw88399_stop(struct aw_device *aw_dev)
-{
- struct aw_sec_data_desc *dsp_cfg =
- &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG];
- struct aw_sec_data_desc *dsp_fw =
- &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW];
- int int_st;
-
- if (aw_dev->status == AW88399_DEV_PW_OFF) {
- dev_dbg(aw_dev->dev, "already power off");
- return 0;
- }
-
- aw_dev->status = AW88399_DEV_PW_OFF;
-
- aw88399_dev_mute(aw_dev, true);
- usleep_range(AW88399_4000_US, AW88399_4000_US + 100);
-
- aw_dev_i2s_tx_enable(aw_dev, false);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 100);
-
- int_st = aw_dev_check_sysint(aw_dev);
-
- aw_dev_dsp_enable(aw_dev, false);
-
- aw_dev_amppd(aw_dev, true);
-
- if (int_st) {
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC);
- aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len);
- aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len);
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
- }
-
- aw_dev_pwd(aw_dev, true);
-
- return 0;
-}
-
static struct snd_soc_dai_driver aw88399_dai[] = {
{
.name = "aw88399-aif",
@@ -1702,11 +498,10 @@ static int aw88399_profile_set(struct snd_kcontrol *kcontrol,
struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec);
int ret;
- mutex_lock(&aw88399->lock);
+ guard(mutex)(&aw88399->lock);
ret = aw88399_dev_set_profile_index(aw88399->aw_pa, ucontrol->value.integer.value[0]);
if (ret) {
dev_dbg(codec->dev, "profile index does not change");
- mutex_unlock(&aw88399->lock);
return 0;
}
@@ -1715,8 +510,6 @@ static int aw88399_profile_set(struct snd_kcontrol *kcontrol,
aw88399_start(aw88399, AW88399_SYNC_START);
}
- mutex_unlock(&aw88399->lock);
-
return 1;
}
@@ -1869,86 +662,6 @@ static int aw88399_calib_set(struct snd_kcontrol *kcontrol,
return 0;
}
-static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg)
-{
- struct aw_device *aw_dev = aw88399->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;
- }
- aw_dev->fade_in_time = AW88399_1000_US / 10;
- aw_dev->fade_out_time = AW88399_1000_US >> 1;
- aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id;
- aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id;
-
- ret = aw88399_dev_fw_update(aw88399, AW88399_FORCE_UPDATE_ON, AW88399_DSP_FW_UPDATE_ON);
- if (ret) {
- dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret);
- return ret;
- }
-
- aw88399_dev_mute(aw_dev, true);
-
- /* close tx feedback */
- aw_dev_i2s_tx_enable(aw_dev, false);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 100);
-
- /* enable amppd */
- aw_dev_amppd(aw_dev, true);
-
- /* close dsp */
- aw_dev_dsp_enable(aw_dev, false);
- /* set power down */
- aw_dev_pwd(aw_dev, true);
-
- return 0;
-}
-
-static int aw88399_request_firmware_file(struct aw88399 *aw88399)
-{
- const struct firmware *cont = NULL;
- int ret;
-
- aw88399->aw_pa->fw_status = AW88399_DEV_FW_FAILED;
-
- ret = request_firmware(&cont, AW88399_ACF_FILE, aw88399->aw_pa->dev);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "request [%s] failed!", AW88399_ACF_FILE);
- return ret;
- }
-
- dev_dbg(aw88399->aw_pa->dev, "loaded %s - size: %zu\n",
- AW88399_ACF_FILE, cont ? cont->size : 0);
-
- aw88399->aw_cfg = devm_kzalloc(aw88399->aw_pa->dev,
- struct_size(aw88399->aw_cfg, data, cont->size), GFP_KERNEL);
- if (!aw88399->aw_cfg) {
- release_firmware(cont);
- return -ENOMEM;
- }
- aw88399->aw_cfg->len = (int)cont->size;
- memcpy(aw88399->aw_cfg->data, cont->data, cont->size);
- release_firmware(cont);
-
- ret = aw88395_dev_load_acf_check(aw88399->aw_pa, aw88399->aw_cfg);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "load [%s] failed!", AW88399_ACF_FILE);
- return ret;
- }
-
- mutex_lock(&aw88399->lock);
- /* aw device init */
- ret = aw88399_dev_init(aw88399, aw88399->aw_cfg);
- if (ret)
- dev_err(aw88399->aw_pa->dev, "dev init failed");
- mutex_unlock(&aw88399->lock);
-
- return ret;
-}
-
static const struct snd_kcontrol_new aw88399_controls[] = {
SOC_SINGLE_EXT("PCM Playback Volume", AW88399_SYSCTRL2_REG,
6, AW88399_MUTE_VOL, 0, aw88399_volume_get,
@@ -1975,7 +688,7 @@ static int aw88399_playback_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct aw88399 *aw88399 = snd_soc_component_get_drvdata(component);
- mutex_lock(&aw88399->lock);
+ guard(mutex)(&aw88399->lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
aw88399_start(aw88399, AW88399_ASYNC_START);
@@ -1986,7 +699,6 @@ static int aw88399_playback_event(struct snd_soc_dapm_widget *w,
default:
break;
}
- mutex_unlock(&aw88399->lock);
return 0;
}
@@ -2040,70 +752,6 @@ static const struct snd_soc_component_driver soc_codec_dev_aw88399 = {
.num_controls = ARRAY_SIZE(aw88399_controls),
};
-static void aw88399_hw_reset(struct aw88399 *aw88399)
-{
- if (aw88399->reset_gpio) {
- gpiod_set_value_cansleep(aw88399->reset_gpio, 1);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
- gpiod_set_value_cansleep(aw88399->reset_gpio, 0);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
- gpiod_set_value_cansleep(aw88399->reset_gpio, 1);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
- }
-}
-
-static void aw88399_parse_channel_dt(struct aw_device *aw_dev)
-{
- struct device_node *np = aw_dev->dev->of_node;
- u32 channel_value;
-
- of_property_read_u32(np, "awinic,audio-channel", &channel_value);
- aw_dev->channel = channel_value;
-}
-
-static int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap)
-{
- struct aw_device *aw_dev;
- unsigned int chip_id;
- int ret;
-
- ret = regmap_read(regmap, AW88399_ID_REG, &chip_id);
- if (ret) {
- dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
- return ret;
- }
- if (chip_id != AW88399_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;
- aw88399->aw_pa = aw_dev;
-
- aw_dev->i2c = i2c;
- aw_dev->dev = &i2c->dev;
- aw_dev->regmap = regmap;
- mutex_init(&aw_dev->dsp_lock);
-
- aw_dev->chip_id = chip_id;
- aw_dev->acf = NULL;
- aw_dev->prof_info.prof_desc = NULL;
- aw_dev->prof_info.count = 0;
- aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
- aw_dev->channel = AW88399_DEV_DEFAULT_CH;
- aw_dev->fw_status = AW88399_DEV_FW_FAILED;
-
- aw_dev->fade_step = AW88399_VOLUME_STEP_DB;
- aw_dev->volume_desc.ctl_volume = AW88399_VOL_DEFAULT_VALUE;
-
- aw88399_parse_channel_dt(aw_dev);
-
- return 0;
-}
-
static int aw88399_i2c_probe(struct i2c_client *i2c)
{
struct aw88399 *aw88399;
diff --git a/sound/soc/codecs/aw88399.h b/sound/soc/codecs/aw88399.h
index b386f4836748..04123bf0ad84 100644
--- a/sound/soc/codecs/aw88399.h
+++ b/sound/soc/codecs/aw88399.h
@@ -10,512 +10,10 @@
#ifndef __AW88399_H__
#define __AW88399_H__
-/* registers list */
-#define AW88399_ID_REG (0x00)
-#define AW88399_SYSST_REG (0x01)
-#define AW88399_SYSINT_REG (0x02)
-#define AW88399_SYSINTM_REG (0x03)
-#define AW88399_SYSCTRL_REG (0x04)
-#define AW88399_SYSCTRL2_REG (0x05)
-#define AW88399_I2SCTRL1_REG (0x06)
-#define AW88399_I2SCTRL2_REG (0x07)
-#define AW88399_I2SCTRL3_REG (0x08)
-#define AW88399_DACCFG1_REG (0x09)
-#define AW88399_DACCFG2_REG (0x0A)
-#define AW88399_DACCFG3_REG (0x0B)
-#define AW88399_DACCFG4_REG (0x0C)
-#define AW88399_DACCFG5_REG (0x0D)
-#define AW88399_DACCFG6_REG (0x0E)
-#define AW88399_DACCFG7_REG (0x0F)
-#define AW88399_MPDCFG1_REG (0x10)
-#define AW88399_MPDCFG2_REG (0x11)
-#define AW88399_MPDCFG3_REG (0x12)
-#define AW88399_MPDCFG4_REG (0x13)
-#define AW88399_PWMCTRL1_REG (0x14)
-#define AW88399_PWMCTRL2_REG (0x15)
-#define AW88399_PWMCTRL3_REG (0x16)
-#define AW88399_I2SCFG1_REG (0x17)
-#define AW88399_DBGCTRL_REG (0x18)
-#define AW88399_HAGCST_REG (0x20)
-#define AW88399_VBAT_REG (0x21)
-#define AW88399_TEMP_REG (0x22)
-#define AW88399_PVDD_REG (0x23)
-#define AW88399_ISNDAT_REG (0x24)
-#define AW88399_VSNDAT_REG (0x25)
-#define AW88399_I2SINT_REG (0x26)
-#define AW88399_I2SCAPCNT_REG (0x27)
-#define AW88399_ANASTA1_REG (0x28)
-#define AW88399_ANASTA2_REG (0x29)
-#define AW88399_ANASTA3_REG (0x2A)
-#define AW88399_TESTDET_REG (0x2B)
-#define AW88399_DSMCFG1_REG (0x30)
-#define AW88399_DSMCFG2_REG (0x31)
-#define AW88399_DSMCFG3_REG (0x32)
-#define AW88399_DSMCFG4_REG (0x33)
-#define AW88399_DSMCFG5_REG (0x34)
-#define AW88399_DSMCFG6_REG (0x35)
-#define AW88399_DSMCFG7_REG (0x36)
-#define AW88399_DSMCFG8_REG (0x37)
-#define AW88399_TESTIN_REG (0x38)
-#define AW88399_TESTOUT_REG (0x39)
-#define AW88399_MEMTEST_REG (0x3A)
-#define AW88399_VSNCTRL1_REG (0x3B)
-#define AW88399_ISNCTRL1_REG (0x3C)
-#define AW88399_ISNCTRL2_REG (0x3D)
-#define AW88399_DSPMADD_REG (0x40)
-#define AW88399_DSPMDAT_REG (0x41)
-#define AW88399_WDT_REG (0x42)
-#define AW88399_ACR1_REG (0x43)
-#define AW88399_ACR2_REG (0x44)
-#define AW88399_ASR1_REG (0x45)
-#define AW88399_ASR2_REG (0x46)
-#define AW88399_DSPCFG_REG (0x47)
-#define AW88399_ASR3_REG (0x48)
-#define AW88399_ASR4_REG (0x49)
-#define AW88399_DSPVCALB_REG (0x4A)
-#define AW88399_CRCCTRL_REG (0x4B)
-#define AW88399_DSPDBG1_REG (0x4C)
-#define AW88399_DSPDBG2_REG (0x4D)
-#define AW88399_DSPDBG3_REG (0x4E)
-#define AW88399_PLLCTRL1_REG (0x50)
-#define AW88399_PLLCTRL2_REG (0x51)
-#define AW88399_PLLCTRL3_REG (0x52)
-#define AW88399_CDACTRL1_REG (0x53)
-#define AW88399_CDACTRL2_REG (0x54)
-#define AW88399_CDACTRL3_REG (0x55)
-#define AW88399_SADCCTRL1_REG (0x56)
-#define AW88399_SADCCTRL2_REG (0x57)
-#define AW88399_BOPCTRL1_REG (0x58)
-#define AW88399_BOPCTRL2_REG (0x5A)
-#define AW88399_BOPCTRL3_REG (0x5B)
-#define AW88399_BOPCTRL4_REG (0x5C)
-#define AW88399_BOPCTRL5_REG (0x5D)
-#define AW88399_BOPCTRL6_REG (0x5E)
-#define AW88399_BOPCTRL7_REG (0x5F)
-#define AW88399_BSTCTRL1_REG (0x60)
-#define AW88399_BSTCTRL2_REG (0x61)
-#define AW88399_BSTCTRL3_REG (0x62)
-#define AW88399_BSTCTRL4_REG (0x63)
-#define AW88399_BSTCTRL5_REG (0x64)
-#define AW88399_BSTCTRL6_REG (0x65)
-#define AW88399_BSTCTRL7_REG (0x66)
-#define AW88399_BSTCTRL8_REG (0x67)
-#define AW88399_BSTCTRL9_REG (0x68)
-#define AW88399_BSTCTRL10_REG (0x69)
-#define AW88399_CPCTRL_REG (0x6A)
-#define AW88399_EFWH_REG (0x6C)
-#define AW88399_EFWM2_REG (0x6D)
-#define AW88399_EFWM1_REG (0x6E)
-#define AW88399_EFWL_REG (0x6F)
-#define AW88399_TESTCTRL1_REG (0x70)
-#define AW88399_TESTCTRL2_REG (0x71)
-#define AW88399_EFCTRL1_REG (0x72)
-#define AW88399_EFCTRL2_REG (0x73)
-#define AW88399_EFRH4_REG (0x74)
-#define AW88399_EFRH3_REG (0x75)
-#define AW88399_EFRH2_REG (0x76)
-#define AW88399_EFRH1_REG (0x77)
-#define AW88399_EFRL4_REG (0x78)
-#define AW88399_EFRL3_REG (0x79)
-#define AW88399_EFRL2_REG (0x7A)
-#define AW88399_EFRL1_REG (0x7B)
-#define AW88399_TM_REG (0x7C)
-#define AW88399_TM2_REG (0x7D)
-
-#define AW88399_REG_MAX (0x7E)
-#define AW88399_MUTE_VOL (1023)
-
-#define AW88399_DSP_CFG_ADDR (0x9B00)
-#define AW88399_DSP_REG_CFG_ADPZ_RA (0x9B68)
-#define AW88399_DSP_FW_ADDR (0x8980)
-#define AW88399_DSP_ROM_CHECK_ADDR (0x1F40)
-#define AW88399_DSP_ROM_CHECK_DATA (0x4638)
-
-#define AW88399_CALI_RE_HBITS_MASK (~(0xFFFF0000))
-#define AW88399_CALI_RE_HBITS_SHIFT (16)
-
-#define AW88399_CALI_RE_LBITS_MASK (~(0xFFFF))
-#define AW88399_CALI_RE_LBITS_SHIFT (0)
-
-#define AW88399_I2STXEN_START_BIT (9)
-#define AW88399_I2STXEN_BITS_LEN (1)
-#define AW88399_I2STXEN_MASK \
- (~(((1<<AW88399_I2STXEN_BITS_LEN)-1) << AW88399_I2STXEN_START_BIT))
-
-#define AW88399_I2STXEN_DISABLE (0)
-#define AW88399_I2STXEN_DISABLE_VALUE \
- (AW88399_I2STXEN_DISABLE << AW88399_I2STXEN_START_BIT)
-
-#define AW88399_I2STXEN_ENABLE (1)
-#define AW88399_I2STXEN_ENABLE_VALUE \
- (AW88399_I2STXEN_ENABLE << AW88399_I2STXEN_START_BIT)
-
-#define AW88399_VOL_START_BIT (0)
-#define AW88399_VOL_BITS_LEN (10)
-#define AW88399_VOL_MASK \
- (~(((1<<AW88399_VOL_BITS_LEN)-1) << AW88399_VOL_START_BIT))
-
-#define AW88399_PWDN_START_BIT (0)
-#define AW88399_PWDN_BITS_LEN (1)
-#define AW88399_PWDN_MASK \
- (~(((1<<AW88399_PWDN_BITS_LEN)-1) << AW88399_PWDN_START_BIT))
-
-#define AW88399_PWDN_POWER_DOWN (1)
-#define AW88399_PWDN_POWER_DOWN_VALUE \
- (AW88399_PWDN_POWER_DOWN << AW88399_PWDN_START_BIT)
-
-#define AW88399_PWDN_WORKING (0)
-#define AW88399_PWDN_WORKING_VALUE \
- (AW88399_PWDN_WORKING << AW88399_PWDN_START_BIT)
-
-#define AW88399_DSPBY_START_BIT (2)
-#define AW88399_DSPBY_BITS_LEN (1)
-#define AW88399_DSPBY_MASK \
- (~(((1<<AW88399_DSPBY_BITS_LEN)-1) << AW88399_DSPBY_START_BIT))
-
-#define AW88399_DSPBY_WORKING (0)
-#define AW88399_DSPBY_WORKING_VALUE \
- (AW88399_DSPBY_WORKING << AW88399_DSPBY_START_BIT)
-
-#define AW88399_DSPBY_BYPASS (1)
-#define AW88399_DSPBY_BYPASS_VALUE \
- (AW88399_DSPBY_BYPASS << AW88399_DSPBY_START_BIT)
-
-#define AW88399_MEM_CLKSEL_START_BIT (3)
-#define AW88399_MEM_CLKSEL_BITS_LEN (1)
-#define AW88399_MEM_CLKSEL_MASK \
- (~(((1<<AW88399_MEM_CLKSEL_BITS_LEN)-1) << AW88399_MEM_CLKSEL_START_BIT))
-
-#define AW88399_MEM_CLKSEL_OSCCLK (0)
-#define AW88399_MEM_CLKSEL_OSCCLK_VALUE \
- (AW88399_MEM_CLKSEL_OSCCLK << AW88399_MEM_CLKSEL_START_BIT)
-
-#define AW88399_MEM_CLKSEL_DAPHCLK (1)
-#define AW88399_MEM_CLKSEL_DAPHCLK_VALUE \
- (AW88399_MEM_CLKSEL_DAPHCLK << AW88399_MEM_CLKSEL_START_BIT)
-
-#define AW88399_DITHER_EN_START_BIT (15)
-#define AW88399_DITHER_EN_BITS_LEN (1)
-#define AW88399_DITHER_EN_MASK \
- (~(((1<<AW88399_DITHER_EN_BITS_LEN)-1) << AW88399_DITHER_EN_START_BIT))
-
-#define AW88399_DITHER_EN_DISABLE (0)
-#define AW88399_DITHER_EN_DISABLE_VALUE \
- (AW88399_DITHER_EN_DISABLE << AW88399_DITHER_EN_START_BIT)
-
-#define AW88399_DITHER_EN_ENABLE (1)
-#define AW88399_DITHER_EN_ENABLE_VALUE \
- (AW88399_DITHER_EN_ENABLE << AW88399_DITHER_EN_START_BIT)
-
-#define AW88399_HMUTE_START_BIT (8)
-#define AW88399_HMUTE_BITS_LEN (1)
-#define AW88399_HMUTE_MASK \
- (~(((1<<AW88399_HMUTE_BITS_LEN)-1) << AW88399_HMUTE_START_BIT))
-
-#define AW88399_HMUTE_DISABLE (0)
-#define AW88399_HMUTE_DISABLE_VALUE \
- (AW88399_HMUTE_DISABLE << AW88399_HMUTE_START_BIT)
-
-#define AW88399_HMUTE_ENABLE (1)
-#define AW88399_HMUTE_ENABLE_VALUE \
- (AW88399_HMUTE_ENABLE << AW88399_HMUTE_START_BIT)
-
-#define AW88399_EF_DBMD_START_BIT (2)
-#define AW88399_EF_DBMD_BITS_LEN (1)
-#define AW88399_EF_DBMD_MASK \
- (~(((1<<AW88399_EF_DBMD_BITS_LEN)-1) << AW88399_EF_DBMD_START_BIT))
-
-#define AW88399_EF_DBMD_OR (1)
-#define AW88399_EF_DBMD_OR_VALUE \
- (AW88399_EF_DBMD_OR << AW88399_EF_DBMD_START_BIT)
-
-#define AW88399_VDSEL_START_BIT (5)
-#define AW88399_VDSEL_BITS_LEN (1)
-#define AW88399_VDSEL_MASK \
- (~(((1<<AW88399_VDSEL_BITS_LEN)-1) << AW88399_VDSEL_START_BIT))
-
-#define AW88399_EF_ISN_GESLP_H_START_BIT (0)
-#define AW88399_EF_ISN_GESLP_H_BITS_LEN (10)
-#define AW88399_EF_ISN_GESLP_H_MASK \
- (~(((1<<AW88399_EF_ISN_GESLP_H_BITS_LEN)-1) << AW88399_EF_ISN_GESLP_H_START_BIT))
-
-/* EF_VSN_GESLP_H bit 9:0 (EFRH3 0x75) */
-#define AW88399_EF_VSN_GESLP_H_START_BIT (0)
-#define AW88399_EF_VSN_GESLP_H_BITS_LEN (10)
-#define AW88399_EF_VSN_GESLP_H_MASK \
- (~(((1<<AW88399_EF_VSN_GESLP_H_BITS_LEN)-1) << AW88399_EF_VSN_GESLP_H_START_BIT))
-
-#define AW88399_EF_ISN_GESLP_L_START_BIT (0)
-#define AW88399_EF_ISN_GESLP_L_BITS_LEN (10)
-#define AW88399_EF_ISN_GESLP_L_MASK \
- (~(((1<<AW88399_EF_ISN_GESLP_L_BITS_LEN)-1) << AW88399_EF_ISN_GESLP_L_START_BIT))
-
-/* EF_VSN_GESLP_L bit 9:0 (EFRL3 0x79) */
-#define AW88399_EF_VSN_GESLP_L_START_BIT (0)
-#define AW88399_EF_VSN_GESLP_L_BITS_LEN (10)
-#define AW88399_EF_VSN_GESLP_L_MASK \
- (~(((1<<AW88399_EF_VSN_GESLP_L_BITS_LEN)-1) << AW88399_EF_VSN_GESLP_L_START_BIT))
-
-#define AW88399_INTERNAL_VSN_TRIM_H_START_BIT (9)
-#define AW88399_INTERNAL_VSN_TRIM_H_BITS_LEN (6)
-#define AW88399_INTERNAL_VSN_TRIM_H_MASK \
- (~(((1<<AW88399_INTERNAL_VSN_TRIM_H_BITS_LEN)-1) << AW88399_INTERNAL_VSN_TRIM_H_START_BIT))
-
-#define AW88399_INTERNAL_VSN_TRIM_L_START_BIT (9)
-#define AW88399_INTERNAL_VSN_TRIM_L_BITS_LEN (6)
-#define AW88399_INTERNAL_VSN_TRIM_L_MASK \
- (~(((1<<AW88399_INTERNAL_VSN_TRIM_L_BITS_LEN)-1) << AW88399_INTERNAL_VSN_TRIM_L_START_BIT))
-
-#define AW88399_RCV_MODE_START_BIT (7)
-#define AW88399_RCV_MODE_BITS_LEN (1)
-#define AW88399_RCV_MODE_MASK \
- (~(((1<<AW88399_RCV_MODE_BITS_LEN)-1) << AW88399_RCV_MODE_START_BIT))
-
-#define AW88399_CLKI_START_BIT (4)
-#define AW88399_NOCLKI_START_BIT (5)
-#define AW88399_PLLI_START_BIT (0)
-#define AW88399_PLLI_INT_VALUE (1)
-#define AW88399_PLLI_INT_INTERRUPT \
- (AW88399_PLLI_INT_VALUE << AW88399_PLLI_START_BIT)
-
-#define AW88399_CLKI_INT_VALUE (1)
-#define AW88399_CLKI_INT_INTERRUPT \
- (AW88399_CLKI_INT_VALUE << AW88399_CLKI_START_BIT)
-
-#define AW88399_NOCLKI_INT_VALUE (1)
-#define AW88399_NOCLKI_INT_INTERRUPT \
- (AW88399_NOCLKI_INT_VALUE << AW88399_NOCLKI_START_BIT)
-
-#define AW88399_BIT_SYSINT_CHECK \
- (AW88399_PLLI_INT_INTERRUPT | \
- AW88399_CLKI_INT_INTERRUPT | \
- AW88399_NOCLKI_INT_INTERRUPT)
-
-#define AW88399_CRC_CHECK_START_BIT (12)
-#define AW88399_CRC_CHECK_BITS_LEN (3)
-#define AW88399_CRC_CHECK_BITS_MASK \
- (~(((1<<AW88399_CRC_CHECK_BITS_LEN)-1) << AW88399_CRC_CHECK_START_BIT))
-
-#define AW88399_RCV_MODE_RECEIVER (1)
-#define AW88399_RCV_MODE_RECEIVER_VALUE \
- (AW88399_RCV_MODE_RECEIVER << AW88399_RCV_MODE_START_BIT)
-
-#define AW88399_AMPPD_START_BIT (1)
-#define AW88399_AMPPD_BITS_LEN (1)
-#define AW88399_AMPPD_MASK \
- (~(((1<<AW88399_AMPPD_BITS_LEN)-1) << AW88399_AMPPD_START_BIT))
-
-#define AW88399_AMPPD_WORKING (0)
-#define AW88399_AMPPD_WORKING_VALUE \
- (AW88399_AMPPD_WORKING << AW88399_AMPPD_START_BIT)
-
-#define AW88399_AMPPD_POWER_DOWN (1)
-#define AW88399_AMPPD_POWER_DOWN_VALUE \
- (AW88399_AMPPD_POWER_DOWN << AW88399_AMPPD_START_BIT)
-
-#define AW88399_RAM_CG_BYP_START_BIT (0)
-#define AW88399_RAM_CG_BYP_BITS_LEN (1)
-#define AW88399_RAM_CG_BYP_MASK \
- (~(((1<<AW88399_RAM_CG_BYP_BITS_LEN)-1) << AW88399_RAM_CG_BYP_START_BIT))
-
-#define AW88399_RAM_CG_BYP_WORK (0)
-#define AW88399_RAM_CG_BYP_WORK_VALUE \
- (AW88399_RAM_CG_BYP_WORK << AW88399_RAM_CG_BYP_START_BIT)
-
-#define AW88399_RAM_CG_BYP_BYPASS (1)
-#define AW88399_RAM_CG_BYP_BYPASS_VALUE \
- (AW88399_RAM_CG_BYP_BYPASS << AW88399_RAM_CG_BYP_START_BIT)
-
-#define AW88399_CRC_END_ADDR_START_BIT (0)
-#define AW88399_CRC_END_ADDR_BITS_LEN (12)
-#define AW88399_CRC_END_ADDR_MASK \
- (~(((1<<AW88399_CRC_END_ADDR_BITS_LEN)-1) << AW88399_CRC_END_ADDR_START_BIT))
-
-#define AW88399_CRC_CODE_EN_START_BIT (13)
-#define AW88399_CRC_CODE_EN_BITS_LEN (1)
-#define AW88399_CRC_CODE_EN_MASK \
- (~(((1<<AW88399_CRC_CODE_EN_BITS_LEN)-1) << AW88399_CRC_CODE_EN_START_BIT))
-
-#define AW88399_CRC_CODE_EN_DISABLE (0)
-#define AW88399_CRC_CODE_EN_DISABLE_VALUE \
- (AW88399_CRC_CODE_EN_DISABLE << AW88399_CRC_CODE_EN_START_BIT)
-
-#define AW88399_CRC_CODE_EN_ENABLE (1)
-#define AW88399_CRC_CODE_EN_ENABLE_VALUE \
- (AW88399_CRC_CODE_EN_ENABLE << AW88399_CRC_CODE_EN_START_BIT)
-
-#define AW88399_CRC_CFG_EN_START_BIT (12)
-#define AW88399_CRC_CFG_EN_BITS_LEN (1)
-#define AW88399_CRC_CFG_EN_MASK \
- (~(((1<<AW88399_CRC_CFG_EN_BITS_LEN)-1) << AW88399_CRC_CFG_EN_START_BIT))
-
-#define AW88399_CRC_CFG_EN_DISABLE (0)
-#define AW88399_CRC_CFG_EN_DISABLE_VALUE \
- (AW88399_CRC_CFG_EN_DISABLE << AW88399_CRC_CFG_EN_START_BIT)
-
-#define AW88399_CRC_CFG_EN_ENABLE (1)
-#define AW88399_CRC_CFG_EN_ENABLE_VALUE \
- (AW88399_CRC_CFG_EN_ENABLE << AW88399_CRC_CFG_EN_START_BIT)
-
-#define AW88399_OCDS_START_BIT (3)
-#define AW88399_OCDS_OC (1)
-#define AW88399_OCDS_OC_VALUE \
- (AW88399_OCDS_OC << AW88399_OCDS_START_BIT)
-
-#define AW88399_NOCLKS_START_BIT (5)
-#define AW88399_NOCLKS_NO_CLOCK (1)
-#define AW88399_NOCLKS_NO_CLOCK_VALUE \
- (AW88399_NOCLKS_NO_CLOCK << AW88399_NOCLKS_START_BIT)
-
-#define AW88399_SWS_START_BIT (8)
-#define AW88399_SWS_SWITCHING (1)
-#define AW88399_SWS_SWITCHING_VALUE \
- (AW88399_SWS_SWITCHING << AW88399_SWS_START_BIT)
-
-#define AW88399_BSTS_START_BIT (9)
-#define AW88399_BSTS_FINISHED (1)
-#define AW88399_BSTS_FINISHED_VALUE \
- (AW88399_BSTS_FINISHED << AW88399_BSTS_START_BIT)
-
-#define AW88399_UVLS_START_BIT (14)
-#define AW88399_UVLS_NORMAL (0)
-#define AW88399_UVLS_NORMAL_VALUE \
- (AW88399_UVLS_NORMAL << AW88399_UVLS_START_BIT)
-
-#define AW88399_BSTOCS_START_BIT (11)
-#define AW88399_BSTOCS_OVER_CURRENT (1)
-#define AW88399_BSTOCS_OVER_CURRENT_VALUE \
- (AW88399_BSTOCS_OVER_CURRENT << AW88399_BSTOCS_START_BIT)
-
-#define AW88399_OTHS_START_BIT (1)
-#define AW88399_OTHS_OT (1)
-#define AW88399_OTHS_OT_VALUE \
- (AW88399_OTHS_OT << AW88399_OTHS_START_BIT)
-
-#define AW88399_PLLS_START_BIT (0)
-#define AW88399_PLLS_LOCKED (1)
-#define AW88399_PLLS_LOCKED_VALUE \
- (AW88399_PLLS_LOCKED << AW88399_PLLS_START_BIT)
-
-#define AW88399_CLKS_START_BIT (4)
-#define AW88399_CLKS_STABLE (1)
-#define AW88399_CLKS_STABLE_VALUE \
- (AW88399_CLKS_STABLE << AW88399_CLKS_START_BIT)
-
-#define AW88399_BIT_PLL_CHECK \
- (AW88399_CLKS_STABLE_VALUE | \
- AW88399_PLLS_LOCKED_VALUE)
-
-#define AW88399_BIT_SYSST_CHECK_MASK \
- (~(AW88399_UVLS_NORMAL_VALUE | \
- AW88399_BSTOCS_OVER_CURRENT_VALUE | \
- AW88399_BSTS_FINISHED_VALUE | \
- AW88399_SWS_SWITCHING_VALUE | \
- AW88399_NOCLKS_NO_CLOCK_VALUE | \
- AW88399_CLKS_STABLE_VALUE | \
- AW88399_OCDS_OC_VALUE | \
- AW88399_OTHS_OT_VALUE | \
- AW88399_PLLS_LOCKED_VALUE))
-
-#define AW88399_BIT_SYSST_NOSWS_CHECK \
- (AW88399_BSTS_FINISHED_VALUE | \
- AW88399_CLKS_STABLE_VALUE | \
- AW88399_PLLS_LOCKED_VALUE)
-
-#define AW88399_BIT_SYSST_SWS_CHECK \
- (AW88399_BSTS_FINISHED_VALUE | \
- AW88399_CLKS_STABLE_VALUE | \
- AW88399_PLLS_LOCKED_VALUE | \
- AW88399_SWS_SWITCHING_VALUE)
-
-#define AW88399_CCO_MUX_START_BIT (14)
-#define AW88399_CCO_MUX_BITS_LEN (1)
-#define AW88399_CCO_MUX_MASK \
- (~(((1<<AW88399_CCO_MUX_BITS_LEN)-1) << AW88399_CCO_MUX_START_BIT))
-
-#define AW88399_CCO_MUX_DIVIDED (0)
-#define AW88399_CCO_MUX_DIVIDED_VALUE \
- (AW88399_CCO_MUX_DIVIDED << AW88399_CCO_MUX_START_BIT)
-
-#define AW88399_CCO_MUX_BYPASS (1)
-#define AW88399_CCO_MUX_BYPASS_VALUE \
- (AW88399_CCO_MUX_BYPASS << AW88399_CCO_MUX_START_BIT)
-
-#define AW88399_NOISE_GATE_EN_START_BIT (13)
-#define AW88399_NOISE_GATE_EN_BITS_LEN (1)
-#define AW88399_NOISE_GATE_EN_MASK \
- (~(((1<<AW88399_NOISE_GATE_EN_BITS_LEN)-1) << AW88399_NOISE_GATE_EN_START_BIT))
-
-#define AW88399_WDT_CNT_START_BIT (0)
-#define AW88399_WDT_CNT_BITS_LEN (8)
-#define AW88399_WDT_CNT_MASK \
- (~(((1<<AW88399_WDT_CNT_BITS_LEN)-1) << AW88399_WDT_CNT_START_BIT))
-
-#define AW88399_REABS_START_BIT (3)
-#define AW88399_REABS_BITS_LEN (1)
-#define AW88399_REABS_MASK \
- (~(((1<<AW88399_REABS_BITS_LEN)-1) << AW88399_REABS_START_BIT))
-
-#define AW88399_DSP_VOL_START_BIT (8)
-#define AW88399_DSP_VOL_BITS_LEN (8)
-#define AW88399_DSP_VOL_MASK \
- (~(((1<<AW88399_DSP_VOL_BITS_LEN)-1) << AW88399_DSP_VOL_START_BIT))
-
-#define AW883XX_DSP_NG_EN_START (13)
-#define AW883XX_DSP_NG_EN_LEN (1)
-#define AW883XX_DSP_NG_EN_MASK \
- (~(((1 << AW883XX_DSP_NG_EN_LEN) - 1) << AW883XX_DSP_NG_EN_START))
-#define AW883XX_DSP_NG_EN_DISABLE (0)
-#define AW883XX_DSP_NG_EN_DISABLE_VALUE \
- (AW883XX_DSP_NG_EN_DISABLE << AW883XX_DSP_NG_EN_START)
-
-#define AW88399_VOLUME_STEP_DB (64)
-#define AW88399_VOL_DEFAULT_VALUE (0)
-#define AW88399_DSP_ODD_NUM_BIT_TEST (0x5555)
-#define AW88399_EF_ISN_GESLP_SIGN_MASK (~(1 << 9))
-#define AW88399_EF_ISN_GESLP_SIGN_NEG (0xfe00)
-
-#define AW88399_EF_VSN_GESLP_SIGN_MASK (~(1 << 9))
-#define AW88399_EF_VSN_GESLP_SIGN_NEG (0xfe00)
-
-#define AW88399_TEM4_SIGN_MASK (~(1 << 5))
-#define AW88399_TEM4_SIGN_NEG (0xffc0)
-
-#define AW88399_ICABLK_FACTOR (1)
-#define AW88399_VCABLK_FACTOR (1)
-#define AW88399_VCABLK_DAC_FACTOR (2)
-
-#define AW88399_VCALB_ADJ_FACTOR (12)
-#define AW88399_VCALB_ACCURACY (1 << 12)
-
-#define AW88399_ISCAL_FACTOR (3125)
-#define AW88399_VSCAL_FACTOR (18875)
-#define AW88399_ISCAL_DAC_FACTOR (3125)
-#define AW88399_VSCAL_DAC_FACTOR (12600)
-#define AW88399_CABL_BASE_VALUE (1000)
-
-#define AW88399_DEV_DEFAULT_CH (0)
-#define AW88399_DEV_DSP_CHECK_MAX (5)
-#define AW88399_MAX_RAM_WRITE_BYTE_SIZE (128)
-#define AW88399_DSP_RE_SHIFT (12)
-#define AW88399_CALI_RE_MAX (15000)
-#define AW88399_CALI_RE_MIN (4000)
-#define AW_FW_ADDR_LEN (4)
-#define AW88399_DSP_RE_TO_SHOW_RE(re, shift) (((re) * (1000)) >> (shift))
-#define AW88399_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000))
-#define AW88399_CRC_CHECK_PASS_VAL (0x4)
-
-#define AW88399_CRC_CFG_BASE_ADDR (0xD80)
-#define AW88399_CRC_FW_BASE_ADDR (0x4C0)
-#define AW88399_ACF_FILE "aw88399_acf.bin"
-#define AW88399_DEV_SYSST_CHECK_MAX (10)
-#define AW88399_CHIP_ID 0x2183
+#include <sound/aw88399.h>
#define AW88399_I2C_NAME "aw88399"
-#define AW88399_START_RETRIES (5)
-#define AW88399_START_WORK_DELAY_MS (0)
-
#define AW88399_RATES (SNDRV_PCM_RATE_8000_48000 | \
SNDRV_PCM_RATE_96000)
#define AW88399_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -550,80 +48,4 @@
.put = profile_set, \
}
-enum {
- AW_EF_AND_CHECK = 0,
- AW_EF_OR_CHECK,
-};
-
-enum {
- AW88399_DEV_VDSEL_DAC = 0,
- AW88399_DEV_VDSEL_VSENSE = 32,
-};
-
-enum {
- AW88399_DSP_CRC_NA = 0,
- AW88399_DSP_CRC_OK = 1,
-};
-
-enum {
- AW88399_DSP_FW_UPDATE_OFF = 0,
- AW88399_DSP_FW_UPDATE_ON = 1,
-};
-
-enum {
- AW88399_FORCE_UPDATE_OFF = 0,
- AW88399_FORCE_UPDATE_ON = 1,
-};
-
-enum {
- AW88399_1000_US = 1000,
- AW88399_2000_US = 2000,
- AW88399_3000_US = 3000,
- AW88399_4000_US = 4000,
-};
-
-enum AW88399_DEV_STATUS {
- AW88399_DEV_PW_OFF = 0,
- AW88399_DEV_PW_ON,
-};
-
-enum AW88399_DEV_FW_STATUS {
- AW88399_DEV_FW_FAILED = 0,
- AW88399_DEV_FW_OK,
-};
-
-enum AW88399_DEV_MEMCLK {
- AW88399_DEV_MEMCLK_OSC = 0,
- AW88399_DEV_MEMCLK_PLL = 1,
-};
-
-enum AW88399_DEV_DSP_CFG {
- AW88399_DEV_DSP_WORK = 0,
- AW88399_DEV_DSP_BYPASS = 1,
-};
-
-enum {
- AW88399_NOT_RCV_MODE = 0,
- AW88399_RCV_MODE = 1,
-};
-
-enum {
- AW88399_SYNC_START = 0,
- AW88399_ASYNC_START,
-};
-
-struct aw88399 {
- struct aw_device *aw_pa;
- struct mutex lock;
- struct gpio_desc *reset_gpio;
- struct delayed_work start_work;
- struct regmap *regmap;
- struct aw_container *aw_cfg;
-
- unsigned int check_val;
- unsigned int crc_init_val;
- unsigned int vcalb_init_val;
- unsigned int dither_st;
-};
-
-#endif
+#endif /* __AW88399_H__ */
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c
index c0bf45b76cb8..b085885e3f18 100644
--- a/sound/soc/codecs/bt-sco.c
+++ b/sound/soc/codecs/bt-sco.c
@@ -85,13 +85,9 @@ static int bt_sco_probe(struct platform_device *pdev)
}
static const struct platform_device_id bt_sco_driver_ids[] = {
- {
- .name = "dfbmcs320",
- },
- {
- .name = "bt-sco",
- },
- {},
+ { .name = "dfbmcs320" },
+ { .name = "bt-sco" },
+ { }
};
MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
index 6b80c455b074..fc41e1547bda 100644
--- a/sound/soc/codecs/cpcap.c
+++ b/sound/soc/codecs/cpcap.c
@@ -26,14 +26,6 @@
/* Register 9 - CPCAP_REG_INTS2 --- Interrupt Sense 2 */
#define CPCAP_BIT_PTT_S 11 /* Push To Talk */
-/* Register 512 CPCAP_REG_VAUDIOC --- Audio Regulator and Bias Voltage */
-#define CPCAP_BIT_AUDIO_LOW_PWR 6
-#define CPCAP_BIT_AUD_LOWPWR_SPEED 5
-#define CPCAP_BIT_VAUDIOPRISTBY 4
-#define CPCAP_BIT_VAUDIO_MODE1 2
-#define CPCAP_BIT_VAUDIO_MODE0 1
-#define CPCAP_BIT_V_AUDIO_EN 0
-
/* Register 513 CPCAP_REG_CC --- CODEC */
#define CPCAP_BIT_CDC_CLK2 15
#define CPCAP_BIT_CDC_CLK1 14
@@ -239,7 +231,6 @@ struct cpcap_reg_info {
};
static const struct cpcap_reg_info cpcap_default_regs[] = {
- { CPCAP_REG_VAUDIOC, 0x003F, 0x0000 },
{ CPCAP_REG_CC, 0xFFFF, 0x0000 },
{ CPCAP_REG_CC, 0xFFFF, 0x0000 },
{ CPCAP_REG_CDI, 0xBFFF, 0x0000 },
@@ -1265,6 +1256,7 @@ static int cpcap_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component = dai->component;
struct device *dev = component->dev;
struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
@@ -1298,7 +1290,7 @@ static int cpcap_voice_hw_params(struct snd_pcm_substream *substream,
return err;
}
- return 0;
+ return snd_soc_runtime_set_dai_fmt(rtd, rtd->dai_link->dai_fmt);
}
static int cpcap_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
@@ -1391,121 +1383,8 @@ static int cpcap_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
-
-/*
- * Configure codec for voice call if requested.
- *
- * We can configure most with snd_soc_dai_set_sysclk(), snd_soc_dai_set_fmt()
- * and snd_soc_dai_set_tdm_slot(). This function configures the rest of the
- * cpcap related hardware as CPU is not involved in the voice call.
- */
-static int cpcap_voice_call(struct cpcap_audio *cpcap, struct snd_soc_dai *dai,
- bool voice_call)
-{
- int mask, err;
-
- /* Modem to codec VAUDIO_MODE1 */
- mask = BIT(CPCAP_BIT_VAUDIO_MODE1);
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_VAUDIOC,
- mask, voice_call ? mask : 0);
- if (err)
- return err;
-
- /* Clear MIC1_MUX for call */
- mask = BIT(CPCAP_BIT_MIC1_MUX);
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
- mask, voice_call ? 0 : mask);
- if (err)
- return err;
-
- /* Set MIC2_MUX for call */
- mask = BIT(CPCAP_BIT_MB_ON1L) | BIT(CPCAP_BIT_MB_ON1R) |
- BIT(CPCAP_BIT_MIC2_MUX) | BIT(CPCAP_BIT_MIC2_PGA_EN);
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
- mask, voice_call ? mask : 0);
- if (err)
- return err;
-
- /* Enable LDSP for call */
- mask = BIT(CPCAP_BIT_A2_LDSP_L_EN) | BIT(CPCAP_BIT_A2_LDSP_R_EN);
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXOA,
- mask, voice_call ? mask : 0);
- if (err)
- return err;
-
- /* Enable CPCAP_BIT_PGA_CDC_EN for call */
- mask = BIT(CPCAP_BIT_PGA_CDC_EN);
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA,
- mask, voice_call ? mask : 0);
- if (err)
- return err;
-
- /* Unmute voice for call */
- if (dai) {
- err = snd_soc_dai_digital_mute(dai, !voice_call,
- SNDRV_PCM_STREAM_PLAYBACK);
- if (err)
- return err;
- }
-
- /* Set modem to codec mic CDC and HPF for call */
- mask = BIT(CPCAP_BIT_MIC2_CDC_EN) | BIT(CPCAP_BIT_CDC_EN_RX) |
- BIT(CPCAP_BIT_AUDOHPF_1) | BIT(CPCAP_BIT_AUDOHPF_0) |
- BIT(CPCAP_BIT_AUDIHPF_1) | BIT(CPCAP_BIT_AUDIHPF_0);
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC,
- mask, voice_call ? mask : 0);
- if (err)
- return err;
-
- /* Enable modem to codec CDC for call*/
- mask = BIT(CPCAP_BIT_CDC_CLK_EN);
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
- mask, voice_call ? mask : 0);
-
- return err;
-}
-
-static int cpcap_voice_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 cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
- int err, ts_mask, mask;
- bool voice_call;
-
- /*
- * Primitive test for voice call, probably needs more checks
- * later on for 16-bit calls detected, Bluetooth headset etc.
- */
- if (tx_mask == 0 && rx_mask == 1 && slot_width == 8)
- voice_call = true;
- else
- voice_call = false;
-
- ts_mask = 0x7 << CPCAP_BIT_MIC2_TIMESLOT0;
- ts_mask |= 0x7 << CPCAP_BIT_MIC1_RX_TIMESLOT0;
-
- mask = (tx_mask & 0x7) << CPCAP_BIT_MIC2_TIMESLOT0;
- mask |= (rx_mask & 0x7) << CPCAP_BIT_MIC1_RX_TIMESLOT0;
-
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
- ts_mask, mask);
- if (err)
- return err;
-
- err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, slot_width * 1000);
- if (err)
- return err;
-
- err = cpcap_voice_call(cpcap, dai, voice_call);
- if (err)
- return err;
-
- return 0;
-}
-
-static int cpcap_voice_set_mute(struct snd_soc_dai *dai, int mute, int direction)
+static int cpcap_voice_set_mute(struct snd_soc_dai *dai,
+ int mute, int direction)
{
struct snd_soc_component *component = dai->component;
struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
@@ -1526,7 +1405,6 @@ static const struct snd_soc_dai_ops cpcap_dai_voice_ops = {
.hw_params = cpcap_voice_hw_params,
.set_sysclk = cpcap_voice_set_dai_sysclk,
.set_fmt = cpcap_voice_set_dai_fmt,
- .set_tdm_slot = cpcap_voice_set_tdm_slot,
.mute_stream = cpcap_voice_set_mute,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c
index 7dc5a7c3ca96..1148e37e29ce 100644
--- a/sound/soc/codecs/cros_ec_codec.c
+++ b/sound/soc/codecs/cros_ec_codec.c
@@ -12,6 +12,7 @@
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/cleanup.h>
#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
@@ -319,10 +320,18 @@ static int i2s_rx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
(uint8_t *)&p, sizeof(p), NULL, 0);
}
+static const u64 i2s_rx_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
static const struct snd_soc_dai_ops i2s_rx_dai_ops = {
.hw_params = i2s_rx_hw_params,
.set_fmt = i2s_rx_set_fmt,
.set_bclk_ratio = i2s_rx_set_bclk_ratio,
+ .auto_selectable_formats = &i2s_rx_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static int i2s_rx_event(struct snd_soc_dapm_widget *w,
@@ -608,10 +617,10 @@ static void wov_copy_work(struct work_struct *w)
container_of(w, struct cros_ec_codec_priv, wov_copy_work.work);
int ret;
- mutex_lock(&priv->wov_dma_lock);
+ guard(mutex)(&priv->wov_dma_lock);
if (!priv->wov_substream) {
dev_warn(priv->dev, "no pcm substream\n");
- goto leave;
+ return;
}
if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_AUDIO_SHM))
@@ -624,8 +633,6 @@ static void wov_copy_work(struct work_struct *w)
msecs_to_jiffies(10));
else if (ret)
dev_err(priv->dev, "failed to read audio data\n");
-leave:
- mutex_unlock(&priv->wov_dma_lock);
}
static int wov_enable_get(struct snd_kcontrol *kcontrol,
@@ -895,12 +902,11 @@ static int wov_pcm_hw_params(struct snd_soc_component *component,
struct cros_ec_codec_priv *priv =
snd_soc_component_get_drvdata(component);
- mutex_lock(&priv->wov_dma_lock);
+ guard(mutex)(&priv->wov_dma_lock);
priv->wov_substream = substream;
priv->wov_rp = priv->wov_wp = 0;
priv->wov_dma_offset = 0;
priv->wov_burst_read = true;
- mutex_unlock(&priv->wov_dma_lock);
return 0;
}
@@ -911,10 +917,10 @@ static int wov_pcm_hw_free(struct snd_soc_component *component,
struct cros_ec_codec_priv *priv =
snd_soc_component_get_drvdata(component);
- mutex_lock(&priv->wov_dma_lock);
- wov_queue_dequeue(priv, wov_queue_size(priv));
- priv->wov_substream = NULL;
- mutex_unlock(&priv->wov_dma_lock);
+ scoped_guard(mutex, &priv->wov_dma_lock) {
+ wov_queue_dequeue(priv, wov_queue_size(priv));
+ priv->wov_substream = NULL;
+ }
cancel_delayed_work_sync(&priv->wov_copy_work);
diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c
index 371e99205b58..41a9a5b005c6 100644
--- a/sound/soc/codecs/cs-amp-lib.c
+++ b/sound/soc/codecs/cs-amp-lib.c
@@ -7,6 +7,7 @@
#include <asm/byteorder.h>
#include <kunit/static_stub.h>
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/dev_printk.h>
#include <linux/efi.h>
@@ -83,10 +84,12 @@ static int cs_amp_write_cal_coeff(struct cs_dsp *dsp,
KUNIT_STATIC_STUB_REDIRECT(cs_amp_write_cal_coeff, dsp, controls, ctl_name, val);
if (IS_REACHABLE(CONFIG_FW_CS_DSP)) {
- mutex_lock(&dsp->pwr_lock);
- cs_ctl = cs_dsp_get_ctl(dsp, ctl_name, controls->mem_region, controls->alg_id);
- ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, &beval, sizeof(beval));
- mutex_unlock(&dsp->pwr_lock);
+ scoped_guard(mutex, &dsp->pwr_lock) {
+ cs_ctl = cs_dsp_get_ctl(dsp, ctl_name,
+ controls->mem_region,
+ controls->alg_id);
+ ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, &beval, sizeof(beval));
+ }
if (ret < 0) {
dev_err(dsp->dev, "Failed to write to '%s': %d\n", ctl_name, ret);
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index c835088de578..8288fb6d50be 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -538,7 +538,15 @@ static int cs35l32_runtime_resume(struct device *dev)
gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
regcache_cache_only(cs35l32->regmap, false);
- regcache_sync(cs35l32->regmap);
+ ret = regcache_sync(cs35l32->regmap);
+ if (ret) {
+ regcache_cache_only(cs35l32->regmap, true);
+ regcache_mark_dirty(cs35l32->regmap);
+ gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
+ regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
+ cs35l32->supplies);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c
index f49edb9ea1f2..e217da124549 100644
--- a/sound/soc/codecs/cs35l33.c
+++ b/sound/soc/codecs/cs35l33.c
@@ -40,6 +40,7 @@ struct cs35l33_private {
struct regmap *regmap;
struct gpio_desc *reset_gpio;
bool amp_cal;
+ bool irq_requested;
int mclk_int;
struct regulator_bulk_data core_supplies[2];
int num_core_supplies;
@@ -881,6 +882,9 @@ static int cs35l33_runtime_resume(struct device *dev)
goto err;
}
+ if (cs35l33->irq_requested)
+ enable_irq(to_i2c_client(dev)->irq);
+
return 0;
err:
@@ -900,6 +904,10 @@ static int cs35l33_runtime_suspend(struct device *dev)
/* redo the calibration in next power up */
cs35l33->amp_cal = false;
+ /* Drain and block the threaded IRQ before cache_only/power-off. */
+ if (cs35l33->irq_requested)
+ disable_irq(to_i2c_client(dev)->irq);
+
regcache_cache_only(cs35l33->regmap, true);
regcache_mark_dirty(cs35l33->regmap);
regulator_bulk_disable(cs35l33->num_core_supplies,
@@ -1154,10 +1162,12 @@ static int cs35l33_i2c_probe(struct i2c_client *i2c_client)
}
ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL,
- cs35l33_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
- "cs35l33", cs35l33);
+ cs35l33_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ "cs35l33", cs35l33);
if (ret != 0)
dev_warn(&i2c_client->dev, "Failed to request IRQ: %d\n", ret);
+ else
+ cs35l33->irq_requested = true;
/* We could issue !RST or skip it based on AMP topology */
cs35l33->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
index e80984b22159..3f265bd760f7 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -45,6 +45,7 @@ struct cs35l34_private {
int num_core_supplies;
int mclk_int;
bool tdm_mode;
+ bool irq_requested;
struct gpio_desc *reset_gpio; /* Active-low reset GPIO */
};
@@ -1032,10 +1033,12 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client)
}
ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL,
- cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
- "cs35l34", cs35l34);
+ cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ "cs35l34", cs35l34);
if (ret != 0)
dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret);
+ else
+ cs35l34->irq_requested = true;
cs35l34->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
"reset", GPIOD_OUT_LOW);
@@ -1140,6 +1143,9 @@ static int cs35l34_runtime_resume(struct device *dev)
dev_err(dev, "Failed to restore register cache\n");
goto err;
}
+
+ if (cs35l34->irq_requested)
+ enable_irq(to_i2c_client(dev)->irq);
return 0;
err:
regcache_cache_only(cs35l34->regmap, true);
@@ -1153,6 +1159,10 @@ static int cs35l34_runtime_suspend(struct device *dev)
{
struct cs35l34_private *cs35l34 = dev_get_drvdata(dev);
+ /* Drain and block the threaded IRQ before cache_only/power-off. */
+ if (cs35l34->irq_requested)
+ disable_irq(to_i2c_client(dev)->irq);
+
regcache_cache_only(cs35l34->regmap, true);
regcache_mark_dirty(cs35l34->regmap);
diff --git a/sound/soc/codecs/cs35l56-i2c.c b/sound/soc/codecs/cs35l56-i2c.c
index 4f6ddf1c5a3f..5e69ddbe342a 100644
--- a/sound/soc/codecs/cs35l56-i2c.c
+++ b/sound/soc/codecs/cs35l56-i2c.c
@@ -51,15 +51,7 @@ static int cs35l56_i2c_probe(struct i2c_client *client)
return dev_err_probe(cs35l56->base.dev, ret, "Failed to allocate register map\n");
}
- ret = cs35l56_common_probe(cs35l56);
- if (ret != 0)
- return ret;
-
- ret = cs35l56_irq_request(&cs35l56->base, client->irq);
- if (ret < 0)
- cs35l56_remove(cs35l56);
-
- return ret;
+ return cs35l56_common_probe(cs35l56, client->irq);
}
static void cs35l56_i2c_remove(struct i2c_client *client)
diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c
index 0a55b93b96f9..4fba59e80c37 100644
--- a/sound/soc/codecs/cs35l56-sdw.c
+++ b/sound/soc/codecs/cs35l56-sdw.c
@@ -231,7 +231,7 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral)
* a soft reset.
*/
if (cs35l56->base.init_done)
- cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral);
+ cs35l56_unmask_soundwire_interrupts(cs35l56);
out:
pm_runtime_put_autosuspend(cs35l56->base.dev);
@@ -240,47 +240,17 @@ out:
static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral,
struct sdw_slave_intr_status *status)
{
- struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
-
- /* SoundWire core holds our pm_runtime when calling this function. */
-
- dev_dbg(cs35l56->base.dev, "int control_port=%#x\n", status->control_port);
-
- if ((status->control_port & SDW_SCP_INT1_IMPL_DEF) == 0)
- return 0;
-
/*
- * Prevent bus manager suspending and possibly issuing a
- * bus-reset before the queued work has run.
+ * The IRQ itself was handled through the regmap_irq handler, this is
+ * just clearing up the additional Cirrus SoundWire registers that are
+ * not covered by the SoundWire framework or the IRQ handler itself.
*/
- pm_runtime_get_noresume(cs35l56->base.dev);
-
- /*
- * Mask and clear until it has been handled.
- * None of the interrupts are time-critical so use the
- * power-efficient queue.
- */
- cs35l56_mask_soundwire_interrupts(peripheral);
- queue_work(system_power_efficient_wq, &cs35l56->sdw_irq_work);
+ sdw_read_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1);
+ sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF);
return 0;
}
-static void cs35l56_sdw_irq_work(struct work_struct *work)
-{
- struct cs35l56_private *cs35l56 = container_of(work,
- struct cs35l56_private,
- sdw_irq_work);
-
- cs35l56_irq(-1, &cs35l56->base);
-
- /* unmask interrupts */
- if (!cs35l56->sdw_irq_no_unmask)
- cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral);
-
- pm_runtime_put_autosuspend(cs35l56->base.dev);
-}
-
static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
@@ -302,6 +272,7 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral)
prop->source_ports = BIT(CS35L56_SDW1_CAPTURE_PORT);
prop->sink_ports = BIT(CS35L56_SDW1_PLAYBACK_PORT);
prop->paging_support = true;
+ prop->use_domain_irq = true;
prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY | SDW_SCP_INT1_IMPL_DEF;
@@ -406,7 +377,7 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev)
if (ret)
return ret;
- cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral);
+ cs35l56_unmask_soundwire_interrupts(cs35l56);
return 0;
}
@@ -418,21 +389,12 @@ static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev)
if (!cs35l56->base.init_done)
return 0;
- cs35l56_disable_sdw_interrupts(cs35l56);
+ /* runtime_resume unmasks the interrupt */
+ cs35l56_mask_soundwire_interrupts(cs35l56);
return cs35l56_system_suspend(dev);
}
-static int __maybe_unused cs35l56_sdw_system_resume(struct device *dev)
-{
- struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
-
- cs35l56->sdw_irq_no_unmask = false;
- /* runtime_resume re-enables the interrupt */
-
- return cs35l56_system_resume(dev);
-}
-
static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_device_id *id)
{
struct device *dev = &peripheral->dev;
@@ -447,7 +409,6 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi
cs35l56->base.dev = dev;
cs35l56->sdw_peripheral = peripheral;
cs35l56->sdw_link_num = peripheral->bus->link_id;
- INIT_WORK(&cs35l56->sdw_irq_work, cs35l56_sdw_irq_work);
dev_set_drvdata(dev, cs35l56);
@@ -457,6 +418,7 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi
regmap_config = &cs35l56_regmap_sdw;
break;
case 0x3563:
+ case 0x3562:
regmap_config = &cs35l63_regmap_sdw;
break;
default:
@@ -483,25 +445,21 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi
/* Start in cache-only until device is enumerated */
regcache_cache_only(cs35l56->base.regmap, true);
- ret = cs35l56_common_probe(cs35l56);
- if (ret != 0)
- return ret;
-
- return 0;
+ return cs35l56_common_probe(cs35l56, peripheral->irq);
}
static void cs35l56_sdw_remove(struct sdw_slave *peripheral)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
- cs35l56_disable_sdw_interrupts(cs35l56);
+ cs35l56_mask_soundwire_interrupts(cs35l56);
cs35l56_remove(cs35l56);
}
static const struct dev_pm_ops cs35l56_sdw_pm = {
SET_RUNTIME_PM_OPS(cs35l56_sdw_runtime_suspend, cs35l56_sdw_runtime_resume, NULL)
- SYSTEM_SLEEP_PM_OPS(cs35l56_sdw_system_suspend, cs35l56_sdw_system_resume)
+ SYSTEM_SLEEP_PM_OPS(cs35l56_sdw_system_suspend, cs35l56_system_resume)
LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_late, cs35l56_system_resume_early)
/* NOIRQ stage not needed, SoundWire doesn't use a hard IRQ */
};
@@ -509,6 +467,7 @@ static const struct dev_pm_ops cs35l56_sdw_pm = {
static const struct sdw_device_id cs35l56_sdw_id[] = {
SDW_SLAVE_ENTRY(0x01FA, 0x3556, 0x3556),
SDW_SLAVE_ENTRY(0x01FA, 0x3557, 0x3557),
+ SDW_SLAVE_ENTRY(0x01FA, 0x3562, 0x3562),
SDW_SLAVE_ENTRY(0x01FA, 0x3563, 0x3563),
{},
};
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index f14e2eaaa4ee..7b3e37d462d6 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -96,6 +96,7 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base)
ARRAY_SIZE(cs35l56_patch_fw));
break;
case 0x63:
+ case 0x62:
ret = regmap_register_patch(cs35l56_base->regmap, cs35l63_patch_fw,
ARRAY_SIZE(cs35l63_patch_fw));
break;
@@ -389,6 +390,7 @@ static void cs35l56_set_fw_reg_table(struct cs35l56_base *cs35l56_base)
}
break;
case 0x63:
+ case 0x62:
cs35l56_base->fw_reg = &cs35l63_fw_reg;
break;
}
@@ -595,6 +597,7 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire)
}
break;
case 0x63:
+ case 0x62:
regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
cs35l63_system_reset_seq,
ARRAY_SIZE(cs35l63_system_reset_seq));
@@ -613,26 +616,7 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire)
}
EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, "SND_SOC_CS35L56_SHARED");
-int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq)
-{
- int ret;
-
- if (irq < 1)
- return 0;
-
- ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq,
- IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
- "cs35l56", cs35l56_base);
- if (!ret)
- cs35l56_base->irq = irq;
- else
- dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret);
-
- return ret;
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, "SND_SOC_CS35L56_SHARED");
-
-irqreturn_t cs35l56_irq(int irq, void *data)
+static irqreturn_t cs35l56_irq(int irq, void *data)
{
struct cs35l56_base *cs35l56_base = data;
unsigned int status1 = 0, status8 = 0, status20 = 0;
@@ -640,23 +624,22 @@ irqreturn_t cs35l56_irq(int irq, void *data)
unsigned int val;
int rv;
- irqreturn_t ret = IRQ_NONE;
-
if (!cs35l56_base->init_done)
return IRQ_NONE;
- mutex_lock(&cs35l56_base->irq_lock);
+ guard(mutex)(&cs35l56_base->irq_lock);
- rv = pm_runtime_resume_and_get(cs35l56_base->dev);
+ PM_RUNTIME_ACQUIRE_IF_ENABLED(cs35l56_base->dev, pm);
+ rv = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (rv < 0) {
dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv);
- goto err_unlock;
+ return IRQ_NONE;
}
regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val);
if ((val & CS35L56_IRQ1_STS_MASK) == 0) {
dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n");
- goto err;
+ return IRQ_NONE;
}
/* Ack interrupts */
@@ -680,7 +663,7 @@ irqreturn_t cs35l56_irq(int irq, void *data)
/* Check to see if unmasked bits are active */
if (!status1 && !status8 && !status20)
- goto err;
+ return IRQ_NONE;
if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK)
dev_crit(cs35l56_base->dev, "Amp short error\n");
@@ -688,16 +671,27 @@ irqreturn_t cs35l56_irq(int irq, void *data)
if (status8 & CS35L56_TEMP_ERR_EINT1_MASK)
dev_crit(cs35l56_base->dev, "Overtemp error\n");
- ret = IRQ_HANDLED;
+ return IRQ_HANDLED;
+}
-err:
- pm_runtime_put(cs35l56_base->dev);
-err_unlock:
- mutex_unlock(&cs35l56_base->irq_lock);
+int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq)
+{
+ int ret;
+
+ if (irq < 1)
+ return 0;
+
+ ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq,
+ IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
+ "cs35l56", cs35l56_base);
+ if (!ret)
+ cs35l56_base->irq = irq;
+ else
+ dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret);
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_irq, "SND_SOC_CS35L56_SHARED");
+EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, "SND_SOC_CS35L56_SHARED");
int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base)
{
@@ -816,14 +810,10 @@ int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_sou
if (!cs35l56_base->init_done)
return 0;
- if (!cs35l56_base->can_hibernate)
- goto out_sync;
-
- /* Must be done before releasing cache-only */
- if (!is_soundwire)
+ /* Hibernate wake must be done before releasing cache-only */
+ if (cs35l56_base->can_hibernate && !is_soundwire)
cs35l56_issue_wake_event(cs35l56_base);
-out_sync:
ret = cs35l56_wait_for_firmware_boot(cs35l56_base);
if (ret) {
dev_err(cs35l56_base->dev, "Hibernate wake failed: %d\n", ret);
@@ -1470,6 +1460,7 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
cs35l56_base->calibration_controls = &cs35l56_calibration_controls;
break;
case 0x35A630:
+ case 0x35A620:
cs35l56_base->calibration_controls = &cs35l63_calibration_controls;
devid = devid >> 4;
break;
diff --git a/sound/soc/codecs/cs35l56-spi.c b/sound/soc/codecs/cs35l56-spi.c
index b1eb924a5b6c..21b18da9e73d 100644
--- a/sound/soc/codecs/cs35l56-spi.c
+++ b/sound/soc/codecs/cs35l56-spi.c
@@ -40,15 +40,7 @@ static int cs35l56_spi_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = cs35l56_common_probe(cs35l56);
- if (ret != 0)
- return ret;
-
- ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
- if (ret < 0)
- cs35l56_remove(cs35l56);
-
- return ret;
+ return cs35l56_common_probe(cs35l56, spi->irq);
}
static void cs35l56_spi_remove(struct spi_device *spi)
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index 063ef7a70de0..b9118ad8fab5 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -37,48 +37,49 @@
#include "wm_adsp.h"
#include "cs35l56.h"
-void cs35l56_mask_soundwire_interrupts(struct sdw_slave *peripheral)
+void cs35l56_mask_soundwire_interrupts(struct cs35l56_private *cs35l56)
{
/*
+ * Mask unconditionally.
+ *
* The read of GEN_INT_STAT_1 is required as per the SoundWire spec
* for interrupt status bits to clear.
* GEN_INT_MASK_1 masks the _inputs_ to GEN_INT_STAT1.
*/
- sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1, 0);
- sdw_read_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1);
- sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF);
+ sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1, 0);
+ sdw_read_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_STAT_1);
+ sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF);
}
EXPORT_SYMBOL_NS_GPL(cs35l56_mask_soundwire_interrupts, "SND_SOC_CS35L56_CORE");
-void cs35l56_unmask_soundwire_interrupts(struct sdw_slave *peripheral)
+void cs35l56_unmask_soundwire_interrupts(struct cs35l56_private *cs35l56)
{
- sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1, CS35L56_SDW_INT_MASK_CODEC_IRQ);
+ if (!cs35l56->base.irq)
+ return;
+
+ sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1,
+ CS35L56_SDW_INT_MASK_CODEC_IRQ);
}
EXPORT_SYMBOL_NS_GPL(cs35l56_unmask_soundwire_interrupts, "SND_SOC_CS35L56_CORE");
-void cs35l56_disable_sdw_interrupts(struct cs35l56_private *cs35l56)
+static void cs35l56_disable_sdw_interrupts(struct cs35l56_private *cs35l56)
{
if (!cs35l56->sdw_peripheral)
return;
- cs35l56->sdw_irq_no_unmask = true;
- flush_work(&cs35l56->sdw_irq_work);
-
- /* Mask interrupts and flush in case sdw_irq_work was queued again */
- cs35l56_mask_soundwire_interrupts(cs35l56->sdw_peripheral);
- flush_work(&cs35l56->sdw_irq_work);
+ cs35l56_mask_soundwire_interrupts(cs35l56);
+ if (cs35l56->base.irq)
+ disable_irq(cs35l56->base.irq);
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_disable_sdw_interrupts, "SND_SOC_CS35L56_CORE");
-void cs35l56_enable_sdw_interrupts(struct cs35l56_private *cs35l56)
+static void cs35l56_enable_sdw_interrupts(struct cs35l56_private *cs35l56)
{
- if (!cs35l56->sdw_peripheral)
+ if (!cs35l56->sdw_peripheral || !cs35l56->base.irq)
return;
- cs35l56->sdw_irq_no_unmask = false;
- cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral);
+ enable_irq(cs35l56->base.irq);
+ cs35l56_unmask_soundwire_interrupts(cs35l56);
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_enable_sdw_interrupts, "SND_SOC_CS35L56_CORE");
static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
@@ -828,11 +829,7 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56, bool firmware_missing
{
int ret;
- /*
- * Disable SoundWire interrupts to prevent race with IRQ work.
- * Setting sdw_irq_no_unmask prevents the handler re-enabling
- * the SoundWire interrupt.
- */
+ /* Disable SoundWire interrupts to prevent race with IRQ handler thread */
cs35l56_disable_sdw_interrupts(cs35l56);
ret = cs35l56_firmware_shutdown(&cs35l56->base);
@@ -1402,6 +1399,7 @@ static int _cs35l56_component_probe(struct snd_soc_component *component)
ARRAY_SIZE(cs35l56_controls));
break;
case 0x63:
+ case 0x62:
ret = snd_soc_add_component_controls(component, cs35l63_controls,
ARRAY_SIZE(cs35l63_controls));
break;
@@ -1941,7 +1939,7 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5
return ret;
}
-int cs35l56_common_probe(struct cs35l56_private *cs35l56)
+int cs35l56_common_probe(struct cs35l56_private *cs35l56, int irq)
{
int ret;
@@ -2018,16 +2016,24 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
goto err_remove_wm_adsp;
}
+ ret = cs35l56_irq_request(&cs35l56->base, irq);
+ if (ret)
+ goto err_remove_wm_adsp;
+
ret = snd_soc_register_component(cs35l56->base.dev,
&soc_component_dev_cs35l56,
cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
if (ret < 0) {
dev_err_probe(cs35l56->base.dev, ret, "Register codec failed\n");
- goto err_remove_wm_adsp;
+ goto err_free_irq;
}
return 0;
+err_free_irq:
+ if (cs35l56->base.irq)
+ devm_free_irq(cs35l56->base.dev, cs35l56->base.irq, &cs35l56->base);
+
err_remove_wm_adsp:
wm_adsp2_remove(&cs35l56->dsp);
diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h
index 9acd2e7e17c9..35c02ae17de3 100644
--- a/sound/soc/codecs/cs35l56.h
+++ b/sound/soc/codecs/cs35l56.h
@@ -39,8 +39,6 @@ struct cs35l56_private {
struct sdw_slave *sdw_peripheral;
struct regmap *sdw_bus_regmap;
const char *fallback_fw_suffix;
- struct work_struct sdw_irq_work;
- bool sdw_irq_no_unmask;
bool soft_resetting;
bool sdw_attached;
struct completion init_completion;
@@ -65,10 +63,8 @@ static inline struct cs35l56_private *cs35l56_private_from_base(struct cs35l56_b
extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi;
-void cs35l56_mask_soundwire_interrupts(struct sdw_slave *peripheral);
-void cs35l56_unmask_soundwire_interrupts(struct sdw_slave *peripheral);
-void cs35l56_disable_sdw_interrupts(struct cs35l56_private *cs35l56);
-void cs35l56_enable_sdw_interrupts(struct cs35l56_private *cs35l56);
+void cs35l56_mask_soundwire_interrupts(struct cs35l56_private *cs35l56);
+void cs35l56_unmask_soundwire_interrupts(struct cs35l56_private *cs35l56);
int cs35l56_system_suspend(struct device *dev);
int cs35l56_system_suspend_late(struct device *dev);
@@ -76,9 +72,8 @@ int cs35l56_system_suspend_no_irq(struct device *dev);
int cs35l56_system_resume_no_irq(struct device *dev);
int cs35l56_system_resume_early(struct device *dev);
int cs35l56_system_resume(struct device *dev);
-irqreturn_t cs35l56_irq(int irq, void *data);
int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq);
-int cs35l56_common_probe(struct cs35l56_private *cs35l56);
+int cs35l56_common_probe(struct cs35l56_private *cs35l56, int irq);
int cs35l56_init(struct cs35l56_private *cs35l56);
void cs35l56_remove(struct cs35l56_private *cs35l56);
diff --git a/sound/soc/codecs/cs40l50-codec.c b/sound/soc/codecs/cs40l50-codec.c
index aa629ef53db4..676367163067 100644
--- a/sound/soc/codecs/cs40l50-codec.c
+++ b/sound/soc/codecs/cs40l50-codec.c
@@ -288,8 +288,8 @@ static int cs40l50_codec_driver_probe(struct platform_device *pdev)
}
static const struct platform_device_id cs40l50_id[] = {
- { "cs40l50-codec", },
- {}
+ { .name = "cs40l50-codec" },
+ { }
};
MODULE_DEVICE_TABLE(platform, cs40l50_id);
diff --git a/sound/soc/codecs/cs42l42-sdw.c b/sound/soc/codecs/cs42l42-sdw.c
index ad1256910a18..b61ca74dcf0b 100644
--- a/sound/soc/codecs/cs42l42-sdw.c
+++ b/sound/soc/codecs/cs42l42-sdw.c
@@ -481,10 +481,20 @@ static int cs42l42_sdw_runtime_resume(struct device *dev)
regcache_cache_only(cs42l42->regmap, false);
/* Sync LATCH_TO_VP first so the VP domain registers sync correctly */
- regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1);
- regcache_sync(cs42l42->regmap);
+ ret = regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1);
+ if (ret)
+ goto err_sync;
+
+ ret = regcache_sync(cs42l42->regmap);
+ if (ret)
+ goto err_sync;
return 0;
+
+err_sync:
+ regcache_cache_only(cs42l42->regmap, true);
+ regcache_mark_dirty(cs42l42->regmap);
+ return ret;
}
static int cs42l42_sdw_resume(struct device *dev)
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 2652a639a79a..fadf68860601 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -9,6 +9,7 @@
* Author: Michael White <michael.white@cirrus.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -565,7 +566,7 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
/* Prevent race with interrupt handler */
- mutex_lock(&cs42l42->irq_lock);
+ guard(mutex)(&cs42l42->irq_lock);
cs42l42->jack = jk;
if (jk) {
@@ -581,7 +582,6 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_
break;
}
}
- mutex_unlock(&cs42l42->irq_lock);
return 0;
}
@@ -1668,13 +1668,10 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data)
unsigned int current_button_status;
unsigned int i;
- pm_runtime_get_sync(cs42l42->dev);
- mutex_lock(&cs42l42->irq_lock);
- if (cs42l42->suspended || !cs42l42->init_done) {
- mutex_unlock(&cs42l42->irq_lock);
- pm_runtime_put_autosuspend(cs42l42->dev);
+ guard(pm_runtime_active_auto)(cs42l42->dev);
+ guard(mutex)(&cs42l42->irq_lock);
+ if (cs42l42->suspended || !cs42l42->init_done)
return IRQ_NONE;
- }
/* Read sticky registers to clear interurpt */
for (i = 0; i < ARRAY_SIZE(stickies); i++) {
@@ -1774,9 +1771,6 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data)
}
}
- mutex_unlock(&cs42l42->irq_lock);
- pm_runtime_put_autosuspend(cs42l42->dev);
-
return IRQ_HANDLED;
}
EXPORT_SYMBOL_NS_GPL(cs42l42_irq_thread, "SND_SOC_CS42L42_CORE");
@@ -2163,22 +2157,22 @@ int cs42l42_suspend(struct device *dev)
* future interrupts. This ensures a safe disable if the interrupt
* is shared.
*/
- mutex_lock(&cs42l42->irq_lock);
- cs42l42->suspended = true;
+ scoped_guard(mutex, &cs42l42->irq_lock) {
+ cs42l42->suspended = true;
- /* Save register values that will be overwritten by shutdown sequence */
- for (i = 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) {
- regmap_read(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, &reg);
- save_regs[i] = (u8)reg;
- }
+ /* Save register values that will be overwritten by shutdown sequence */
+ for (i = 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) {
+ regmap_read(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, &reg);
+ save_regs[i] = (u8)reg;
+ }
- /* Shutdown codec */
- regmap_multi_reg_write(cs42l42->regmap,
- cs42l42_shutdown_seq,
- ARRAY_SIZE(cs42l42_shutdown_seq));
+ /* Shutdown codec */
+ regmap_multi_reg_write(cs42l42->regmap,
+ cs42l42_shutdown_seq,
+ ARRAY_SIZE(cs42l42_shutdown_seq));
- /* All interrupt sources are now disabled */
- mutex_unlock(&cs42l42->irq_lock);
+ /* All interrupt sources are now disabled */
+ }
/* Wait for power-down complete */
msleep(CS42L42_PDN_DONE_TIME_MS);
@@ -2250,13 +2244,13 @@ void cs42l42_resume_restore(struct device *dev)
regcache_cache_only(cs42l42->regmap, false);
regcache_mark_dirty(cs42l42->regmap);
- mutex_lock(&cs42l42->irq_lock);
- /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */
- regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1);
- regcache_sync(cs42l42->regmap);
+ scoped_guard(mutex, &cs42l42->irq_lock) {
+ /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */
+ regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1);
+ regcache_sync(cs42l42->regmap);
- cs42l42->suspended = false;
- mutex_unlock(&cs42l42->irq_lock);
+ cs42l42->suspended = false;
+ }
dev_dbg(dev, "System resumed\n");
}
diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c
index dbf45cabfffe..a2555dd9229e 100644
--- a/sound/soc/codecs/cs42l43-jack.c
+++ b/sound/soc/codecs/cs42l43-jack.c
@@ -6,6 +6,7 @@
// Cirrus Logic International Semiconductor Ltd.
#include <linux/build_bug.h>
+#include <linux/cleanup.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/errno.h>
@@ -67,6 +68,21 @@ static int cs42l43_find_index(struct cs42l43_codec *priv, const char * const pro
return -EINVAL;
}
+static void cs42l43_apply_accdet_config(struct cs42l43_codec *priv,
+ unsigned int autocontrol,
+ unsigned int pdncntl)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
+ CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK |
+ CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol);
+ regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL,
+ CS42L43_RING_SENSE_EN_MASK, pdncntl);
+
+ dev_dbg(priv->dev, "Successfully configured accessory detect\n");
+}
+
int cs42l43_set_jack(struct snd_soc_component *component,
struct snd_soc_jack *jack, void *d)
{
@@ -80,31 +96,34 @@ int cs42l43_set_jack(struct snd_soc_component *component,
dev_dbg(priv->dev, "Configure accessory detect\n");
- ret = pm_runtime_resume_and_get(priv->dev);
+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (ret) {
dev_err(priv->dev, "Failed to resume for jack config: %d\n", ret);
return ret;
}
- mutex_lock(&priv->jack_lock);
+ guard(mutex)(&priv->jack_lock);
priv->jack_hp = jack;
- if (!jack)
- goto done;
+ if (!jack) {
+ cs42l43_apply_accdet_config(priv, autocontrol, pdncntl);
+ return 0;
+ }
ret = device_property_count_u32(cs42l43->dev, "cirrus,buttons-ohms");
if (ret != -EINVAL) {
if (ret < 0) {
dev_err(priv->dev, "Property cirrus,buttons-ohms malformed: %d\n",
ret);
- goto error;
+ return ret;
}
if (ret > CS42L43_N_BUTTONS) {
ret = -EINVAL;
dev_err(priv->dev, "Property cirrus,buttons-ohms too many entries\n");
- goto error;
+ return ret;
}
ret = device_property_read_u32_array(cs42l43->dev, "cirrus,buttons-ohms",
@@ -112,7 +131,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
if (ret < 0) {
dev_err(priv->dev, "Property cirrus,button-ohms malformed: %d\n",
ret);
- goto error;
+ return ret;
}
} else {
priv->buttons[0] = 70;
@@ -124,7 +143,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
ret = cs42l43_find_index(priv, "cirrus,detect-us", 50000, &priv->detect_us,
cs42l43_accdet_us, ARRAY_SIZE(cs42l43_accdet_us));
if (ret < 0)
- goto error;
+ return ret;
hs2 |= ret << CS42L43_AUTO_HSDET_TIME_SHIFT;
@@ -134,7 +153,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
&priv->bias_ramp_ms, cs42l43_accdet_ramp_ms,
ARRAY_SIZE(cs42l43_accdet_ramp_ms));
if (ret < 0)
- goto error;
+ return ret;
hs2 |= ret << CS42L43_HSBIAS_RAMP_SHIFT;
@@ -142,7 +161,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
&priv->bias_sense_ua, cs42l43_accdet_bias_sense,
ARRAY_SIZE(cs42l43_accdet_bias_sense));
if (ret < 0)
- goto error;
+ return ret;
if (priv->bias_sense_ua)
autocontrol |= ret << CS42L43_HSBIAS_SENSE_TRIP_SHIFT;
@@ -154,7 +173,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
&priv->tip_debounce_ms);
if (ret < 0 && ret != -EINVAL) {
dev_err(priv->dev, "Property cirrus,tip-debounce-ms malformed: %d\n", ret);
- goto error;
+ return ret;
}
/* This tip sense invert is set normally, as TIPSENSE_INV already inverted */
@@ -170,7 +189,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
&priv->tip_fall_db_ms, cs42l43_accdet_db_ms,
ARRAY_SIZE(cs42l43_accdet_db_ms));
if (ret < 0)
- goto error;
+ return ret;
tip_deb |= ret << CS42L43_TIPSENSE_FALLING_DB_TIME_SHIFT;
@@ -178,7 +197,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
&priv->tip_rise_db_ms, cs42l43_accdet_db_ms,
ARRAY_SIZE(cs42l43_accdet_db_ms));
if (ret < 0)
- goto error;
+ return ret;
tip_deb |= ret << CS42L43_TIPSENSE_RISING_DB_TIME_SHIFT;
@@ -199,7 +218,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
NULL, cs42l43_accdet_db_ms,
ARRAY_SIZE(cs42l43_accdet_db_ms));
if (ret < 0)
- goto error;
+ return ret;
ring_deb |= ret << CS42L43_RINGSENSE_FALLING_DB_TIME_SHIFT;
@@ -207,7 +226,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
NULL, cs42l43_accdet_db_ms,
ARRAY_SIZE(cs42l43_accdet_db_ms));
if (ret < 0)
- goto error;
+ return ret;
ring_deb |= ret << CS42L43_RINGSENSE_RISING_DB_TIME_SHIFT;
pdncntl |= CS42L43_RING_SENSE_EN_MASK;
@@ -228,23 +247,9 @@ int cs42l43_set_jack(struct snd_soc_component *component,
CS42L43_HSBIAS_RAMP_MASK | CS42L43_HSDET_MODE_MASK |
CS42L43_AUTO_HSDET_TIME_MASK, hs2);
-done:
- ret = 0;
-
- regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
- CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK |
- CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol);
- regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL,
- CS42L43_RING_SENSE_EN_MASK, pdncntl);
-
- dev_dbg(priv->dev, "Successfully configured accessory detect\n");
-
-error:
- mutex_unlock(&priv->jack_lock);
-
- pm_runtime_put_autosuspend(priv->dev);
+ cs42l43_apply_accdet_config(priv, autocontrol, pdncntl);
- return ret;
+ return 0;
}
static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool type_detect)
@@ -370,22 +375,22 @@ irqreturn_t cs42l43_button_press(int irq, void *data)
{
struct cs42l43_codec *priv = data;
struct cs42l43 *cs42l43 = priv->core;
- irqreturn_t iret = IRQ_NONE;
unsigned int buttons = 0;
unsigned int val = 0;
int i, ret;
- ret = pm_runtime_resume_and_get(priv->dev);
+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (ret) {
dev_err(priv->dev, "Failed to resume for button press: %d\n", ret);
- return iret;
+ return IRQ_NONE;
}
- mutex_lock(&priv->jack_lock);
+ guard(mutex)(&priv->jack_lock);
if (!priv->button_detect_running) {
dev_dbg(priv->dev, "Spurious button press IRQ\n");
- goto error;
+ return IRQ_NONE;
}
// Wait for 2 full cycles of comb filter to ensure good reading
@@ -396,12 +401,12 @@ irqreturn_t cs42l43_button_press(int irq, void *data)
/* Bail if jack removed, the button is irrelevant and likely invalid */
if (!cs42l43_jack_present(priv)) {
dev_dbg(priv->dev, "Button ignored due to removal\n");
- goto error;
+ return IRQ_NONE;
}
if (val & CS42L43_HSBIAS_CLAMP_STS_MASK) {
dev_dbg(priv->dev, "Button ignored due to bias sense\n");
- goto error;
+ return IRQ_NONE;
}
val = (val & CS42L43_HSDET_DC_STS_MASK) >> CS42L43_HSDET_DC_STS_SHIFT;
@@ -424,45 +429,32 @@ irqreturn_t cs42l43_button_press(int irq, void *data)
snd_soc_jack_report(priv->jack_hp, buttons, CS42L43_JACK_BUTTONS);
- iret = IRQ_HANDLED;
-
-error:
- mutex_unlock(&priv->jack_lock);
-
- pm_runtime_put_autosuspend(priv->dev);
-
- return iret;
+ return IRQ_HANDLED;
}
irqreturn_t cs42l43_button_release(int irq, void *data)
{
struct cs42l43_codec *priv = data;
- irqreturn_t iret = IRQ_NONE;
int ret;
- ret = pm_runtime_resume_and_get(priv->dev);
+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (ret) {
dev_err(priv->dev, "Failed to resume for button release: %d\n", ret);
- return iret;
+ return IRQ_NONE;
}
- mutex_lock(&priv->jack_lock);
-
- if (priv->button_detect_running) {
- dev_dbg(priv->dev, "Button release IRQ\n");
-
- snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS);
+ guard(mutex)(&priv->jack_lock);
- iret = IRQ_HANDLED;
- } else {
+ if (!priv->button_detect_running) {
dev_dbg(priv->dev, "Spurious button release IRQ\n");
+ return IRQ_NONE;
}
- mutex_unlock(&priv->jack_lock);
+ dev_dbg(priv->dev, "Button release IRQ\n");
+ snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS);
- pm_runtime_put_autosuspend(priv->dev);
-
- return iret;
+ return IRQ_HANDLED;
}
void cs42l43_bias_sense_timeout(struct work_struct *work)
@@ -472,13 +464,14 @@ void cs42l43_bias_sense_timeout(struct work_struct *work)
struct cs42l43 *cs42l43 = priv->core;
int ret;
- ret = pm_runtime_resume_and_get(priv->dev);
+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (ret) {
dev_err(priv->dev, "Failed to resume for bias sense: %d\n", ret);
return;
}
- mutex_lock(&priv->jack_lock);
+ guard(mutex)(&priv->jack_lock);
if (cs42l43_jack_present(priv) && priv->button_detect_running) {
dev_dbg(priv->dev, "Bias sense timeout out, restore bias\n");
@@ -491,10 +484,6 @@ void cs42l43_bias_sense_timeout(struct work_struct *work)
CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK,
CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK);
}
-
- mutex_unlock(&priv->jack_lock);
-
- pm_runtime_put_autosuspend(priv->dev);
}
static const struct reg_sequence cs42l43_3pole_patch[] = {
@@ -896,9 +885,8 @@ int cs42l43_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
- mutex_lock(&priv->jack_lock);
+ guard(mutex)(&priv->jack_lock);
ucontrol->value.integer.value[0] = priv->jack_override;
- mutex_unlock(&priv->jack_lock);
return 0;
}
@@ -914,17 +902,13 @@ int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u
if (override >= e->items)
return -EINVAL;
- mutex_lock(&priv->jack_lock);
+ guard(mutex)(&priv->jack_lock);
- if (!cs42l43_jack_present(priv)) {
- mutex_unlock(&priv->jack_lock);
+ if (!cs42l43_jack_present(priv))
return -EBUSY;
- }
- if (override == priv->jack_override) {
- mutex_unlock(&priv->jack_lock);
+ if (override == priv->jack_override)
return 0;
- }
priv->jack_override = override;
@@ -984,7 +968,5 @@ int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u
cs42l43_jack_override_modes[override].report);
}
- mutex_unlock(&priv->jack_lock);
-
return 1;
}
diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c
index 1d133577702e..1b817e1a6ea5 100644
--- a/sound/soc/codecs/cs42l43.c
+++ b/sound/soc/codecs/cs42l43.c
@@ -8,6 +8,7 @@
#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/build_bug.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -1207,14 +1208,12 @@ static void cs42l43_spk_vu_sync(struct cs42l43_codec *priv)
{
struct cs42l43 *cs42l43 = priv->core;
- mutex_lock(&priv->spk_vu_lock);
+ guard(mutex)(&priv->spk_vu_lock);
regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1,
CS42L43_AMP1_2_VU_MASK, CS42L43_AMP1_2_VU_MASK);
regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1,
CS42L43_AMP1_2_VU_MASK, 0);
-
- mutex_unlock(&priv->spk_vu_lock);
}
static int cs42l43_shutter_get(struct cs42l43_codec *priv, unsigned int shift)
@@ -1601,7 +1600,7 @@ static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w,
struct cs42l43 *cs42l43 = priv->core;
int ret;
- mutex_lock(&cs42l43->pll_lock);
+ guard(mutex)(&cs42l43->pll_lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1626,8 +1625,6 @@ static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w,
break;
}
- mutex_unlock(&cs42l43->pll_lock);
-
return ret;
}
@@ -2565,13 +2562,10 @@ static int cs42l43_set_sysclk(struct snd_soc_component *component, int clk_id,
{
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
struct cs42l43 *cs42l43 = priv->core;
- int ret;
- mutex_lock(&cs42l43->pll_lock);
- ret = cs42l43_set_pll(priv, src, freq);
- mutex_unlock(&cs42l43->pll_lock);
+ guard(mutex)(&cs42l43->pll_lock);
- return ret;
+ return cs42l43_set_pll(priv, src, freq);
}
static int cs42l43_component_probe(struct snd_soc_component *component)
@@ -2941,8 +2935,8 @@ static const struct dev_pm_ops cs42l43_codec_pm_ops = {
};
static const struct platform_device_id cs42l43_codec_id_table[] = {
- { "cs42l43-codec", },
- {}
+ { .name = "cs42l43-codec" },
+ { }
};
MODULE_DEVICE_TABLE(platform, cs42l43_codec_id_table);
diff --git a/sound/soc/codecs/cs42l84.c b/sound/soc/codecs/cs42l84.c
index f2448b4c11fc..a545730b7ed9 100644
--- a/sound/soc/codecs/cs42l84.c
+++ b/sound/soc/codecs/cs42l84.c
@@ -10,6 +10,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -280,10 +281,9 @@ static int cs42l84_set_jack(struct snd_soc_component *component, struct snd_soc_
struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component);
/* Prevent race with interrupt handler */
- mutex_lock(&cs42l84->irq_lock);
+ guard(mutex)(&cs42l84->irq_lock);
cs42l84->jack = jk;
snd_soc_jack_report(jk, cs42l84->hs_type, SND_JACK_HEADSET);
- mutex_unlock(&cs42l84->irq_lock);
return 0;
}
@@ -830,7 +830,7 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data)
u8 current_ring_state;
int i;
- mutex_lock(&cs42l84->irq_lock);
+ guard(mutex)(&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,
@@ -901,8 +901,6 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data)
break;
}
- mutex_unlock(&cs42l84->irq_lock);
-
return IRQ_HANDLED;
}
@@ -918,8 +916,6 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data)
}
}
- mutex_unlock(&cs42l84->irq_lock);
-
return IRQ_HANDLED;
}
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c
index e7b06f962790..48d88dad4ceb 100644
--- a/sound/soc/codecs/cs43130.c
+++ b/sound/soc/codecs/cs43130.c
@@ -6,6 +6,7 @@
*
* Authors: Li Xu <li.xu@cirrus.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -818,26 +819,26 @@ static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream,
unsigned int required_clk;
u8 dsd_speed;
- mutex_lock(&cs43130->clk_mutex);
- if (!cs43130->clk_req) {
- /* no DAI is currently using clk */
- if (!(CS43130_MCLK_22M % params_rate(params)))
- required_clk = CS43130_MCLK_22M;
- else
- required_clk = CS43130_MCLK_24M;
+ scoped_guard(mutex, &cs43130->clk_mutex) {
+ if (!cs43130->clk_req) {
+ /* no DAI is currently using clk */
+ if (!(CS43130_MCLK_22M % params_rate(params)))
+ required_clk = CS43130_MCLK_22M;
+ else
+ required_clk = CS43130_MCLK_24M;
+
+ cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk);
+ if (cs43130->pll_bypass)
+ cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
+ else
+ cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
+ }
- cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk);
- if (cs43130->pll_bypass)
- cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
- else
- cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
+ cs43130->clk_req++;
+ if (cs43130->clk_req == 2)
+ cs43130_pcm_dsd_mix(true, cs43130->regmap);
}
- cs43130->clk_req++;
- if (cs43130->clk_req == 2)
- cs43130_pcm_dsd_mix(true, cs43130->regmap);
- mutex_unlock(&cs43130->clk_mutex);
-
switch (params_rate(params)) {
case 176400:
dsd_speed = 0;
@@ -881,26 +882,26 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream,
unsigned int required_clk;
u8 dsd_speed;
- mutex_lock(&cs43130->clk_mutex);
- if (!cs43130->clk_req) {
- /* no DAI is currently using clk */
- if (!(CS43130_MCLK_22M % params_rate(params)))
- required_clk = CS43130_MCLK_22M;
- else
- required_clk = CS43130_MCLK_24M;
+ scoped_guard(mutex, &cs43130->clk_mutex) {
+ if (!cs43130->clk_req) {
+ /* no DAI is currently using clk */
+ if (!(CS43130_MCLK_22M % params_rate(params)))
+ required_clk = CS43130_MCLK_22M;
+ else
+ required_clk = CS43130_MCLK_24M;
+
+ cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk);
+ if (cs43130->pll_bypass)
+ cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
+ else
+ cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
+ }
- cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk);
- if (cs43130->pll_bypass)
- cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
- else
- cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
+ cs43130->clk_req++;
+ if (cs43130->clk_req == 2)
+ cs43130_pcm_dsd_mix(true, cs43130->regmap);
}
- cs43130->clk_req++;
- if (cs43130->clk_req == 2)
- cs43130_pcm_dsd_mix(true, cs43130->regmap);
- mutex_unlock(&cs43130->clk_mutex);
-
switch (dai->id) {
case CS43130_ASP_DOP_DAI:
case CS43130_XSP_DOP_DAI:
@@ -988,14 +989,13 @@ static int cs43130_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
- mutex_lock(&cs43130->clk_mutex);
+ guard(mutex)(&cs43130->clk_mutex);
cs43130->clk_req--;
if (!cs43130->clk_req) {
/* no DAI is currently using clk */
cs43130_change_clksrc(component, CS43130_MCLK_SRC_RCO);
cs43130_pcm_dsd_mix(false, cs43130->regmap);
}
- mutex_unlock(&cs43130->clk_mutex);
return 0;
}
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
index 6ac6d306b054..9a7f70175717 100644
--- a/sound/soc/codecs/cs4349.c
+++ b/sound/soc/codecs/cs4349.c
@@ -340,7 +340,13 @@ static int cs4349_runtime_resume(struct device *dev)
gpiod_set_value_cansleep(cs4349->reset_gpio, 1);
regcache_cache_only(cs4349->regmap, false);
- regcache_sync(cs4349->regmap);
+ ret = regcache_sync(cs4349->regmap);
+ if (ret) {
+ regcache_cache_only(cs4349->regmap, true);
+ regcache_mark_dirty(cs4349->regmap);
+ gpiod_set_value_cansleep(cs4349->reset_gpio, 0);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c
index da64e0a1db28..2f30dd834709 100644
--- a/sound/soc/codecs/cs47l15.c
+++ b/sound/soc/codecs/cs47l15.c
@@ -6,6 +6,7 @@
// Cirrus Logic International Semiconductor Ltd.
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
@@ -1285,9 +1286,8 @@ static int cs47l15_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_to_dapm(component);
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = snd_soc_component_to_dapm(component);
ret = madera_init_inputs(component);
if (ret)
@@ -1317,9 +1317,8 @@ static void cs47l15_component_remove(struct snd_soc_component *component)
struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component);
struct madera *madera = cs47l15->core.madera;
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = NULL;
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = NULL;
wm_adsp2_component_remove(&cs47l15->core.adsp[0], component);
}
diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c
index a8fe5a99a8bb..e77ac7bc8466 100644
--- a/sound/soc/codecs/cs47l35.c
+++ b/sound/soc/codecs/cs47l35.c
@@ -6,6 +6,7 @@
// Cirrus Logic International Semiconductor Ltd.
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/init.h>
@@ -1566,9 +1567,8 @@ static int cs47l35_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_to_dapm(component);
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = snd_soc_component_to_dapm(component);
ret = madera_init_inputs(component);
if (ret)
@@ -1600,9 +1600,8 @@ static void cs47l35_component_remove(struct snd_soc_component *component)
struct madera *madera = cs47l35->core.madera;
int i;
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = NULL;
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = NULL;
for (i = 0; i < CS47L35_NUM_ADSP; i++)
wm_adsp2_component_remove(&cs47l35->core.adsp[i], component);
diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c
index 42fafb0b392c..9ee60616c04c 100644
--- a/sound/soc/codecs/cs47l85.c
+++ b/sound/soc/codecs/cs47l85.c
@@ -6,6 +6,7 @@
// Cirrus Logic International Semiconductor Ltd.
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
@@ -2504,9 +2505,8 @@ static int cs47l85_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_to_dapm(component);
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = snd_soc_component_to_dapm(component);
ret = madera_init_inputs(component);
if (ret)
@@ -2537,9 +2537,8 @@ static void cs47l85_component_remove(struct snd_soc_component *component)
struct madera *madera = cs47l85->core.madera;
int i;
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = NULL;
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = NULL;
for (i = 0; i < CS47L85_NUM_ADSP; i++)
wm_adsp2_component_remove(&cs47l85->core.adsp[i], component);
diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c
index 77e8aabb241a..6ce603bfd500 100644
--- a/sound/soc/codecs/cs47l90.c
+++ b/sound/soc/codecs/cs47l90.c
@@ -6,6 +6,7 @@
// Cirrus Logic International Semiconductor Ltd.
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
@@ -2423,9 +2424,8 @@ static int cs47l90_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_to_dapm(component);
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = snd_soc_component_to_dapm(component);
ret = madera_init_inputs(component);
if (ret)
@@ -2456,9 +2456,8 @@ static void cs47l90_component_remove(struct snd_soc_component *component)
struct madera *madera = cs47l90->core.madera;
int i;
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = NULL;
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = NULL;
for (i = 0; i < CS47L90_NUM_ADSP; i++)
wm_adsp2_component_remove(&cs47l90->core.adsp[i], component);
diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c
index 868237bd6d91..07bc303d9797 100644
--- a/sound/soc/codecs/cs47l92.c
+++ b/sound/soc/codecs/cs47l92.c
@@ -6,6 +6,7 @@
// Cirrus Logic International Semiconductor Ltd.
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
@@ -1892,9 +1893,8 @@ static int cs47l92_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_to_dapm(component);
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = snd_soc_component_to_dapm(component);
ret = madera_init_inputs(component);
if (ret)
@@ -1922,9 +1922,8 @@ static void cs47l92_component_remove(struct snd_soc_component *component)
struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component);
struct madera *madera = cs47l92->core.madera;
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = NULL;
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = NULL;
wm_adsp2_component_remove(&cs47l92->core.adsp[0], component);
}
diff --git a/sound/soc/codecs/cs48l32.c b/sound/soc/codecs/cs48l32.c
index 086ed0f57a85..a9967771124e 100644
--- a/sound/soc/codecs/cs48l32.c
+++ b/sound/soc/codecs/cs48l32.c
@@ -8,6 +8,7 @@
#include <dt-bindings/sound/cs48l32.h>
#include <linux/array_size.h>
#include <linux/build_bug.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/container_of.h>
#include <linux/delay.h>
@@ -236,15 +237,13 @@ static int cs48l32_rate_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
int ret;
/* Prevent any mixer mux changes while we do this */
- mutex_lock(&cs48l32_codec->rate_lock);
+ guard(mutex)(&cs48l32_codec->rate_lock);
/* The write must be guarded by a number of SYSCLK cycles */
cs48l32_spin_sysclk(cs48l32_codec);
ret = snd_soc_put_enum_double(kcontrol, ucontrol);
cs48l32_spin_sysclk(cs48l32_codec);
- mutex_unlock(&cs48l32_codec->rate_lock);
-
return ret;
}
@@ -2242,7 +2241,6 @@ static int cs48l32_dai_set_sysclk(struct snd_soc_dai *dai,
struct cs48l32_dai_priv *dai_priv = &cs48l32_codec->dai[dai->id - 1];
unsigned int base = dai->driver->base;
unsigned int current_asp_rate, target_asp_rate;
- bool change_rate_domain = false;
int ret;
if (clk_id == dai_priv->clk)
@@ -2284,19 +2282,15 @@ static int cs48l32_dai_set_sysclk(struct snd_soc_dai *dai,
if ((current_asp_rate & CS48L32_ASP_RATE_MASK) !=
(target_asp_rate & CS48L32_ASP_RATE_MASK)) {
- change_rate_domain = true;
-
- mutex_lock(&cs48l32_codec->rate_lock);
/* Guard the rate change with SYSCLK cycles */
- cs48l32_spin_sysclk(cs48l32_codec);
- }
-
- snd_soc_component_update_bits(component, base + CS48L32_ASP_CONTROL1,
- CS48L32_ASP_RATE_MASK, target_asp_rate);
-
- if (change_rate_domain) {
- cs48l32_spin_sysclk(cs48l32_codec);
- mutex_unlock(&cs48l32_codec->rate_lock);
+ scoped_guard(mutex, &cs48l32_codec->rate_lock) {
+ cs48l32_spin_sysclk(cs48l32_codec);
+ snd_soc_component_update_bits(component,
+ base + CS48L32_ASP_CONTROL1,
+ CS48L32_ASP_RATE_MASK,
+ target_asp_rate);
+ cs48l32_spin_sysclk(cs48l32_codec);
+ }
}
}
diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c
index 0dd35fa86cc5..d02ab74e549b 100644
--- a/sound/soc/codecs/cx2072x.c
+++ b/sound/soc/codecs/cx2072x.c
@@ -9,6 +9,7 @@
//
#include <linux/acpi.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
@@ -96,51 +97,60 @@ static const struct reg_default cx2072x_reg_defaults[] = {
{ CX2072X_GPIO_WAKE, 0x00000000 },
{ CX2072X_GPIO_UM_ENABLE, 0x00000000 },
{ CX2072X_GPIO_STICKY_MASK, 0x00000000 },
- { CX2072X_DAC1_CONVERTER_FORMAT, 0x00000031 },
- { CX2072X_DAC1_AMP_GAIN_RIGHT, 0x0000004a },
- { CX2072X_DAC1_AMP_GAIN_LEFT, 0x0000004a },
{ CX2072X_DAC1_POWER_STATE, 0x00000433 },
{ CX2072X_DAC1_CONVERTER_STREAM_CHANNEL, 0x00000000 },
{ CX2072X_DAC1_EAPD_ENABLE, 0x00000000 },
- { CX2072X_DAC2_CONVERTER_FORMAT, 0x00000031 },
- { CX2072X_DAC2_AMP_GAIN_RIGHT, 0x0000004a },
- { CX2072X_DAC2_AMP_GAIN_LEFT, 0x0000004a },
+ { CX2072X_DAC1_AMP_GAIN_RIGHT, 0x0000004a },
+ { CX2072X_DAC1_AMP_GAIN_LEFT, 0x0000004a },
+ { CX2072X_DAC1_CONVERTER_FORMAT, 0x00000031 },
{ CX2072X_DAC2_POWER_STATE, 0x00000433 },
{ CX2072X_DAC2_CONVERTER_STREAM_CHANNEL, 0x00000000 },
- { CX2072X_ADC1_CONVERTER_FORMAT, 0x00000031 },
+ { CX2072X_DAC2_AMP_GAIN_RIGHT, 0x0000004a },
+ { CX2072X_DAC2_AMP_GAIN_LEFT, 0x0000004a },
+ { CX2072X_DAC2_CONVERTER_FORMAT, 0x00000031 },
+ { CX2072X_ADC1_CONNECTION_SELECT_CONTROL, 0x00000000 },
+ { CX2072X_ADC1_POWER_STATE, 0x00000433 },
+ { CX2072X_ADC1_CONVERTER_STREAM_CHANNEL, 0x00000000 },
{ CX2072X_ADC1_AMP_GAIN_RIGHT_0, 0x0000004a },
- { CX2072X_ADC1_AMP_GAIN_LEFT_0, 0x0000004a },
{ CX2072X_ADC1_AMP_GAIN_RIGHT_1, 0x0000004a },
- { CX2072X_ADC1_AMP_GAIN_LEFT_1, 0x0000004a },
{ CX2072X_ADC1_AMP_GAIN_RIGHT_2, 0x0000004a },
- { CX2072X_ADC1_AMP_GAIN_LEFT_2, 0x0000004a },
{ CX2072X_ADC1_AMP_GAIN_RIGHT_3, 0x0000004a },
- { CX2072X_ADC1_AMP_GAIN_LEFT_3, 0x0000004a },
{ CX2072X_ADC1_AMP_GAIN_RIGHT_4, 0x0000004a },
- { CX2072X_ADC1_AMP_GAIN_LEFT_4, 0x0000004a },
{ CX2072X_ADC1_AMP_GAIN_RIGHT_5, 0x0000004a },
- { CX2072X_ADC1_AMP_GAIN_LEFT_5, 0x0000004a },
{ CX2072X_ADC1_AMP_GAIN_RIGHT_6, 0x0000004a },
+ { CX2072X_ADC1_AMP_GAIN_LEFT_0, 0x0000004a },
+ { CX2072X_ADC1_AMP_GAIN_LEFT_1, 0x0000004a },
+ { CX2072X_ADC1_AMP_GAIN_LEFT_2, 0x0000004a },
+ { CX2072X_ADC1_AMP_GAIN_LEFT_3, 0x0000004a },
+ { CX2072X_ADC1_AMP_GAIN_LEFT_4, 0x0000004a },
+ { CX2072X_ADC1_AMP_GAIN_LEFT_5, 0x0000004a },
{ CX2072X_ADC1_AMP_GAIN_LEFT_6, 0x0000004a },
- { CX2072X_ADC1_CONNECTION_SELECT_CONTROL, 0x00000000 },
- { CX2072X_ADC1_POWER_STATE, 0x00000433 },
- { CX2072X_ADC1_CONVERTER_STREAM_CHANNEL, 0x00000000 },
- { CX2072X_ADC2_CONVERTER_FORMAT, 0x00000031 },
+ { CX2072X_ADC1_CONVERTER_FORMAT, 0x00000031 },
+ { CX2072X_ADC2_CONNECTION_SELECT_CONTROL, 0x00000000 },
+ { CX2072X_ADC2_POWER_STATE, 0x00000433 },
+ { CX2072X_ADC2_CONVERTER_STREAM_CHANNEL, 0x00000000 },
{ CX2072X_ADC2_AMP_GAIN_RIGHT_0, 0x0000004a },
- { CX2072X_ADC2_AMP_GAIN_LEFT_0, 0x0000004a },
{ CX2072X_ADC2_AMP_GAIN_RIGHT_1, 0x0000004a },
- { CX2072X_ADC2_AMP_GAIN_LEFT_1, 0x0000004a },
{ CX2072X_ADC2_AMP_GAIN_RIGHT_2, 0x0000004a },
+ { CX2072X_ADC2_AMP_GAIN_LEFT_0, 0x0000004a },
+ { CX2072X_ADC2_AMP_GAIN_LEFT_1, 0x0000004a },
{ CX2072X_ADC2_AMP_GAIN_LEFT_2, 0x0000004a },
- { CX2072X_ADC2_CONNECTION_SELECT_CONTROL, 0x00000000 },
- { CX2072X_ADC2_POWER_STATE, 0x00000433 },
- { CX2072X_ADC2_CONVERTER_STREAM_CHANNEL, 0x00000000 },
+ { CX2072X_ADC2_CONVERTER_FORMAT, 0x00000031 },
+ { CX2072X_MIXER_POWER_STATE, 0x00000433 },
+ { CX2072X_MIXER_GAIN_RIGHT_0, 0x0000004a },
+ { CX2072X_MIXER_GAIN_RIGHT_1, 0x0000004a },
+ { CX2072X_MIXER_GAIN_LEFT_0, 0x0000004a },
+ { CX2072X_MIXER_GAIN_LEFT_1, 0x0000004a },
{ CX2072X_PORTA_CONNECTION_SELECT_CTRL, 0x00000000 },
{ CX2072X_PORTA_POWER_STATE, 0x00000433 },
{ CX2072X_PORTA_PIN_CTRL, 0x000000c0 },
{ CX2072X_PORTA_UNSOLICITED_RESPONSE, 0x00000000 },
{ CX2072X_PORTA_PIN_SENSE, 0x00000000 },
{ CX2072X_PORTA_EAPD_BTL, 0x00000002 },
+ { CX2072X_PORTG_CONNECTION_SELECT_CTRL, 0x00000000 },
+ { CX2072X_PORTG_POWER_STATE, 0x00000433 },
+ { CX2072X_PORTG_PIN_CTRL, 0x00000040 },
+ { CX2072X_PORTG_EAPD_BTL, 0x00000002 },
{ CX2072X_PORTB_POWER_STATE, 0x00000433 },
{ CX2072X_PORTB_PIN_CTRL, 0x00000000 },
{ CX2072X_PORTB_UNSOLICITED_RESPONSE, 0x00000000 },
@@ -148,43 +158,16 @@ static const struct reg_default cx2072x_reg_defaults[] = {
{ CX2072X_PORTB_EAPD_BTL, 0x00000002 },
{ CX2072X_PORTB_GAIN_RIGHT, 0x00000000 },
{ CX2072X_PORTB_GAIN_LEFT, 0x00000000 },
- { CX2072X_PORTC_POWER_STATE, 0x00000433 },
- { CX2072X_PORTC_PIN_CTRL, 0x00000000 },
- { CX2072X_PORTC_GAIN_RIGHT, 0x00000000 },
- { CX2072X_PORTC_GAIN_LEFT, 0x00000000 },
{ CX2072X_PORTD_POWER_STATE, 0x00000433 },
{ CX2072X_PORTD_PIN_CTRL, 0x00000020 },
{ CX2072X_PORTD_UNSOLICITED_RESPONSE, 0x00000000 },
{ CX2072X_PORTD_PIN_SENSE, 0x00000000 },
{ CX2072X_PORTD_GAIN_RIGHT, 0x00000000 },
{ CX2072X_PORTD_GAIN_LEFT, 0x00000000 },
- { CX2072X_PORTE_CONNECTION_SELECT_CTRL, 0x00000000 },
- { CX2072X_PORTE_POWER_STATE, 0x00000433 },
- { CX2072X_PORTE_PIN_CTRL, 0x00000040 },
- { CX2072X_PORTE_UNSOLICITED_RESPONSE, 0x00000000 },
- { CX2072X_PORTE_PIN_SENSE, 0x00000000 },
- { CX2072X_PORTE_EAPD_BTL, 0x00000002 },
- { CX2072X_PORTE_GAIN_RIGHT, 0x00000000 },
- { CX2072X_PORTE_GAIN_LEFT, 0x00000000 },
- { CX2072X_PORTF_POWER_STATE, 0x00000433 },
- { CX2072X_PORTF_PIN_CTRL, 0x00000000 },
- { CX2072X_PORTF_UNSOLICITED_RESPONSE, 0x00000000 },
- { CX2072X_PORTF_PIN_SENSE, 0x00000000 },
- { CX2072X_PORTF_GAIN_RIGHT, 0x00000000 },
- { CX2072X_PORTF_GAIN_LEFT, 0x00000000 },
- { CX2072X_PORTG_POWER_STATE, 0x00000433 },
- { CX2072X_PORTG_PIN_CTRL, 0x00000040 },
- { CX2072X_PORTG_CONNECTION_SELECT_CTRL, 0x00000000 },
- { CX2072X_PORTG_EAPD_BTL, 0x00000002 },
- { CX2072X_PORTM_POWER_STATE, 0x00000433 },
- { CX2072X_PORTM_PIN_CTRL, 0x00000000 },
- { CX2072X_PORTM_CONNECTION_SELECT_CTRL, 0x00000000 },
- { CX2072X_PORTM_EAPD_BTL, 0x00000002 },
- { CX2072X_MIXER_POWER_STATE, 0x00000433 },
- { CX2072X_MIXER_GAIN_RIGHT_0, 0x0000004a },
- { CX2072X_MIXER_GAIN_LEFT_0, 0x0000004a },
- { CX2072X_MIXER_GAIN_RIGHT_1, 0x0000004a },
- { CX2072X_MIXER_GAIN_LEFT_1, 0x0000004a },
+ { CX2072X_PORTC_POWER_STATE, 0x00000433 },
+ { CX2072X_PORTC_PIN_CTRL, 0x00000000 },
+ { CX2072X_PORTC_GAIN_RIGHT, 0x00000000 },
+ { CX2072X_PORTC_GAIN_LEFT, 0x00000000 },
{ CX2072X_SPKR_DRC_ENABLE_STEP, 0x040065a4 },
{ CX2072X_SPKR_DRC_CONTROL, 0x007b0024 },
{ CX2072X_SPKR_DRC_TEST, 0x00000000 },
@@ -195,12 +178,15 @@ static const struct reg_default cx2072x_reg_defaults[] = {
{ CX2072X_I2SPCM_CONTROL3, 0x00000000 },
{ CX2072X_I2SPCM_CONTROL4, 0x00000000 },
{ CX2072X_I2SPCM_CONTROL5, 0x00000000 },
- { CX2072X_I2SPCM_CONTROL6, 0x00000000 },
{ CX2072X_UM_INTERRUPT_CRTL_E, 0x00000000 },
+ { CX2072X_I2SPCM_CONTROL6, 0x00000000 },
+ { CX2072X_DIGITAL_TEST16, 0x00000021 },
+ { CX2072X_DIGITAL_TEST17, 0x00000018 },
+ { CX2072X_DIGITAL_TEST18, 0x00000024 },
+ { CX2072X_DIGITAL_TEST19, 0x00000001 },
+ { CX2072X_DIGITAL_TEST20, 0x00000002 },
{ CX2072X_CODEC_TEST2, 0x00000000 },
{ CX2072X_CODEC_TEST9, 0x00000004 },
- { CX2072X_CODEC_TEST20, 0x00000600 },
- { CX2072X_CODEC_TEST26, 0x00000208 },
{ CX2072X_ANALOG_TEST4, 0x00000000 },
{ CX2072X_ANALOG_TEST5, 0x00000000 },
{ CX2072X_ANALOG_TEST6, 0x0000059a },
@@ -215,11 +201,26 @@ static const struct reg_default cx2072x_reg_defaults[] = {
{ CX2072X_DIGITAL_TEST11, 0x00000000 },
{ CX2072X_DIGITAL_TEST12, 0x00000084 },
{ CX2072X_DIGITAL_TEST15, 0x00000077 },
- { CX2072X_DIGITAL_TEST16, 0x00000021 },
- { CX2072X_DIGITAL_TEST17, 0x00000018 },
- { CX2072X_DIGITAL_TEST18, 0x00000024 },
- { CX2072X_DIGITAL_TEST19, 0x00000001 },
- { CX2072X_DIGITAL_TEST20, 0x00000002 },
+ { CX2072X_CODEC_TEST20, 0x00000600 },
+ { CX2072X_CODEC_TEST26, 0x00000208 },
+ { CX2072X_PORTE_CONNECTION_SELECT_CTRL, 0x00000000 },
+ { CX2072X_PORTE_POWER_STATE, 0x00000433 },
+ { CX2072X_PORTE_PIN_CTRL, 0x00000040 },
+ { CX2072X_PORTE_UNSOLICITED_RESPONSE, 0x00000000 },
+ { CX2072X_PORTE_PIN_SENSE, 0x00000000 },
+ { CX2072X_PORTE_EAPD_BTL, 0x00000002 },
+ { CX2072X_PORTE_GAIN_RIGHT, 0x00000000 },
+ { CX2072X_PORTE_GAIN_LEFT, 0x00000000 },
+ { CX2072X_PORTF_POWER_STATE, 0x00000433 },
+ { CX2072X_PORTF_PIN_CTRL, 0x00000000 },
+ { CX2072X_PORTF_UNSOLICITED_RESPONSE, 0x00000000 },
+ { CX2072X_PORTF_PIN_SENSE, 0x00000000 },
+ { CX2072X_PORTF_GAIN_RIGHT, 0x00000000 },
+ { CX2072X_PORTF_GAIN_LEFT, 0x00000000 },
+ { CX2072X_PORTM_CONNECTION_SELECT_CTRL, 0x00000000 },
+ { CX2072X_PORTM_POWER_STATE, 0x00000433 },
+ { CX2072X_PORTM_PIN_CTRL, 0x00000000 },
+ { CX2072X_PORTM_EAPD_BTL, 0x00000002 },
};
/*
@@ -1408,7 +1409,7 @@ static int cx2072x_jack_status_check(void *data)
unsigned int type = 0;
int state = 0;
- mutex_lock(&cx2072x->lock);
+ guard(mutex)(&cx2072x->lock);
regmap_read(cx2072x->regmap, CX2072X_PORTA_PIN_SENSE, &jack);
jack = jack >> 24;
@@ -1434,8 +1435,6 @@ static int cx2072x_jack_status_check(void *data)
/* clear interrupt */
regmap_write(cx2072x->regmap, CX2072X_UM_INTERRUPT_CRTL_E, 0x12 << 24);
- mutex_unlock(&cx2072x->lock);
-
dev_dbg(codec->dev, "CX2072X_HSDETECT type=0x%X,Jack state = %x\n",
type, state);
return state;
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 4bf91ab2553a..923b997efbc4 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -11,6 +11,7 @@
#include <linux/acpi.h>
#include <linux/of.h>
#include <linux/property.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -216,13 +217,10 @@ static int da7213_volsw_locked_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7213->ctrl_lock);
- ret = snd_soc_get_volsw(kcontrol, ucontrol);
- mutex_unlock(&da7213->ctrl_lock);
+ guard(mutex)(&da7213->ctrl_lock);
- return ret;
+ return snd_soc_get_volsw(kcontrol, ucontrol);
}
static int da7213_volsw_locked_put(struct snd_kcontrol *kcontrol,
@@ -230,13 +228,10 @@ static int da7213_volsw_locked_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7213->ctrl_lock);
- ret = snd_soc_put_volsw(kcontrol, ucontrol);
- mutex_unlock(&da7213->ctrl_lock);
+ guard(mutex)(&da7213->ctrl_lock);
- return ret;
+ return snd_soc_put_volsw(kcontrol, ucontrol);
}
static int da7213_enum_locked_get(struct snd_kcontrol *kcontrol,
@@ -244,13 +239,10 @@ static int da7213_enum_locked_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7213->ctrl_lock);
- ret = snd_soc_get_enum_double(kcontrol, ucontrol);
- mutex_unlock(&da7213->ctrl_lock);
+ guard(mutex)(&da7213->ctrl_lock);
- return ret;
+ return snd_soc_get_enum_double(kcontrol, ucontrol);
}
static int da7213_enum_locked_put(struct snd_kcontrol *kcontrol,
@@ -258,13 +250,10 @@ static int da7213_enum_locked_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7213->ctrl_lock);
- ret = snd_soc_put_enum_double(kcontrol, ucontrol);
- mutex_unlock(&da7213->ctrl_lock);
+ guard(mutex)(&da7213->ctrl_lock);
- return ret;
+ return snd_soc_put_enum_double(kcontrol, ucontrol);
}
/* ALC */
@@ -465,9 +454,8 @@ static int da7213_tonegen_freq_get(struct snd_kcontrol *kcontrol,
__le16 val;
int ret;
- mutex_lock(&da7213->ctrl_lock);
- ret = regmap_raw_read(da7213->regmap, reg, &val, sizeof(val));
- mutex_unlock(&da7213->ctrl_lock);
+ scoped_guard(mutex, &da7213->ctrl_lock)
+ ret = regmap_raw_read(da7213->regmap, reg, &val, sizeof(val));
if (ret)
return ret;
@@ -499,12 +487,11 @@ static int da7213_tonegen_freq_put(struct snd_kcontrol *kcontrol,
*/
val_new = cpu_to_le16(ucontrol->value.integer.value[0]);
- mutex_lock(&da7213->ctrl_lock);
+ guard(mutex)(&da7213->ctrl_lock);
ret = regmap_raw_read(da7213->regmap, reg, &val_old, sizeof(val_old));
if (ret == 0 && (val_old != val_new))
ret = regmap_raw_write(da7213->regmap, reg,
&val_new, sizeof(val_new));
- mutex_unlock(&da7213->ctrl_lock);
if (ret < 0)
return ret;
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index f0874d891e12..f6d371e93549 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -8,6 +8,7 @@
*/
#include <linux/acpi.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
@@ -256,13 +257,10 @@ static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7219->ctrl_lock);
- ret = snd_soc_get_volsw(kcontrol, ucontrol);
- mutex_unlock(&da7219->ctrl_lock);
+ guard(mutex)(&da7219->ctrl_lock);
- return ret;
+ return snd_soc_get_volsw(kcontrol, ucontrol);
}
static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol,
@@ -270,13 +268,10 @@ static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7219->ctrl_lock);
- ret = snd_soc_put_volsw(kcontrol, ucontrol);
- mutex_unlock(&da7219->ctrl_lock);
+ guard(mutex)(&da7219->ctrl_lock);
- return ret;
+ return snd_soc_put_volsw(kcontrol, ucontrol);
}
static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol,
@@ -284,13 +279,10 @@ static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7219->ctrl_lock);
- ret = snd_soc_get_enum_double(kcontrol, ucontrol);
- mutex_unlock(&da7219->ctrl_lock);
+ guard(mutex)(&da7219->ctrl_lock);
- return ret;
+ return snd_soc_get_enum_double(kcontrol, ucontrol);
}
static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol,
@@ -298,13 +290,10 @@ static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7219->ctrl_lock);
- ret = snd_soc_put_enum_double(kcontrol, ucontrol);
- mutex_unlock(&da7219->ctrl_lock);
+ guard(mutex)(&da7219->ctrl_lock);
- return ret;
+ return snd_soc_put_enum_double(kcontrol, ucontrol);
}
/* ALC */
@@ -422,9 +411,8 @@ static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol,
__le16 val;
int ret;
- mutex_lock(&da7219->ctrl_lock);
- ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val));
- mutex_unlock(&da7219->ctrl_lock);
+ scoped_guard(mutex, &da7219->ctrl_lock)
+ ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val));
if (ret)
return ret;
@@ -456,12 +444,11 @@ static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol,
*/
val_new = cpu_to_le16(ucontrol->value.integer.value[0]);
- mutex_lock(&da7219->ctrl_lock);
+ guard(mutex)(&da7219->ctrl_lock);
ret = regmap_raw_read(da7219->regmap, reg, &val_old, sizeof(val_old));
if (ret == 0 && (val_old != val_new))
ret = regmap_raw_write(da7219->regmap, reg,
- &val_new, sizeof(val_new));
- mutex_unlock(&da7219->ctrl_lock);
+ &val_new, sizeof(val_new));
if (ret < 0)
return ret;
@@ -1167,15 +1154,12 @@ 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;
- mutex_lock(&da7219->pll_lock);
+ guard(mutex)(&da7219->pll_lock);
- if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq)) {
- mutex_unlock(&da7219->pll_lock);
+ if (da7219->clk_src == clk_id && da7219->mclk_rate == freq)
return 0;
- }
- if ((freq < 2000000) || (freq > 54000000)) {
- mutex_unlock(&da7219->pll_lock);
+ if (freq < 2000000 || freq > 54000000) {
dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
freq);
return -EINVAL;
@@ -1193,7 +1177,6 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
break;
default:
dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
- mutex_unlock(&da7219->pll_lock);
return -EINVAL;
}
@@ -1203,17 +1186,13 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
freq = clk_round_rate(da7219->mclk, freq);
ret = clk_set_rate(da7219->mclk, freq);
if (ret) {
- dev_err(codec_dai->dev, "Failed to set clock rate %d\n",
- freq);
- mutex_unlock(&da7219->pll_lock);
+ dev_err(codec_dai->dev, "Failed to set clock rate %d\n", freq);
return ret;
}
}
da7219->mclk_rate = freq;
- mutex_unlock(&da7219->pll_lock);
-
return 0;
}
@@ -1296,13 +1275,10 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
{
struct snd_soc_component *component = codec_dai->component;
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7219->pll_lock);
- ret = da7219_set_pll(component, source, fout);
- mutex_unlock(&da7219->pll_lock);
+ guard(mutex)(&da7219->pll_lock);
- return ret;
+ return da7219_set_pll(component, source, fout);
}
static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index 3abe77423f29..24ec8b211cdb 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -9,11 +9,13 @@
#include <linux/module.h>
#include <linux/acpi.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -30,6 +32,13 @@ static const unsigned int supported_mclk_lrck_ratios[] = {
256, 384, 400, 500, 512, 768, 1024
};
+static const char * const es8316_supply_names[] = {
+ "avdd",
+ "cpvdd",
+ "dvdd",
+ "pvdd",
+};
+
struct es8316_priv {
struct mutex lock;
struct clk *mclk;
@@ -620,15 +629,15 @@ static irqreturn_t es8316_irq(int irq, void *data)
struct snd_soc_component *comp = es8316->component;
unsigned int flags;
- mutex_lock(&es8316->lock);
+ guard(mutex)(&es8316->lock);
regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags);
if (flags == 0x00)
- goto out; /* Powered-down / reset */
+ return IRQ_HANDLED; /* Powered-down / reset */
/* Catch spurious IRQ before set_jack is called */
if (!es8316->jack)
- goto out;
+ return IRQ_HANDLED;
if (es8316->jd_inverted)
flags ^= ES8316_GPIO_FLAG_HP_NOT_INSERTED;
@@ -681,8 +690,6 @@ static irqreturn_t es8316_irq(int irq, void *data)
}
}
-out:
- mutex_unlock(&es8316->lock);
return IRQ_HANDLED;
}
@@ -699,18 +706,16 @@ static void es8316_enable_jack_detect(struct snd_soc_component *component,
es8316->jd_inverted = device_property_read_bool(component->dev,
"everest,jack-detect-inverted");
- mutex_lock(&es8316->lock);
-
- es8316->jack = jack;
+ scoped_guard(mutex, &es8316->lock) {
+ es8316->jack = jack;
- if (es8316->jack->status & SND_JACK_MICROPHONE)
- es8316_enable_micbias_for_mic_gnd_short_detect(component);
-
- snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE,
- ES8316_GPIO_ENABLE_INTERRUPT,
- ES8316_GPIO_ENABLE_INTERRUPT);
+ if (es8316->jack->status & SND_JACK_MICROPHONE)
+ es8316_enable_micbias_for_mic_gnd_short_detect(component);
- mutex_unlock(&es8316->lock);
+ snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE,
+ ES8316_GPIO_ENABLE_INTERRUPT,
+ ES8316_GPIO_ENABLE_INTERRUPT);
+ }
/* Enable irq and sync initial jack state */
enable_irq(es8316->irq);
@@ -726,7 +731,7 @@ static void es8316_disable_jack_detect(struct snd_soc_component *component)
disable_irq(es8316->irq);
- mutex_lock(&es8316->lock);
+ guard(mutex)(&es8316->lock);
snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE,
ES8316_GPIO_ENABLE_INTERRUPT, 0);
@@ -737,8 +742,6 @@ static void es8316_disable_jack_detect(struct snd_soc_component *component)
}
es8316->jack = NULL;
-
- mutex_unlock(&es8316->lock);
}
static int es8316_set_jack(struct snd_soc_component *component,
@@ -871,6 +874,11 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client)
i2c_set_clientdata(i2c_client, es8316);
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(es8316_supply_names),
+ es8316_supply_names);
+ if (ret)
+ return dev_err_probe(dev, ret, "unable to enable supplies\n");
+
es8316->regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap);
if (IS_ERR(es8316->regmap))
return PTR_ERR(es8316->regmap);
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
index a79b2da35099..c5460589a88b 100644
--- a/sound/soc/codecs/es8326.c
+++ b/sound/soc/codecs/es8326.c
@@ -6,6 +6,7 @@
// Authors: David Yang <yangxiaohua@everest-semi.com>
//
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
@@ -790,7 +791,7 @@ static void es8326_jack_button_handler(struct work_struct *work)
if (!(es8326->jack->status & SND_JACK_HEADSET)) /* Jack unplugged */
return;
- mutex_lock(&es8326->lock);
+ guard(mutex)(&es8326->lock);
iface = snd_soc_component_read(comp, ES8326_HPDET_STA);
switch (iface) {
case 0x93:
@@ -845,7 +846,6 @@ static void es8326_jack_button_handler(struct work_struct *work)
}
es8326_disable_micbias(es8326->component);
}
- mutex_unlock(&es8326->lock);
}
static void es8326_jack_detect_handler(struct work_struct *work)
@@ -855,7 +855,7 @@ static void es8326_jack_detect_handler(struct work_struct *work)
struct snd_soc_component *comp = es8326->component;
unsigned int iface;
- mutex_lock(&es8326->lock);
+ guard(mutex)(&es8326->lock);
iface = snd_soc_component_read(comp, ES8326_HPDET_STA);
dev_dbg(comp->dev, "gpio flag %#04x", iface);
@@ -873,7 +873,7 @@ static void es8326_jack_detect_handler(struct work_struct *work)
regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE,
ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ?
~es8326->jack_pol : es8326->jack_pol));
- goto exit;
+ return;
}
if ((iface & ES8326_HPINSERT_FLAG) == 0) {
@@ -930,7 +930,7 @@ static void es8326_jack_detect_handler(struct work_struct *work)
queue_delayed_work(system_dfl_wq, &es8326->jack_detect_work,
msecs_to_jiffies(400));
es8326->hp = 1;
- goto exit;
+ return;
}
if (es8326->jack->status & SND_JACK_HEADSET) {
/* detect button */
@@ -939,7 +939,7 @@ static void es8326_jack_detect_handler(struct work_struct *work)
(ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON));
es8326_enable_micbias(es8326->component);
queue_delayed_work(system_dfl_wq, &es8326->button_press_work, 10);
- goto exit;
+ return;
}
if ((iface & ES8326_HPBUTTON_FLAG) == 0x01) {
dev_dbg(comp->dev, "Headphone detected\n");
@@ -958,8 +958,6 @@ static void es8326_jack_detect_handler(struct work_struct *work)
usleep_range(10000, 15000);
}
}
-exit:
- mutex_unlock(&es8326->lock);
}
static irqreturn_t es8326_irq(int irq, void *dev_id)
@@ -1200,13 +1198,12 @@ static void es8326_enable_jack_detect(struct snd_soc_component *component,
{
struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
- mutex_lock(&es8326->lock);
- if (es8326->jd_inverted)
- snd_soc_component_update_bits(component, ES8326_HPDET_TYPE,
- ES8326_HP_DET_JACK_POL, ~es8326->jack_pol);
- es8326->jack = jack;
-
- mutex_unlock(&es8326->lock);
+ scoped_guard(mutex, &es8326->lock) {
+ if (es8326->jd_inverted)
+ snd_soc_component_update_bits(component, ES8326_HPDET_TYPE,
+ ES8326_HP_DET_JACK_POL, ~es8326->jack_pol);
+ es8326->jack = jack;
+ }
es8326_irq(es8326->irq, es8326);
}
@@ -1219,13 +1216,12 @@ static void es8326_disable_jack_detect(struct snd_soc_component *component)
return; /* Already disabled (or never enabled) */
cancel_delayed_work_sync(&es8326->jack_detect_work);
- mutex_lock(&es8326->lock);
+ guard(mutex)(&es8326->lock);
if (es8326->jack->status & SND_JACK_MICROPHONE) {
es8326_disable_micbias(component);
snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
}
es8326->jack = NULL;
- mutex_unlock(&es8326->lock);
}
static int es8326_set_jack(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index 9838fe42cb6f..aaa6646ad4c5 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -405,6 +405,11 @@ static const struct snd_soc_dapm_route es8328_dapm_routes[] = {
{ "Mic Bias", NULL, "Mic Bias Gen" },
+ { "LINPUT1", NULL, "Mic Bias" },
+ { "RINPUT1", NULL, "Mic Bias" },
+ { "LINPUT2", NULL, "Mic Bias" },
+ { "RINPUT2", NULL, "Mic Bias" },
+
{ "Left Mixer", NULL, "Left DAC" },
{ "Left Mixer", "Left Bypass Switch", "Left Line Mux" },
{ "Left Mixer", "Right Playback Switch", "Right DAC" },
diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c
index 3484c87853cb..80efce3e0a22 100644
--- a/sound/soc/codecs/es8389.c
+++ b/sound/soc/codecs/es8389.c
@@ -36,6 +36,10 @@ struct es8389_private {
unsigned int sysclk;
int mastermode;
+ u8 hpfl;
+ u8 hpfr;
+ u32 hpf_freq;
+ u32 capture_rate;
u8 mclk_src;
u8 vddd;
int version;
@@ -50,10 +54,29 @@ static const char * const es8389_core_supplies[] = {
static bool es8389_volatile_register(struct device *dev,
unsigned int reg)
{
- if ((reg <= 0xff))
- return true;
- else
+ switch (reg) {
+ case ES8389_ADCL_VOL:
+ case ES8389_ADCR_VOL:
+ case ES8389_MIC1_GAIN:
+ case ES8389_MIC2_GAIN:
+ case ES8389_DACL_VOL:
+ case ES8389_DACR_VOL:
+ case ES8389_ALC_ON:
+ case ES8389_ALC_CTL:
+ case ES8389_ALC_TARGET:
+ case ES8389_ALC_GAIN:
+ case ES8389_ADC_MUTE:
+ case ES8389_OSR_VOL:
+ case ES8389_DAC_INV:
+ case ES8389_MIX_VOL:
+ case ES8389_DAC_MIX:
+ case ES8389_ADC_RESET:
+ case ES8389_ADC_MODE:
+ case ES8389_DMIC_EN:
return false;
+ default:
+ return true;
+ }
}
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
@@ -63,6 +86,92 @@ static const DECLARE_TLV_DB_SCALE(mix_vol_tlv, -9500, 100, 0);
static const DECLARE_TLV_DB_SCALE(alc_target_tlv, -3200, 200, 0);
static const DECLARE_TLV_DB_SCALE(alc_max_level, -3200, 200, 0);
+static const u32 hpf_table[10][10] = {
+ {1020, 754, 624, 559, 527, 511, 502, 498, 497, 496},
+ {754, 495, 368, 306, 274, 259, 251, 247, 246, 244},
+ {624, 368, 243, 182, 151, 136, 128, 124, 123, 121},
+ {559, 306, 182, 120, 90, 75, 68, 63, 62, 60},
+ {527, 274, 151, 90, 60, 45, 38, 33, 32, 31},
+ {511, 259, 136, 75, 45, 30, 23, 19, 18, 17},
+ {502, 251, 128, 68, 38, 23, 16, 13, 11, 11},
+ {498, 247, 124, 63, 33, 19, 13, 10, 8, 8},
+ {497, 246, 123, 62, 32, 18, 11, 8, 8, 0},
+ {496, 244, 121, 60, 31, 17, 11, 8, 0, 0}
+};
+
+static bool find_best_hpf_freq(u32 target_hz, u8 *hpf1, u8 *hpf2, u32 *out)
+{
+ int best_row = -1, best_col = -1;
+ u32 min_diff = U32_MAX;
+ u32 f, diff;
+ int i, j;
+
+ if (target_hz > 1020)
+ return false;
+
+ for (i = 0; i < 10; i++) {
+ for (j = i; j < 10; j++) {
+ f = hpf_table[i][j];
+
+ diff = (target_hz > f) ? (target_hz - f) : (f - target_hz);
+ if (diff < min_diff) {
+ min_diff = diff;
+ best_row = i;
+ best_col = j;
+ *out = f;
+ }
+ }
+ }
+
+ *hpf1 = best_col + ES8389_HPF_OFFSET;
+ *hpf2 = best_row + ES8389_HPF_OFFSET;
+
+ return true;
+}
+
+static int es8389_hpf_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = es8389->hpf_freq;
+ return 0;
+}
+
+static int es8389_hpf_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+ u32 freq;
+ bool hpf;
+
+ if (es8389->hpf_freq == ucontrol->value.integer.value[0])
+ return 0;
+
+ if (es8389->capture_rate) {
+ freq = (ucontrol->value.integer.value[0] * 48000) / es8389->capture_rate;
+
+ hpf = find_best_hpf_freq(freq, &es8389->hpfl, &es8389->hpfr, &es8389->hpf_freq);
+ if (!hpf)
+ return -EBUSY;
+
+ if (es8389->hpf_freq != ucontrol->value.integer.value[0])
+ dev_dbg(component->dev, "At the %u Hz sampling rate, %ld Hz could not be obtained."
+ "the frequency has been set to the closest value, %u Hz\n",
+ es8389->capture_rate, ucontrol->value.integer.value[0], es8389->hpf_freq);
+
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, es8389->hpfl);
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, es8389->hpfr);
+ } else {
+ es8389->hpf_freq = ucontrol->value.integer.value[0];
+ dev_dbg(component->dev, "PCM_STREAM_CAPTURE is not active.retain the input frequency\n");
+ }
+
+ return 1;
+}
+
static int es8389_dmic_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -143,6 +252,16 @@ static const struct soc_enum alc_ramprate =
static const struct soc_enum alc_winsize =
SOC_ENUM_SINGLE(ES8389_ALC_CTL, 0, 16, winsize);
+static const char *const es8389_adcl_mux_txt[] = {
+ "Normal",
+ "ADC2 channel to ADC1 channel",
+};
+
+static const char *const es8389_adcr_mux_txt[] = {
+ "Normal",
+ "ADC1 channel to ADC2 channel",
+};
+
static const char *const es8389_outl_mux_txt[] = {
"Normal",
"DAC2 channel to DAC1 channel",
@@ -170,6 +289,20 @@ static const unsigned int es8389_pga_values[] = {
1, 5, 6
};
+static const struct soc_enum es8389_adcl_mux_enum =
+ SOC_ENUM_SINGLE(ES8389_ADC_MODE, 5,
+ ARRAY_SIZE(es8389_adcl_mux_txt), es8389_adcl_mux_txt);
+
+static const struct snd_kcontrol_new es8389_adcl_mux_controls =
+ SOC_DAPM_ENUM("INPUTL MUX", es8389_adcl_mux_enum);
+
+static const struct soc_enum es8389_adcr_mux_enum =
+ SOC_ENUM_SINGLE(ES8389_ADC_MODE, 4,
+ ARRAY_SIZE(es8389_adcr_mux_txt), es8389_adcr_mux_txt);
+
+static const struct snd_kcontrol_new es8389_adcr_mux_controls =
+ SOC_DAPM_ENUM("INPUTR MUX", es8389_adcr_mux_enum);
+
static const struct soc_enum es8389_outl_mux_enum =
SOC_ENUM_SINGLE(ES8389_DAC_MIX, 5,
ARRAY_SIZE(es8389_outl_mux_txt), es8389_outl_mux_txt);
@@ -240,6 +373,8 @@ static const struct snd_kcontrol_new es8389_snd_controls[] = {
SOC_DOUBLE("ADC OSR Volume ON Switch", ES8389_ADC_MUTE, 6, 7, 1, 0),
SOC_SINGLE_TLV("ADC OSR Volume", ES8389_OSR_VOL, 0, 0xFF, 0, adc_vol_tlv),
SOC_DOUBLE("ADC OUTPUT Invert Switch", ES8389_ADC_HPF2, 5, 6, 1, 0),
+ SOC_SINGLE_EXT("ADC HPF Freq Select", SND_SOC_NOPM, 0, 1020, 0,
+ es8389_hpf_get, es8389_hpf_set),
SOC_SINGLE_TLV("DACL Playback Volume", ES8389_DACL_VOL, 0, 0xFF, 0, dac_vol_tlv),
SOC_SINGLE_TLV("DACR Playback Volume", ES8389_DACR_VOL, 0, 0xFF, 0, dac_vol_tlv),
@@ -298,6 +433,8 @@ static const struct snd_soc_dapm_widget es8389_dapm_widgets[] = {
&es8389_adc_mixer_controls[0],
ARRAY_SIZE(es8389_adc_mixer_controls)),
SND_SOC_DAPM_MUX("ADC MUX", SND_SOC_NOPM, 0, 0, &es8389_dmic_mux_controls),
+ SND_SOC_DAPM_MUX("INPUTL MUX", SND_SOC_NOPM, 0, 0, &es8389_adcl_mux_controls),
+ SND_SOC_DAPM_MUX("INPUTR MUX", SND_SOC_NOPM, 0, 0, &es8389_adcr_mux_controls),
SND_SOC_DAPM_MUX("OUTL MUX", SND_SOC_NOPM, 0, 0, &es8389_outl_mux_controls),
SND_SOC_DAPM_MUX("OUTR MUX", SND_SOC_NOPM, 0, 0, &es8389_outr_mux_controls),
@@ -311,10 +448,15 @@ static const struct snd_soc_dapm_route es8389_dapm_routes[] = {
{"ADCL", NULL, "PGAL"},
{"ADCR", NULL, "PGAR"},
+ {"INPUTL MUX", "Normal", "ADCL"},
+ {"INPUTL MUX", "ADC2 channel to ADC1 channel", "ADCR"},
+ {"INPUTR MUX", "Normal", "ADCR"},
+ {"INPUTR MUX", "ADC1 channel to ADC2 channel", "ADCL"},
+
{"ADC Mixer", "DACL ADCL Mixer", "DACL"},
{"ADC Mixer", "DACR ADCR Mixer", "DACR"},
- {"ADC Mixer", NULL, "ADCL"},
- {"ADC Mixer", NULL, "ADCR"},
+ {"ADC Mixer", NULL, "INPUTL MUX"},
+ {"ADC Mixer", NULL, "INPUTR MUX"},
{"ADC MUX", "AMIC", "ADC Mixer"},
{"ADC MUX", "DMIC", "DMIC"},
@@ -415,52 +557,54 @@ static const struct _coeff_div coeff_div[] = {
{36, 576000, 16000, 0x00, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{48, 768000, 16000, 0x02, 0x57, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{50, 800000, 16000, 0x00, 0x7E, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {64, 1024000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {72, 1152000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {64, 1024000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {72, 1152000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{96, 1536000, 16000, 0x02, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{128, 2048000, 16000, 0x00, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{144, 2304000, 16000, 0x00, 0x51, 0x00, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {150, 2400000, 16000, 0x02, 0x7E, 0x01, 0xC9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{192, 3072000, 16000, 0x02, 0x65, 0x25, 0xE0, 0x00, 0xE1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {256, 4096000, 16000, 0x00, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {256, 4096000, 16000, 0x00, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{300, 4800000, 16000, 0x02, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{384, 6144000, 16000, 0x02, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {512, 8192000, 16000, 0x01, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {512, 8192000, 16000, 0x01, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{750, 12000000, 16000, 0x0E, 0x7E, 0x01, 0xC9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {768, 12288000, 16000, 0x02, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {1024, 16384000, 16000, 0x03, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {768, 12288000, 16000, 0x02, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {1024, 16384000, 16000, 0x03, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{1152, 18432000, 16000, 0x08, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{1200, 19200000, 16000, 0x0B, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{1500, 24000000, 16000, 0x0E, 0x26, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {1536, 24576000, 16000, 0x05, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {1536, 24576000, 16000, 0x05, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{1625, 26000000, 16000, 0x40, 0x6E, 0x05, 0xC8, 0x01, 0xC2, 0x90, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{800, 19200000, 24000, 0x07, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x1A, 0x49, 0x14, 2, 2},
{375, 12000000, 32000, 0x0E, 0x2E, 0x05, 0xC8, 0x00, 0xC2, 0x80, 0x40, 0x01, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 0},
- {600, 19200000, 32000, 0x05, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 2},
- {32, 1411200, 44100, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {600, 19200000, 32000, 0x05, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 2},
+ {32, 1411200, 44100, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{64, 2822400, 44100, 0x00, 0x51, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {128, 5644800, 44100, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {256, 11289600, 44100, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {512, 22579200, 44100, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {32, 1536000, 48000, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {128, 5644800, 44100, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {256, 11289600, 44100, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {512, 22579200, 44100, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {32, 1536000, 48000, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{48, 2304000, 48000, 0x02, 0x55, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{50, 2400000, 48000, 0x00, 0x76, 0x01, 0xC8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{64, 3072000, 48000, 0x00, 0x51, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {100, 4800000, 48000, 0x00, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {100, 4800000, 48000, 0x00, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{125, 6000000, 48000, 0x04, 0x6E, 0x05, 0xC8, 0x10, 0xC2, 0x80, 0x00, 0x01, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {128, 6144000, 48000, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {200, 9600000, 48000, 0x01, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {128, 6144000, 48000, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {200, 9600000, 48000, 0x01, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{250, 12000000, 48000, 0x04, 0x76, 0x01, 0xC8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {256, 12288000, 48000, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {384, 18432000, 48000, 0x02, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {400, 19200000, 48000, 0x03, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {500, 24000000, 48000, 0x04, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {512, 24576000, 48000, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {256, 12288000, 48000, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {384, 18432000, 48000, 0x02, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {400, 19200000, 48000, 0x03, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {500, 24000000, 48000, 0x04, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {512, 24576000, 48000, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{800, 38400000, 48000, 0x18, 0x45, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{128, 11289600, 88200, 0x00, 0x50, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x32, 0x89, 0x25, 2, 2},
- {64, 6144000, 96000, 0x00, 0x41, 0x00, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2},
+ {64, 6144000, 96000, 0x00, 0x41, 0x00, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2},
{96, 9216000, 96000, 0x02, 0x43, 0x00, 0xC0, 0x10, 0xC0, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2},
{256, 24576000, 96000, 0x00, 0x40, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2},
{128, 24576000, 192000, 0x00, 0x50, 0x00, 0xC0, 0x18, 0xC1, 0x81, 0xC0, 0x00, 0x8F, 0x7F, 0xBF, 0xC0, 0x3F, 0x7F, 0x80, 0x12, 0xC0, 0x3F, 0xF9, 0x3F, 2, 2},
+ {64, 12288000, 192000, 0x00, 0x41, 0x00, 0xC0, 0x18, 0xC1, 0x80, 0x00, 0x00, 0x8F, 0x7F, 0xEF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x3F, 0xF9, 0x3F, 1, 0},
};
static inline int get_coeff(u8 vddd, u8 dmic, int mclk, int rate)
@@ -564,6 +708,8 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream,
int coeff, ret;
u8 dmic_enable, state = 0;
unsigned int regv;
+ u32 freq;
+ bool hpf;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -590,7 +736,7 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream,
if (es8389->mclk_src == ES8389_SCLK_PIN) {
regmap_update_bits(es8389->regmap, ES8389_MASTER_CLK,
- ES8389_MCLK_SOURCE, es8389->mclk_src);
+ ES8389_MCLK_MASK, ES8389_MCLK_FROM_SCLK);
es8389->sysclk = params_channels(params) * params_width(params) * params_rate(params);
}
@@ -641,6 +787,28 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream,
dev_warn(component->dev, "Clock coefficients do not match");
}
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ es8389->capture_rate = params_rate(params);
+ freq = (es8389->hpf_freq * 48000) / params_rate(params);
+ hpf = find_best_hpf_freq(freq, &es8389->hpfl, &es8389->hpfr, &es8389->hpf_freq);
+ if (!hpf) {
+ dev_err(component->dev, "The HPF frequency is invalid\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int es8389_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ es8389->capture_rate = 0;
+
return 0;
}
@@ -721,8 +889,8 @@ static int es8389_mute(struct snd_soc_dai *dai, int mute, int direction)
regmap_update_bits(es8389->regmap, ES8389_DAC_FORMAT_MUTE,
0x03, 0x00);
} else {
- regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, 0x0a);
- regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, 0x0a);
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, es8389->hpfl);
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, es8389->hpfr);
regmap_update_bits(es8389->regmap, ES8389_ADC_FORMAT_MUTE,
0x03, 0x00);
}
@@ -738,6 +906,7 @@ static int es8389_mute(struct snd_soc_dai *dai, int mute, int direction)
static const struct snd_soc_dai_ops es8389_ops = {
.hw_params = es8389_pcm_hw_params,
+ .hw_free = es8389_pcm_hw_free,
.set_fmt = es8389_set_dai_fmt,
.set_sysclk = es8389_set_dai_sysclk,
.set_tdm_slot = es8389_set_tdm_slot,
@@ -771,7 +940,7 @@ static void es8389_init(struct snd_soc_component *component)
regmap_read(es8389->regmap, ES8389_MAX_REGISTER, &reg);
es8389->version = reg;
- regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x00);
+ regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x56);
regmap_write(es8389->regmap, ES8389_RESET, 0x7E);
regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x38);
regmap_write(es8389->regmap, ES8389_ADC_HPF1, 0x64);
@@ -823,7 +992,7 @@ static void es8389_init(struct snd_soc_component *component)
regmap_write(es8389->regmap, ES8389_SCLK_DIV, 0x04);
regmap_write(es8389->regmap, ES8389_LRCK_DIV1, 0x01);
regmap_write(es8389->regmap, ES8389_LRCK_DIV2, 0x00);
- regmap_write(es8389->regmap, ES8389_OSC_CLK, 0x00);
+ regmap_write(es8389->regmap, ES8389_OSC_CLK, 0x10);
regmap_write(es8389->regmap, ES8389_ADC_OSR, 0x1F);
regmap_write(es8389->regmap, ES8389_ADC_DSP, 0x7F);
regmap_write(es8389->regmap, ES8389_ADC_MUTE, 0xC0);
@@ -861,13 +1030,13 @@ static int es8389_resume(struct snd_soc_component *component)
regcache_cache_only(es8389->regmap, false);
regcache_cache_bypass(es8389->regmap, true);
regmap_read(es8389->regmap, ES8389_RESET, &regv);
- regcache_cache_bypass(es8389->regmap, false);
if (regv == 0xff)
es8389_init(component);
else
es8389_set_bias_level(component, SND_SOC_BIAS_ON);
+ regcache_cache_bypass(es8389->regmap, false);
regcache_sync(es8389->regmap);
return 0;
@@ -913,6 +1082,7 @@ static int es8389_probe(struct snd_soc_component *component)
return ret;
}
+ es8389->hpf_freq = ES8389_HPF_DEFAULT;
es8389_init(component);
es8389_set_bias_level(component, SND_SOC_BIAS_STANDBY);
diff --git a/sound/soc/codecs/es8389.h b/sound/soc/codecs/es8389.h
index d21e72f876a6..de39e9bf96e9 100644
--- a/sound/soc/codecs/es8389.h
+++ b/sound/soc/codecs/es8389.h
@@ -106,6 +106,9 @@
#define ES8389_MIC_SEL_MASK (7 << 4)
#define ES8389_MIC_DEFAULT (1 << 4)
+#define ES8389_HPF_DEFAULT 16
+#define ES8389_HPF_OFFSET 4
+
#define ES8389_MASTER_MODE_EN (1 << 0)
#define ES8389_TDM_OFF (0 << 0)
@@ -116,9 +119,11 @@
#define ES8389_TDM_SLOT (0x70 << 0)
#define ES8389_TDM_SHIFT 4
-#define ES8389_MCLK_SOURCE (1 << 6)
-#define ES8389_MCLK_PIN (1 << 6)
-#define ES8389_SCLK_PIN (0 << 6)
+#define ES8389_MCLK_MASK (3 << 6)
+#define ES8389_MCLK_FROM_SCLK (1 << 6)
+#define ES8389_MCLK_SOURCE ES8389_MCLK_PIN
+#define ES8389_MCLK_PIN 0
+#define ES8389_SCLK_PIN 1
/* ES8389_FMT */
#define ES8389_S24_LE (0 << 5)
diff --git a/sound/soc/codecs/es9356.c b/sound/soc/codecs/es9356.c
index 1122455aab77..80db0f2f4aef 100644
--- a/sound/soc/codecs/es9356.c
+++ b/sound/soc/codecs/es9356.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/soundwire/sdw.h>
@@ -19,8 +20,6 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
-#include <sound/sdca_function.h>
-#include <sound/sdca_regmap.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <sound/jack.h>
@@ -500,16 +499,19 @@ static int es9356_power_state(struct snd_soc_dai *dai, unsigned char ps, unsigne
}
/* power state changes are not independent across functions */
- mutex_lock(&es9356->pde_lock);
- ret = es9356_pde_transition_delay(es9356, func, pde_entity, ps?ps0:ps3);
- if (ret) {
- regmap_write(es9356->regmap,
- SDW_SDCA_CTL(func, pde_entity, ES9356_SDCA_CTL_REQ_POWER_STATE, 0), ps?ps3:ps0);
- es9356_pde_transition_delay(es9356, func, pde_entity, ps?ps3:ps0);
- } else
- dev_dbg(component->dev, "%s PDE is already %d\n", __func__, ps?ps0:ps3);
-
- mutex_unlock(&es9356->pde_lock);
+ scoped_guard(mutex, &es9356->pde_lock) {
+ ret = es9356_pde_transition_delay(es9356, func, pde_entity, ps ? ps0 : ps3);
+ if (ret) {
+ regmap_write(es9356->regmap,
+ SDW_SDCA_CTL(func, pde_entity,
+ ES9356_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps ? ps3 : ps0);
+ es9356_pde_transition_delay(es9356, func, pde_entity, ps ? ps3 : ps0);
+ } else {
+ dev_dbg(component->dev, "%s PDE is already %d\n", __func__,
+ ps ? ps0 : ps3);
+ }
+ }
if (rate)
regmap_write(es9356->regmap,
@@ -671,7 +673,7 @@ static int es9356_sdca_mbq_size(struct device *dev, unsigned int reg)
}
}
-static struct regmap_sdw_mbq_cfg es9356_mbq_config = {
+static const struct regmap_sdw_mbq_cfg es9356_mbq_config = {
.mbq_size = es9356_sdca_mbq_size,
};
@@ -1091,9 +1093,8 @@ static int es9356_sdca_dev_system_suspend(struct device *dev)
{
struct es9356_sdw_priv *es9356 = dev_get_drvdata(dev);
- mutex_lock(&es9356->disable_irq_lock);
- es9356->disable_irq = true;
- mutex_unlock(&es9356->disable_irq_lock);
+ scoped_guard(mutex, &es9356->disable_irq_lock)
+ es9356->disable_irq = true;
return es9356_sdca_dev_suspend(dev);
}
diff --git a/sound/soc/codecs/fs-amp-lib.c b/sound/soc/codecs/fs-amp-lib.c
index c8f56617e370..a562c72fc524 100644
--- a/sound/soc/codecs/fs-amp-lib.c
+++ b/sound/soc/codecs/fs-amp-lib.c
@@ -221,7 +221,7 @@ static void fs_print_firmware_info(struct fs_amp_lib *amp_lib)
int fs_amp_load_firmware(struct fs_amp_lib *amp_lib, const char *name)
{
- const struct firmware *cont;
+ const struct firmware *cont __free(firmware) = NULL;
struct fs_fwm_header *hdr;
int ret;
@@ -237,7 +237,6 @@ int fs_amp_load_firmware(struct fs_amp_lib *amp_lib, const char *name)
dev_info(amp_lib->dev, "Loading %s - size: %zu\n", name, cont->size);
hdr = devm_kmemdup(amp_lib->dev, cont->data, cont->size, GFP_KERNEL);
- release_firmware(cont);
if (!hdr)
return -ENOMEM;
diff --git a/sound/soc/codecs/fs210x.c b/sound/soc/codecs/fs210x.c
index d794ff918b6f..510cbeea5b62 100644
--- a/sound/soc/codecs/fs210x.c
+++ b/sound/soc/codecs/fs210x.c
@@ -4,6 +4,7 @@
//
// Copyright (C) 2016-2025 Shanghai FourSemi Semiconductor Co.,Ltd.
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -771,9 +772,8 @@ static int fs210x_dai_hw_params(struct snd_pcm_substream *substream,
if (fs210x->devid == FS2105S_DEVICE_ID && fs210x->srate == 16000)
return -EOPNOTSUPP;
- mutex_lock(&fs210x->lock);
- ret = fs210x_set_hw_params(fs210x);
- mutex_unlock(&fs210x->lock);
+ scoped_guard(mutex, &fs210x->lock)
+ ret = fs210x_set_hw_params(fs210x);
if (ret)
dev_err(fs210x->dev, "Failed to set hw params: %d\n", ret);
@@ -790,15 +790,11 @@ static int fs210x_dai_mute(struct snd_soc_dai *dai, int mute, int stream)
fs210x = snd_soc_component_get_drvdata(dai->component);
- mutex_lock(&fs210x->lock);
-
- if (!fs210x->is_inited || fs210x->is_suspended) {
- mutex_unlock(&fs210x->lock);
- return 0;
+ scoped_guard(mutex, &fs210x->lock) {
+ if (!fs210x->is_inited || fs210x->is_suspended)
+ return 0;
}
- mutex_unlock(&fs210x->lock);
-
if (mute) {
cancel_delayed_work_sync(&fs210x->fault_check_work);
cancel_delayed_work_sync(&fs210x->start_work);
@@ -817,15 +813,11 @@ static int fs210x_dai_trigger(struct snd_pcm_substream *substream,
fs210x = snd_soc_component_get_drvdata(dai->component);
- mutex_lock(&fs210x->lock);
-
- if (!fs210x->is_inited || fs210x->is_suspended || fs210x->is_playing) {
- mutex_unlock(&fs210x->lock);
- return 0;
+ scoped_guard(mutex, &fs210x->lock) {
+ if (!fs210x->is_inited || fs210x->is_suspended || fs210x->is_playing)
+ return 0;
}
- mutex_unlock(&fs210x->lock);
-
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -853,13 +845,11 @@ static void fs210x_start_work(struct work_struct *work)
fs210x = container_of(work, struct fs210x_priv, start_work.work);
- mutex_lock(&fs210x->lock);
+ guard(mutex)(&fs210x->lock);
ret = fs210x_dev_play(fs210x);
if (ret)
dev_err(fs210x->dev, "Failed to start playing: %d\n", ret);
-
- mutex_unlock(&fs210x->lock);
}
static void fs210x_fault_check_work(struct work_struct *work)
@@ -870,15 +860,13 @@ static void fs210x_fault_check_work(struct work_struct *work)
fs210x = container_of(work, struct fs210x_priv, fault_check_work.work);
- mutex_lock(&fs210x->lock);
+ scoped_guard(mutex, &fs210x->lock) {
+ if (!fs210x->is_inited || fs210x->is_suspended || !fs210x->is_playing)
+ return;
- if (!fs210x->is_inited || fs210x->is_suspended || !fs210x->is_playing) {
- mutex_unlock(&fs210x->lock);
- return;
+ ret = fs210x_reg_read(fs210x, FS210X_05H_ANASTAT, &status);
}
- ret = fs210x_reg_read(fs210x, FS210X_05H_ANASTAT, &status);
- mutex_unlock(&fs210x->lock);
if (ret)
return;
@@ -991,7 +979,7 @@ static int fs210x_effect_scene_get(struct snd_kcontrol *kcontrol,
if (fs210x->scene_id < 1)
return -EINVAL;
- mutex_lock(&fs210x->lock);
+ guard(mutex)(&fs210x->lock);
/*
* FS210x has scene(s) as below:
* init scene: id = 0
@@ -1000,7 +988,6 @@ static int fs210x_effect_scene_get(struct snd_kcontrol *kcontrol,
*/
index = fs210x->scene_id - 1;
ucontrol->value.integer.value[0] = index;
- mutex_unlock(&fs210x->lock);
return 0;
}
@@ -1019,7 +1006,7 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
}
- mutex_lock(&fs210x->lock);
+ guard(mutex)(&fs210x->lock);
/*
* FS210x has scene(s) as below:
@@ -1029,17 +1016,14 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol,
*/
scene_id = ucontrol->value.integer.value[0] + 1;
scene_count = fs210x->amp_lib.scene_count - 1; /* Skip init scene */
- if (scene_id < 1 || scene_id > scene_count) {
- mutex_unlock(&fs210x->lock);
+ if (scene_id < 1 || scene_id > scene_count)
return -ERANGE;
- }
if (scene_id != fs210x->scene_id)
is_changed = true;
if (fs210x->is_suspended) {
fs210x->scene_id = scene_id;
- mutex_unlock(&fs210x->lock);
return is_changed;
}
@@ -1047,8 +1031,6 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol,
if (ret)
dev_err(fs210x->dev, "Failed to set scene: %d\n", ret);
- mutex_unlock(&fs210x->lock);
-
if (!ret && is_changed)
return 1;
@@ -1062,12 +1044,10 @@ static int fs210x_playback_event(struct snd_soc_dapm_widget *w,
struct fs210x_priv *fs210x = snd_soc_component_get_drvdata(cmpnt);
int ret = 0;
- mutex_lock(&fs210x->lock);
+ guard(mutex)(&fs210x->lock);
- if (fs210x->is_suspended) {
- mutex_unlock(&fs210x->lock);
+ if (fs210x->is_suspended)
return 0;
- }
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1088,8 +1068,6 @@ static int fs210x_playback_event(struct snd_soc_dapm_widget *w,
break;
}
- mutex_unlock(&fs210x->lock);
-
return ret;
}
@@ -1220,11 +1198,9 @@ static int fs210x_probe(struct snd_soc_component *cmpnt)
if (ret)
return ret;
- mutex_lock(&fs210x->lock);
- ret = fs210x_init_chip(fs210x);
- mutex_unlock(&fs210x->lock);
+ guard(mutex)(&fs210x->lock);
- return ret;
+ return fs210x_init_chip(fs210x);
}
static void fs210x_remove(struct snd_soc_component *cmpnt)
@@ -1251,15 +1227,15 @@ static int fs210x_suspend(struct snd_soc_component *cmpnt)
regcache_cache_only(fs210x->regmap, true);
- mutex_lock(&fs210x->lock);
- fs210x->cur_scene = NULL;
- fs210x->is_inited = false;
- fs210x->is_playing = false;
- fs210x->is_suspended = true;
+ scoped_guard(mutex, &fs210x->lock) {
+ fs210x->cur_scene = NULL;
+ fs210x->is_inited = false;
+ fs210x->is_playing = false;
+ fs210x->is_suspended = true;
- gpiod_set_value_cansleep(fs210x->gpio_sdz, 1); /* Active */
- fsleep(30000); /* >= 30ms */
- mutex_unlock(&fs210x->lock);
+ gpiod_set_value_cansleep(fs210x->gpio_sdz, 1); /* Active */
+ fsleep(30000); /* >= 30ms */
+ }
cancel_delayed_work_sync(&fs210x->start_work);
cancel_delayed_work_sync(&fs210x->fault_check_work);
@@ -1288,14 +1264,11 @@ static int fs210x_resume(struct snd_soc_component *cmpnt)
return ret;
}
- mutex_lock(&fs210x->lock);
+ guard(mutex)(&fs210x->lock);
fs210x->is_suspended = false;
- ret = fs210x_init_chip(fs210x);
- mutex_unlock(&fs210x->lock);
-
- return ret;
+ return fs210x_init_chip(fs210x);
}
#else
#define fs210x_suspend NULL
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 680e341aa7f1..1c06fdbf0e71 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -437,7 +437,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
#ifdef CONFIG_SND_HDA_PATCH_LOADER
if (loadable_patch[hda_pvt->dev_index] && *loadable_patch[hda_pvt->dev_index]) {
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
dev_info(&hdev->dev, "Applying patch firmware '%s'\n",
loadable_patch[hda_pvt->dev_index]);
@@ -451,7 +451,6 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
dev_err(&hdev->dev, "%s: failed to load hda patch %d\n", __func__, ret);
goto error_no_pm;
}
- release_firmware(fw);
}
}
#endif
@@ -642,10 +641,8 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev)
&hdac_hda_codec, hdac_hda_dais,
ARRAY_SIZE(hdac_hda_dais));
- if (ret < 0) {
+ if (ret < 0)
dev_err(&hdev->dev, "%s: failed to register HDA codec %d\n", __func__, ret);
- return ret;
- }
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 3220f9226e0b..d9e6fa6d3e99 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -10,6 +10,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
+#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/module.h>
@@ -537,10 +538,11 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
continue;
list_for_each_entry(port, &pcm->port_list, head) {
- mutex_lock(&pcm->lock);
- ret = hdac_hdmi_query_port_connlist(hdev,
- port->pin, port);
- mutex_unlock(&pcm->lock);
+ scoped_guard(mutex, &pcm->lock) {
+ ret = hdac_hdmi_query_port_connlist(hdev,
+ port->pin,
+ port);
+ }
if (ret < 0)
continue;
@@ -640,11 +642,11 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
if (pcm) {
- mutex_lock(&pcm->lock);
- pcm->chmap_set = false;
- memset(pcm->chmap, 0, sizeof(pcm->chmap));
- pcm->channels = 0;
- mutex_unlock(&pcm->lock);
+ scoped_guard(mutex, &pcm->lock) {
+ pcm->chmap_set = false;
+ memset(pcm->chmap, 0, sizeof(pcm->chmap));
+ pcm->channels = 0;
+ }
}
if (dai_map->port)
@@ -922,7 +924,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
if (port == NULL)
return -EINVAL;
- mutex_lock(&hdmi->pin_mutex);
+ guard(mutex)(&hdmi->pin_mutex);
list_for_each_entry(pcm, &hdmi->pcm_list, head) {
if (list_empty(&pcm->port_list))
continue;
@@ -945,12 +947,10 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
list_add_tail(&port->head, &pcm->port_list);
if (port->eld.monitor_present && port->eld.eld_valid) {
hdac_hdmi_jack_report_sync(pcm, port, true);
- mutex_unlock(&hdmi->pin_mutex);
return ret;
}
}
}
- mutex_unlock(&hdmi->pin_mutex);
return ret;
}
@@ -1274,67 +1274,65 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
* In case of non MST pin, get_eld info API expectes port
* to be -1.
*/
- mutex_lock(&hdmi->pin_mutex);
- port->eld.monitor_present = false;
+ scoped_guard(mutex, &hdmi->pin_mutex) {
+ port->eld.monitor_present = false;
- if (pin->mst_capable)
- port_id = port->id;
+ if (pin->mst_capable)
+ port_id = port->id;
- size = snd_hdac_acomp_get_eld(hdev, pin->nid, port_id,
- &port->eld.monitor_present,
- port->eld.eld_buffer,
- ELD_MAX_SIZE);
+ size = snd_hdac_acomp_get_eld(hdev, pin->nid, port_id,
+ &port->eld.monitor_present,
+ port->eld.eld_buffer,
+ ELD_MAX_SIZE);
- if (size > 0) {
- size = min(size, ELD_MAX_SIZE);
- if (hdac_hdmi_parse_eld(hdev, port) < 0)
- size = -EINVAL;
- }
+ if (size > 0) {
+ size = min(size, ELD_MAX_SIZE);
+ if (hdac_hdmi_parse_eld(hdev, port) < 0)
+ size = -EINVAL;
+ }
- eld_valid = port->eld.eld_valid;
+ eld_valid = port->eld.eld_valid;
- if (size > 0) {
- port->eld.eld_valid = true;
- port->eld.eld_size = size;
- } else {
- port->eld.eld_valid = false;
- port->eld.eld_size = 0;
- }
+ if (size > 0) {
+ port->eld.eld_valid = true;
+ port->eld.eld_size = size;
+ } else {
+ port->eld.eld_valid = false;
+ port->eld.eld_size = 0;
+ }
- eld_changed = (eld_valid != port->eld.eld_valid);
+ eld_changed = (eld_valid != port->eld.eld_valid);
- pcm = hdac_hdmi_get_pcm(hdev, port);
+ pcm = hdac_hdmi_get_pcm(hdev, port);
- if (!port->eld.monitor_present || !port->eld.eld_valid) {
+ if (!port->eld.monitor_present || !port->eld.eld_valid) {
- dev_dbg(&hdev->dev, "%s: disconnect for pin:port %d:%d\n",
- __func__, pin->nid, port->id);
-
- /*
- * PCMs are not registered during device probe, so don't
- * report jack here. It will be done in usermode mux
- * control select.
- */
- if (pcm) {
- hdac_hdmi_jack_report(pcm, port, false);
- schedule_work(&port->dapm_work);
- }
+ dev_dbg(&hdev->dev, "%s: disconnect for pin:port %d:%d\n",
+ __func__, pin->nid, port->id);
- mutex_unlock(&hdmi->pin_mutex);
- return;
- }
+ /*
+ * PCMs are not registered during device probe, so don't
+ * report jack here. It will be done in usermode mux
+ * control select.
+ */
+ if (pcm) {
+ hdac_hdmi_jack_report(pcm, port, false);
+ schedule_work(&port->dapm_work);
+ }
- if (port->eld.monitor_present && port->eld.eld_valid) {
- if (pcm) {
- hdac_hdmi_jack_report(pcm, port, true);
- schedule_work(&port->dapm_work);
+ return;
}
- print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1,
- port->eld.eld_buffer, port->eld.eld_size, false);
+ if (port->eld.monitor_present && port->eld.eld_valid) {
+ if (pcm) {
+ hdac_hdmi_jack_report(pcm, port, true);
+ schedule_work(&port->dapm_work);
+ }
+ print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1,
+ port->eld.eld_buffer, port->eld.eld_size, false);
+ }
}
- mutex_unlock(&hdmi->pin_mutex);
if (eld_changed && pcm)
snd_ctl_notify(hdmi->card,
@@ -1795,13 +1793,12 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdev, int pcm_idx,
if (list_empty(&pcm->port_list))
return;
- mutex_lock(&pcm->lock);
+ guard(mutex)(&pcm->lock);
pcm->chmap_set = true;
memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap));
list_for_each_entry(port, &pcm->port_list, head)
if (prepared)
hdac_hdmi_setup_audio_infoframe(hdev, pcm, port);
- mutex_unlock(&pcm->lock);
}
static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdev, int pcm_idx)
@@ -1866,8 +1863,10 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
snd_hdac_ext_bus_link_get(hdev->bus, hlink);
hdmi_priv = devm_kzalloc(&hdev->dev, sizeof(*hdmi_priv), GFP_KERNEL);
- if (hdmi_priv == NULL)
+ if (hdmi_priv == NULL) {
+ snd_hdac_ext_bus_link_put(hdev->bus, hlink);
return -ENOMEM;
+ }
snd_hdac_register_chmap_ops(hdev, &hdmi_priv->chmap);
hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap;
@@ -1876,8 +1875,10 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
hdmi_priv->hdev = hdev;
- if (!hdac_id)
+ if (!hdac_id) {
+ snd_hdac_ext_bus_link_put(hdev->bus, hlink);
return -ENODEV;
+ }
if (hdac_id->driver_data)
hdmi_priv->drv_data =
@@ -1902,6 +1903,8 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
if (ret < 0) {
dev_err(&hdev->dev,
"Failed in parse and map nid with err: %d\n", ret);
+ snd_hdac_ext_bus_link_put(hdev->bus, hlink);
+ snd_hdac_display_power(hdev->bus, hdev->addr, false);
return ret;
}
snd_hdac_refresh_widgets(hdev);
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 13ae9e83bc21..bc2c22436ba6 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -4,6 +4,7 @@
* Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/
* Author: Jyri Sarha <jsarha@ti.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/string.h>
#include <sound/core.h>
@@ -452,31 +453,30 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
if (!((has_playback && tx) || (has_capture && !tx)))
return 0;
- mutex_lock(&hcp->lock);
+ guard(mutex)(&hcp->lock);
if (hcp->busy) {
dev_err(dai->dev, "Only one simultaneous stream supported!\n");
- mutex_unlock(&hcp->lock);
return -EINVAL;
}
if (hcp->hcd.ops->audio_startup) {
ret = hcp->hcd.ops->audio_startup(dai->dev->parent, hcp->hcd.data);
if (ret)
- goto err;
+ return ret;
}
if (tx && hcp->hcd.ops->get_eld) {
ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data,
hcp->eld, sizeof(hcp->eld));
if (ret)
- goto err;
+ return ret;
snd_parse_eld(dai->dev, &hcp->eld_parsed,
hcp->eld, sizeof(hcp->eld));
ret = snd_pcm_hw_constraint_eld(substream->runtime, hcp->eld);
if (ret)
- goto err;
+ return ret;
/* Select chmap supported */
hdmi_codec_eld_chmap(hcp);
@@ -484,8 +484,6 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
hcp->busy = true;
-err:
- mutex_unlock(&hcp->lock);
return ret;
}
@@ -503,9 +501,8 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream,
hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data);
- mutex_lock(&hcp->lock);
+ guard(mutex)(&hcp->lock);
hcp->busy = false;
- mutex_unlock(&hcp->lock);
}
static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai,
diff --git a/sound/soc/codecs/idt821034.c b/sound/soc/codecs/idt821034.c
index 084090ccef77..387f17b5f7b3 100644
--- a/sound/soc/codecs/idt821034.c
+++ b/sound/soc/codecs/idt821034.c
@@ -7,6 +7,7 @@
// Author: Herve Codina <herve.codina@bootlin.com>
#include <linux/bitrev.h>
+#include <linux/cleanup.h>
#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -413,12 +414,12 @@ static int idt821034_kctrl_gain_get(struct snd_kcontrol *kcontrol,
ch = IDT821034_ID_GET_CHAN(mc->reg);
- mutex_lock(&idt821034->mutex);
- if (IDT821034_ID_IS_OUT(mc->reg))
- val = idt821034->amps.ch[ch].amp_out.gain;
- else
- val = idt821034->amps.ch[ch].amp_in.gain;
- mutex_unlock(&idt821034->mutex);
+ scoped_guard(mutex, &idt821034->mutex) {
+ if (IDT821034_ID_IS_OUT(mc->reg))
+ val = idt821034->amps.ch[ch].amp_out.gain;
+ else
+ val = idt821034->amps.ch[ch].amp_in.gain;
+ }
ucontrol->value.integer.value[0] = val & mask;
if (invert)
@@ -456,7 +457,7 @@ static int idt821034_kctrl_gain_put(struct snd_kcontrol *kcontrol,
ch = IDT821034_ID_GET_CHAN(mc->reg);
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
if (IDT821034_ID_IS_OUT(mc->reg)) {
amp = &idt821034->amps.ch[ch].amp_out;
@@ -466,22 +467,18 @@ static int idt821034_kctrl_gain_put(struct snd_kcontrol *kcontrol,
gain_type = IDT821034_GAIN_TX;
}
- if (amp->gain == val) {
- ret = 0;
- goto end;
- }
+ if (amp->gain == val)
+ return 0;
if (!amp->is_muted) {
ret = idt821034_set_gain_channel(idt821034, ch, gain_type, val);
if (ret)
- goto end;
+ return ret;
}
amp->gain = val;
- ret = 1; /* The value changed */
-end:
- mutex_unlock(&idt821034->mutex);
- return ret;
+
+ return 1;
}
static int idt821034_kctrl_mute_get(struct snd_kcontrol *kcontrol,
@@ -495,11 +492,11 @@ static int idt821034_kctrl_mute_get(struct snd_kcontrol *kcontrol,
ch = IDT821034_ID_GET_CHAN(id);
- mutex_lock(&idt821034->mutex);
- is_muted = IDT821034_ID_IS_OUT(id) ?
- idt821034->amps.ch[ch].amp_out.is_muted :
- idt821034->amps.ch[ch].amp_in.is_muted;
- mutex_unlock(&idt821034->mutex);
+ scoped_guard(mutex, &idt821034->mutex) {
+ is_muted = IDT821034_ID_IS_OUT(id) ?
+ idt821034->amps.ch[ch].amp_out.is_muted :
+ idt821034->amps.ch[ch].amp_in.is_muted;
+ }
ucontrol->value.integer.value[0] = !is_muted;
@@ -521,7 +518,7 @@ static int idt821034_kctrl_mute_put(struct snd_kcontrol *kcontrol,
ch = IDT821034_ID_GET_CHAN(id);
is_mute = !ucontrol->value.integer.value[0];
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
if (IDT821034_ID_IS_OUT(id)) {
amp = &idt821034->amps.ch[ch].amp_out;
@@ -531,21 +528,17 @@ static int idt821034_kctrl_mute_put(struct snd_kcontrol *kcontrol,
gain_type = IDT821034_GAIN_TX;
}
- if (amp->is_muted == is_mute) {
- ret = 0;
- goto end;
- }
+ if (amp->is_muted == is_mute)
+ return 0;
ret = idt821034_set_gain_channel(idt821034, ch, gain_type,
is_mute ? 0 : amp->gain);
if (ret)
- goto end;
+ return ret;
amp->is_muted = is_mute;
- ret = 1; /* The value changed */
-end:
- mutex_unlock(&idt821034->mutex);
- return ret;
+
+ return 1;
}
static const DECLARE_TLV_DB_LINEAR(idt821034_gain_in, -300, 1300);
@@ -623,24 +616,20 @@ static int idt821034_power_event(struct snd_soc_dapm_widget *w,
struct idt821034 *idt821034 = snd_soc_component_get_drvdata(component);
unsigned int id = w->shift;
u8 power, mask;
- int ret;
u8 ch;
ch = IDT821034_ID_GET_CHAN(id);
mask = IDT821034_ID_IS_OUT(id) ? IDT821034_CONF_PWRUP_RX : IDT821034_CONF_PWRUP_TX;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
power = idt821034_get_channel_power(idt821034, ch);
if (SND_SOC_DAPM_EVENT_ON(event))
power |= mask;
else
power &= ~mask;
- ret = idt821034_set_channel_power(idt821034, ch, power);
-
- mutex_unlock(&idt821034->mutex);
- return ret;
+ return idt821034_set_channel_power(idt821034, ch, power);
}
static const struct snd_soc_dapm_widget idt821034_dapm_widgets[] = {
@@ -717,9 +706,9 @@ static int idt821034_dai_set_tdm_slot(struct snd_soc_dai *dai,
ch = 0;
while (mask && ch < IDT821034_NB_CHANNEL) {
if (mask & 0x1) {
- mutex_lock(&idt821034->mutex);
- ret = idt821034_set_channel_ts(idt821034, ch, IDT821034_CH_RX, slot);
- mutex_unlock(&idt821034->mutex);
+ scoped_guard(mutex, &idt821034->mutex)
+ ret = idt821034_set_channel_ts(idt821034, ch,
+ IDT821034_CH_RX, slot);
if (ret) {
dev_err(dai->dev, "ch%u set tx tdm slot failed (%d)\n",
ch, ret);
@@ -742,9 +731,9 @@ static int idt821034_dai_set_tdm_slot(struct snd_soc_dai *dai,
ch = 0;
while (mask && ch < IDT821034_NB_CHANNEL) {
if (mask & 0x1) {
- mutex_lock(&idt821034->mutex);
- ret = idt821034_set_channel_ts(idt821034, ch, IDT821034_CH_TX, slot);
- mutex_unlock(&idt821034->mutex);
+ scoped_guard(mutex, &idt821034->mutex)
+ ret = idt821034_set_channel_ts(idt821034, ch,
+ IDT821034_CH_TX, slot);
if (ret) {
dev_err(dai->dev, "ch%u set rx tdm slot failed (%d)\n",
ch, ret);
@@ -769,9 +758,8 @@ static int idt821034_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct idt821034 *idt821034 = snd_soc_component_get_drvdata(dai->component);
u8 conf;
- int ret;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
conf = idt821034_get_codec_conf(idt821034);
@@ -785,13 +773,10 @@ static int idt821034_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
default:
dev_err(dai->dev, "Unsupported DAI format 0x%x\n",
fmt & SND_SOC_DAIFMT_FORMAT_MASK);
- ret = -EINVAL;
- goto end;
+ return -EINVAL;
}
- ret = idt821034_set_codec_conf(idt821034, conf);
-end:
- mutex_unlock(&idt821034->mutex);
- return ret;
+
+ return idt821034_set_codec_conf(idt821034, conf);
}
static int idt821034_dai_hw_params(struct snd_pcm_substream *substream,
@@ -800,9 +785,8 @@ static int idt821034_dai_hw_params(struct snd_pcm_substream *substream,
{
struct idt821034 *idt821034 = snd_soc_component_get_drvdata(dai->component);
u8 conf;
- int ret;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
conf = idt821034_get_codec_conf(idt821034);
@@ -816,13 +800,10 @@ static int idt821034_dai_hw_params(struct snd_pcm_substream *substream,
default:
dev_err(dai->dev, "Unsupported PCM format 0x%x\n",
params_format(params));
- ret = -EINVAL;
- goto end;
+ return -EINVAL;
}
- ret = idt821034_set_codec_conf(idt821034, conf);
-end:
- mutex_unlock(&idt821034->mutex);
- return ret;
+
+ return idt821034_set_codec_conf(idt821034, conf);
}
static const unsigned int idt821034_sample_bits[] = {8};
@@ -897,11 +878,11 @@ static int idt821034_reset_audio(struct idt821034 *idt821034)
int ret;
u8 i;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
ret = idt821034_set_codec_conf(idt821034, 0);
if (ret)
- goto end;
+ return ret;
for (i = 0; i < IDT821034_NB_CHANNEL; i++) {
idt821034->amps.ch[i].amp_out.gain = IDT821034_GAIN_OUT_INIT_RAW;
@@ -909,24 +890,21 @@ static int idt821034_reset_audio(struct idt821034 *idt821034)
ret = idt821034_set_gain_channel(idt821034, i, IDT821034_GAIN_RX,
idt821034->amps.ch[i].amp_out.gain);
if (ret)
- goto end;
+ return ret;
idt821034->amps.ch[i].amp_in.gain = IDT821034_GAIN_IN_INIT_RAW;
idt821034->amps.ch[i].amp_in.is_muted = false;
ret = idt821034_set_gain_channel(idt821034, i, IDT821034_GAIN_TX,
idt821034->amps.ch[i].amp_in.gain);
if (ret)
- goto end;
+ return ret;
ret = idt821034_set_channel_power(idt821034, i, 0);
if (ret)
- goto end;
+ return ret;
}
- ret = 0;
-end:
- mutex_unlock(&idt821034->mutex);
- return ret;
+ return 0;
}
static int idt821034_component_probe(struct snd_soc_component *component)
@@ -965,7 +943,7 @@ static int idt821034_chip_gpio_set(struct gpio_chip *c, unsigned int offset,
u8 slic_raw;
int ret;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
slic_raw = idt821034_get_written_slic_raw(idt821034, ch);
if (val)
@@ -974,8 +952,6 @@ static int idt821034_chip_gpio_set(struct gpio_chip *c, unsigned int offset,
slic_raw &= ~mask;
ret = idt821034_write_slic_raw(idt821034, ch, slic_raw);
- mutex_unlock(&idt821034->mutex);
-
if (ret)
dev_err(&idt821034->spi->dev, "set gpio %d (%u, 0x%x) failed (%d)\n",
offset, ch, mask, ret);
@@ -991,9 +967,8 @@ static int idt821034_chip_gpio_get(struct gpio_chip *c, unsigned int offset)
u8 slic_raw;
int ret;
- mutex_lock(&idt821034->mutex);
- ret = idt821034_read_slic_raw(idt821034, ch, &slic_raw);
- mutex_unlock(&idt821034->mutex);
+ scoped_guard(mutex, &idt821034->mutex)
+ ret = idt821034_read_slic_raw(idt821034, ch, &slic_raw);
if (ret) {
dev_err(&idt821034->spi->dev, "get gpio %d (%u, 0x%x) failed (%d)\n",
offset, ch, mask, ret);
@@ -1015,9 +990,8 @@ static int idt821034_chip_get_direction(struct gpio_chip *c, unsigned int offset
struct idt821034 *idt821034 = gpiochip_get_data(c);
u8 slic_dir;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
slic_dir = idt821034_get_slic_conf(idt821034, ch);
- mutex_unlock(&idt821034->mutex);
return slic_dir & mask ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
}
@@ -1034,7 +1008,7 @@ static int idt821034_chip_direction_input(struct gpio_chip *c, unsigned int offs
if (mask & ~(IDT821034_SLIC_IO1_IN | IDT821034_SLIC_IO0_IN))
return -EPERM;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
slic_conf = idt821034_get_slic_conf(idt821034, ch) | mask;
@@ -1044,7 +1018,6 @@ static int idt821034_chip_direction_input(struct gpio_chip *c, unsigned int offs
offset, ch, mask, ret);
}
- mutex_unlock(&idt821034->mutex);
return ret;
}
@@ -1060,7 +1033,7 @@ static int idt821034_chip_direction_output(struct gpio_chip *c, unsigned int off
if (ret)
return ret;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
slic_conf = idt821034_get_slic_conf(idt821034, ch) & ~mask;
@@ -1070,7 +1043,6 @@ static int idt821034_chip_direction_output(struct gpio_chip *c, unsigned int off
offset, ch, mask, ret);
}
- mutex_unlock(&idt821034->mutex);
return ret;
}
@@ -1079,24 +1051,22 @@ static int idt821034_reset_gpio(struct idt821034 *idt821034)
int ret;
u8 i;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
/* IO0 and IO1 as input for all channels and output IO set to 0 */
for (i = 0; i < IDT821034_NB_CHANNEL; i++) {
ret = idt821034_set_slic_conf(idt821034, i,
IDT821034_SLIC_IO1_IN | IDT821034_SLIC_IO0_IN);
if (ret)
- goto end;
+ return ret;
ret = idt821034_write_slic_raw(idt821034, i, 0);
if (ret)
- goto end;
+ return ret;
}
- ret = 0;
-end:
- mutex_unlock(&idt821034->mutex);
- return ret;
+
+ return 0;
}
static int idt821034_gpio_init(struct idt821034 *idt821034)
diff --git a/sound/soc/codecs/lochnagar-sc.c b/sound/soc/codecs/lochnagar-sc.c
index a3d6318c9050..dadb4a6c287f 100644
--- a/sound/soc/codecs/lochnagar-sc.c
+++ b/sound/soc/codecs/lochnagar-sc.c
@@ -137,15 +137,23 @@ static int lochnagar_sc_set_usb_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBP_CFP);
}
+static const u64 lochnagar_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
static const struct snd_soc_dai_ops lochnagar_sc_line_ops = {
.startup = lochnagar_sc_line_startup,
.shutdown = lochnagar_sc_line_shutdown,
.set_fmt = lochnagar_sc_set_line_fmt,
+ .auto_selectable_formats = &lochnagar_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_dai_ops lochnagar_sc_usb_ops = {
.startup = lochnagar_sc_startup,
.set_fmt = lochnagar_sc_set_usb_fmt,
+ .auto_selectable_formats = &lochnagar_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver lochnagar_sc_dai[] = {
diff --git a/sound/soc/codecs/lpass-macro-common.c b/sound/soc/codecs/lpass-macro-common.c
index 6e3b8d0897dd..7e59616ed7bc 100644
--- a/sound/soc/codecs/lpass-macro-common.c
+++ b/sound/soc/codecs/lpass-macro-common.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2022, The Linux Foundation. All rights reserved.
+#include <linux/cleanup.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -71,21 +72,16 @@ EXPORT_SYMBOL_GPL(lpass_macro_pds_exit);
void lpass_macro_set_codec_version(enum lpass_codec_version version)
{
- mutex_lock(&lpass_codec_mutex);
+ guard(mutex)(&lpass_codec_mutex);
lpass_codec_version = version;
- mutex_unlock(&lpass_codec_mutex);
}
EXPORT_SYMBOL_GPL(lpass_macro_set_codec_version);
enum lpass_codec_version lpass_macro_get_codec_version(void)
{
- enum lpass_codec_version ver;
+ guard(mutex)(&lpass_codec_mutex);
- mutex_lock(&lpass_codec_mutex);
- ver = lpass_codec_version;
- mutex_unlock(&lpass_codec_mutex);
-
- return ver;
+ return lpass_codec_version;
}
EXPORT_SYMBOL_GPL(lpass_macro_get_codec_version);
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
index 6233aa9f5bc6..282a6aaa9986 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -6,6 +6,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <sound/soc.h>
@@ -2030,9 +2031,10 @@ static struct snd_soc_dai_driver rx_macro_dai[] = {
},
};
-static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
+static int rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
{
struct regmap *regmap = rx->regmap;
+ int ret;
if (mclk_enable) {
if (rx->rx_mclk_users == 0) {
@@ -2047,14 +2049,16 @@ static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
CDC_RX_FS_MCLK_CNT_EN_MASK,
CDC_RX_FS_MCLK_CNT_ENABLE);
regcache_mark_dirty(regmap);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret)
+ return ret;
}
rx->rx_mclk_users++;
} else {
if (rx->rx_mclk_users <= 0) {
dev_err(rx->dev, "%s: clock already disabled\n", __func__);
rx->rx_mclk_users = 0;
- return;
+ return 0;
}
rx->rx_mclk_users--;
if (rx->rx_mclk_users == 0) {
@@ -2068,6 +2072,8 @@ static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
CDC_RX_CLK_MCLK2_EN_MASK, 0x0);
}
}
+
+ return 0;
}
static int rx_macro_mclk_event(struct snd_soc_dapm_widget *w,
@@ -2079,11 +2085,9 @@ static int rx_macro_mclk_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- rx_macro_mclk_enable(rx, true);
- break;
+ return rx_macro_mclk_enable(rx, true);
case SND_SOC_DAPM_POST_PMD:
- rx_macro_mclk_enable(rx, false);
- break;
+ return rx_macro_mclk_enable(rx, false);
default:
dev_err(component->dev, "%s: invalid DAPM event %d\n", __func__, event);
ret = -EINVAL;
@@ -3671,14 +3675,16 @@ static int swclk_gate_enable(struct clk_hw *hw)
struct rx_macro *rx = to_rx_macro(hw);
int ret;
- ret = clk_prepare_enable(rx->mclk);
+ ret = pm_runtime_resume_and_get(rx->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = rx_macro_mclk_enable(rx, true);
if (ret) {
- dev_err(rx->dev, "unable to prepare mclk\n");
+ clk_disable_unprepare(rx->mclk);
return ret;
}
- rx_macro_mclk_enable(rx, true);
-
regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
CDC_RX_SWR_CLK_EN_MASK, 1);
@@ -3693,7 +3699,7 @@ static void swclk_gate_disable(struct clk_hw *hw)
CDC_RX_SWR_CLK_EN_MASK, 0);
rx_macro_mclk_enable(rx, false);
- clk_disable_unprepare(rx->mclk);
+ pm_runtime_put_autosuspend(rx->dev);
}
static int swclk_gate_is_enabled(struct clk_hw *hw)
@@ -3864,28 +3870,31 @@ static int rx_macro_probe(struct platform_device *pdev)
rx->dev = dev;
/* set MCLK and NPL rates */
- clk_set_rate(rx->mclk, MCLK_FREQ);
- clk_set_rate(rx->npl, MCLK_FREQ);
-
- ret = clk_prepare_enable(rx->macro);
+ ret = clk_set_rate(rx->mclk, MCLK_FREQ);
if (ret)
return ret;
- ret = clk_prepare_enable(rx->dcodec);
+ ret = clk_set_rate(rx->npl, MCLK_FREQ);
if (ret)
- goto err_dcodec;
+ return ret;
- ret = clk_prepare_enable(rx->mclk);
+ ret = devm_pm_clk_create(dev);
if (ret)
- goto err_mclk;
+ return ret;
- ret = clk_prepare_enable(rx->npl);
+ ret = of_pm_clk_add_clks(dev);
+ if (ret < 0)
+ return ret;
+
+ pm_runtime_set_autosuspend_delay(dev, 100);
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_enable(dev);
if (ret)
- goto err_npl;
+ return ret;
- ret = clk_prepare_enable(rx->fsgen);
+ ret = pm_runtime_resume_and_get(dev);
if (ret)
- goto err_fsgen;
+ return ret;
/* reset swr block */
regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
@@ -3902,46 +3911,25 @@ static int rx_macro_probe(struct platform_device *pdev)
rx_macro_dai,
ARRAY_SIZE(rx_macro_dai));
if (ret)
- goto err_clkout;
-
-
- pm_runtime_set_autosuspend_delay(dev, 3000);
- pm_runtime_use_autosuspend(dev);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ goto err_rpm_put;
ret = rx_macro_register_mclk_output(rx);
if (ret)
- goto err_clkout;
+ goto err_rpm_put;
+
+ ret = pm_runtime_put_autosuspend(dev);
+ if (ret < 0)
+ dev_warn(dev, "runtime PM put failed after probe: %d\n", ret);
return 0;
-err_clkout:
- clk_disable_unprepare(rx->fsgen);
-err_fsgen:
- clk_disable_unprepare(rx->npl);
-err_npl:
- clk_disable_unprepare(rx->mclk);
-err_mclk:
- clk_disable_unprepare(rx->dcodec);
-err_dcodec:
- clk_disable_unprepare(rx->macro);
+err_rpm_put:
+ if (pm_runtime_put_sync_suspend(dev) < 0)
+ dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n");
return ret;
}
-static void rx_macro_remove(struct platform_device *pdev)
-{
- struct rx_macro *rx = dev_get_drvdata(&pdev->dev);
-
- clk_disable_unprepare(rx->mclk);
- clk_disable_unprepare(rx->npl);
- clk_disable_unprepare(rx->fsgen);
- clk_disable_unprepare(rx->macro);
- clk_disable_unprepare(rx->dcodec);
-}
-
static const struct of_device_id rx_macro_dt_match[] = {
{
.compatible = "qcom,sc7280-lpass-rx-macro",
@@ -3969,13 +3957,17 @@ MODULE_DEVICE_TABLE(of, rx_macro_dt_match);
static int rx_macro_runtime_suspend(struct device *dev)
{
struct rx_macro *rx = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(rx->regmap, true);
- regcache_mark_dirty(rx->regmap);
- clk_disable_unprepare(rx->fsgen);
- clk_disable_unprepare(rx->npl);
- clk_disable_unprepare(rx->mclk);
+ ret = pm_clk_suspend(dev);
+ if (ret) {
+ regcache_cache_only(rx->regmap, false);
+ return ret;
+ }
+
+ regcache_mark_dirty(rx->regmap);
return 0;
}
@@ -3985,33 +3977,23 @@ static int rx_macro_runtime_resume(struct device *dev)
struct rx_macro *rx = dev_get_drvdata(dev);
int ret;
- ret = clk_prepare_enable(rx->mclk);
+ ret = pm_clk_resume(dev);
if (ret) {
- dev_err(dev, "unable to prepare mclk\n");
+ regcache_cache_only(rx->regmap, true);
+ regcache_mark_dirty(rx->regmap);
return ret;
}
- ret = clk_prepare_enable(rx->npl);
- if (ret) {
- dev_err(dev, "unable to prepare mclkx2\n");
- goto err_npl;
- }
-
- ret = clk_prepare_enable(rx->fsgen);
+ regcache_cache_only(rx->regmap, false);
+ ret = regcache_sync(rx->regmap);
if (ret) {
- dev_err(dev, "unable to prepare fsgen\n");
- goto err_fsgen;
+ regcache_cache_only(rx->regmap, true);
+ regcache_mark_dirty(rx->regmap);
+ pm_clk_suspend(dev);
+ return ret;
}
- regcache_cache_only(rx->regmap, false);
- regcache_sync(rx->regmap);
return 0;
-err_fsgen:
- clk_disable_unprepare(rx->npl);
-err_npl:
- clk_disable_unprepare(rx->mclk);
-
- return ret;
}
static const struct dev_pm_ops rx_macro_pm_ops = {
@@ -4026,7 +4008,6 @@ static struct platform_driver rx_macro_driver = {
.pm = pm_ptr(&rx_macro_pm_ops),
},
.probe = rx_macro_probe,
- .remove = rx_macro_remove,
};
module_platform_driver(rx_macro_driver);
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
index 0cbf50647ff5..a8e83eb60ba2 100644
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -6,6 +6,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <sound/soc.h>
@@ -614,6 +615,7 @@ static int tx_macro_mclk_enable(struct tx_macro *tx,
bool mclk_enable)
{
struct regmap *regmap = tx->regmap;
+ int ret;
if (mclk_enable) {
if (tx->tx_mclk_users == 0) {
@@ -626,7 +628,9 @@ static int tx_macro_mclk_enable(struct tx_macro *tx,
CDC_TX_FS_CNT_EN_MASK,
CDC_TX_FS_CNT_ENABLE);
regcache_mark_dirty(regmap);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret)
+ return ret;
}
tx->tx_mclk_users++;
} else {
@@ -739,11 +743,9 @@ static int tx_macro_mclk_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- tx_macro_mclk_enable(tx, true);
- break;
+ return tx_macro_mclk_enable(tx, true);
case SND_SOC_DAPM_POST_PMD:
- tx_macro_mclk_enable(tx, false);
- break;
+ return tx_macro_mclk_enable(tx, false);
default:
break;
}
@@ -2149,17 +2151,20 @@ static int swclk_gate_enable(struct clk_hw *hw)
struct regmap *regmap = tx->regmap;
int ret;
- ret = clk_prepare_enable(tx->mclk);
+ ret = pm_runtime_resume_and_get(tx->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = tx_macro_mclk_enable(tx, true);
if (ret) {
- dev_err(tx->dev, "failed to enable mclk\n");
+ pm_runtime_put_autosuspend(tx->dev);
return ret;
}
- tx_macro_mclk_enable(tx, true);
-
regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
CDC_TX_SWR_CLK_EN_MASK,
CDC_TX_SWR_CLK_ENABLE);
+
return 0;
}
@@ -2172,7 +2177,7 @@ static void swclk_gate_disable(struct clk_hw *hw)
CDC_TX_SWR_CLK_EN_MASK, 0x0);
tx_macro_mclk_enable(tx, false);
- clk_disable_unprepare(tx->mclk);
+ pm_runtime_put_autosuspend(tx->dev);
}
static int swclk_gate_is_enabled(struct clk_hw *hw)
@@ -2315,28 +2320,31 @@ static int tx_macro_probe(struct platform_device *pdev)
tx->active_decimator[TX_MACRO_AIF3_CAP] = -1;
/* set MCLK and NPL rates */
- clk_set_rate(tx->mclk, MCLK_FREQ);
- clk_set_rate(tx->npl, MCLK_FREQ);
-
- ret = clk_prepare_enable(tx->macro);
+ ret = clk_set_rate(tx->mclk, MCLK_FREQ);
if (ret)
goto err;
- ret = clk_prepare_enable(tx->dcodec);
+ ret = clk_set_rate(tx->npl, MCLK_FREQ);
if (ret)
- goto err_dcodec;
+ goto err;
- ret = clk_prepare_enable(tx->mclk);
+ ret = devm_pm_clk_create(dev);
if (ret)
- goto err_mclk;
+ goto err;
- ret = clk_prepare_enable(tx->npl);
- if (ret)
- goto err_npl;
+ ret = of_pm_clk_add_clks(dev);
+ if (ret < 0)
+ goto err;
- ret = clk_prepare_enable(tx->fsgen);
+ pm_runtime_set_autosuspend_delay(dev, 100);
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_enable(dev);
if (ret)
- goto err_fsgen;
+ goto err;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ goto err;
/* reset soundwire block */
@@ -2356,30 +2364,21 @@ static int tx_macro_probe(struct platform_device *pdev)
tx_macro_dai,
ARRAY_SIZE(tx_macro_dai));
if (ret)
- goto err_clkout;
-
- pm_runtime_set_autosuspend_delay(dev, 3000);
- pm_runtime_use_autosuspend(dev);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ goto err_rpm_put;
ret = tx_macro_register_mclk_output(tx);
if (ret)
- goto err_clkout;
+ goto err_rpm_put;
+
+ ret = pm_runtime_put_autosuspend(dev);
+ if (ret < 0)
+ dev_warn(dev, "runtime PM put failed after probe: %d\n", ret);
return 0;
-err_clkout:
- clk_disable_unprepare(tx->fsgen);
-err_fsgen:
- clk_disable_unprepare(tx->npl);
-err_npl:
- clk_disable_unprepare(tx->mclk);
-err_mclk:
- clk_disable_unprepare(tx->dcodec);
-err_dcodec:
- clk_disable_unprepare(tx->macro);
+err_rpm_put:
+ if (pm_runtime_put_sync_suspend(dev) < 0)
+ dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n");
err:
lpass_macro_pds_exit(tx->pds);
@@ -2390,25 +2389,23 @@ static void tx_macro_remove(struct platform_device *pdev)
{
struct tx_macro *tx = dev_get_drvdata(&pdev->dev);
- clk_disable_unprepare(tx->macro);
- clk_disable_unprepare(tx->dcodec);
- clk_disable_unprepare(tx->mclk);
- clk_disable_unprepare(tx->npl);
- clk_disable_unprepare(tx->fsgen);
-
lpass_macro_pds_exit(tx->pds);
}
static int tx_macro_runtime_suspend(struct device *dev)
{
struct tx_macro *tx = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(tx->regmap, true);
- regcache_mark_dirty(tx->regmap);
- clk_disable_unprepare(tx->fsgen);
- clk_disable_unprepare(tx->npl);
- clk_disable_unprepare(tx->mclk);
+ ret = pm_clk_suspend(dev);
+ if (ret) {
+ regcache_cache_only(tx->regmap, false);
+ return ret;
+ }
+
+ regcache_mark_dirty(tx->regmap);
return 0;
}
@@ -2418,34 +2415,23 @@ static int tx_macro_runtime_resume(struct device *dev)
struct tx_macro *tx = dev_get_drvdata(dev);
int ret;
- ret = clk_prepare_enable(tx->mclk);
+ ret = pm_clk_resume(dev);
if (ret) {
- dev_err(dev, "unable to prepare mclk\n");
+ regcache_cache_only(tx->regmap, true);
+ regcache_mark_dirty(tx->regmap);
return ret;
}
- ret = clk_prepare_enable(tx->npl);
- if (ret) {
- dev_err(dev, "unable to prepare npl\n");
- goto err_npl;
- }
-
- ret = clk_prepare_enable(tx->fsgen);
+ regcache_cache_only(tx->regmap, false);
+ ret = regcache_sync(tx->regmap);
if (ret) {
- dev_err(dev, "unable to prepare fsgen\n");
- goto err_fsgen;
+ regcache_cache_only(tx->regmap, true);
+ regcache_mark_dirty(tx->regmap);
+ pm_clk_suspend(dev);
+ return ret;
}
- regcache_cache_only(tx->regmap, false);
- regcache_sync(tx->regmap);
-
return 0;
-err_fsgen:
- clk_disable_unprepare(tx->npl);
-err_npl:
- clk_disable_unprepare(tx->mclk);
-
- return ret;
}
static const struct dev_pm_ops tx_macro_pm_ops = {
diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c
index 58a5798823d7..dbc5795b9273 100644
--- a/sound/soc/codecs/lpass-va-macro.c
+++ b/sound/soc/codecs/lpass-va-macro.c
@@ -10,6 +10,7 @@
#include <linux/of_clk.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -1351,34 +1352,43 @@ static int fsgen_gate_enable(struct clk_hw *hw)
{
struct va_macro *va = to_va_macro(hw);
struct regmap *regmap = va->regmap;
- int ret;
+ int ret, rpm_ret;
- if (va->has_swr_master) {
- ret = clk_prepare_enable(va->mclk);
- if (ret)
- return ret;
- }
+ ret = pm_runtime_resume_and_get(va->dev);
+ if (ret < 0)
+ return ret;
ret = va_macro_mclk_enable(va, true);
+ if (ret) {
+ rpm_ret = pm_runtime_put_autosuspend(va->dev);
+ if (rpm_ret < 0)
+ dev_warn(va->dev,
+ "runtime PM put failed in fsgen enable unwind: %d\n",
+ rpm_ret);
+ return ret;
+ }
if (va->has_swr_master)
regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
CDC_VA_SWR_CLK_EN_MASK, CDC_VA_SWR_CLK_ENABLE);
- return ret;
+ return 0;
}
static void fsgen_gate_disable(struct clk_hw *hw)
{
struct va_macro *va = to_va_macro(hw);
struct regmap *regmap = va->regmap;
+ int ret;
if (va->has_swr_master)
regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
CDC_VA_SWR_CLK_EN_MASK, 0x0);
va_macro_mclk_enable(va, false);
- if (va->has_swr_master)
- clk_disable_unprepare(va->mclk);
+
+ ret = pm_runtime_put_autosuspend(va->dev);
+ if (ret < 0)
+ dev_warn(va->dev, "runtime PM put failed in fsgen disable: %d\n", ret);
}
static int fsgen_gate_is_enabled(struct clk_hw *hw)
@@ -1539,6 +1549,7 @@ static int va_macro_probe(struct platform_device *pdev)
void __iomem *base;
u32 sample_rate = 0;
int ret;
+ int rpm_ret;
va = devm_kzalloc(dev, sizeof(*va), GFP_KERNEL);
if (!va)
@@ -1594,7 +1605,9 @@ static int va_macro_probe(struct platform_device *pdev)
va->has_npl_clk = data->has_npl_clk;
/* mclk rate */
- clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ);
+ ret = clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ);
+ if (ret)
+ goto err;
if (va->has_npl_clk) {
va->npl = devm_clk_get(dev, "npl");
@@ -1603,25 +1616,29 @@ static int va_macro_probe(struct platform_device *pdev)
goto err;
}
- clk_set_rate(va->npl, 2 * VA_MACRO_MCLK_FREQ);
+ ret = clk_set_rate(va->npl, 2 * VA_MACRO_MCLK_FREQ);
+ if (ret)
+ goto err;
}
- ret = clk_prepare_enable(va->macro);
+ ret = devm_pm_clk_create(dev);
if (ret)
goto err;
- ret = clk_prepare_enable(va->dcodec);
- if (ret)
- goto err_dcodec;
+ ret = of_pm_clk_add_clks(dev);
+ if (ret < 0)
+ goto err;
- ret = clk_prepare_enable(va->mclk);
+ pm_runtime_set_autosuspend_delay(dev, 100);
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_enable(dev);
if (ret)
- goto err_mclk;
+ goto err;
- if (va->has_npl_clk) {
- ret = clk_prepare_enable(va->npl);
- if (ret)
- goto err_npl;
+ rpm_ret = pm_runtime_resume_and_get(dev);
+ if (rpm_ret < 0) {
+ ret = rpm_ret;
+ goto err;
}
/**
@@ -1634,7 +1651,7 @@ static int va_macro_probe(struct platform_device *pdev)
/* read version from register */
ret = va_macro_set_lpass_codec_version(va);
if (ret)
- goto err_clkout;
+ goto err_rpm_put;
}
if (va->has_swr_master) {
@@ -1664,35 +1681,28 @@ static int va_macro_probe(struct platform_device *pdev)
va_macro_dais,
ARRAY_SIZE(va_macro_dais));
if (ret)
- goto err_clkout;
-
- pm_runtime_set_autosuspend_delay(dev, 3000);
- pm_runtime_use_autosuspend(dev);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ goto err_rpm_put;
ret = va_macro_register_fsgen_output(va);
if (ret)
- goto err_clkout;
+ goto err_rpm_put;
va->fsgen = devm_clk_hw_get_clk(dev, &va->hw, "fsgen");
if (IS_ERR(va->fsgen)) {
ret = PTR_ERR(va->fsgen);
- goto err_clkout;
+ goto err_rpm_put;
}
+ rpm_ret = pm_runtime_put_autosuspend(dev);
+ if (rpm_ret < 0)
+ dev_warn(dev, "runtime PM put failed after probe: %d\n", rpm_ret);
+
return 0;
-err_clkout:
- if (va->has_npl_clk)
- clk_disable_unprepare(va->npl);
-err_npl:
- clk_disable_unprepare(va->mclk);
-err_mclk:
- clk_disable_unprepare(va->dcodec);
-err_dcodec:
- clk_disable_unprepare(va->macro);
+err_rpm_put:
+ rpm_ret = pm_runtime_put_sync_suspend(dev);
+ if (rpm_ret < 0)
+ dev_warn(dev, "runtime PM sync suspend failed in probe unwind: %d\n", rpm_ret);
err:
lpass_macro_pds_exit(va->pds);
@@ -1703,27 +1713,23 @@ static void va_macro_remove(struct platform_device *pdev)
{
struct va_macro *va = dev_get_drvdata(&pdev->dev);
- if (va->has_npl_clk)
- clk_disable_unprepare(va->npl);
-
- clk_disable_unprepare(va->mclk);
- clk_disable_unprepare(va->dcodec);
- clk_disable_unprepare(va->macro);
-
lpass_macro_pds_exit(va->pds);
}
static int va_macro_runtime_suspend(struct device *dev)
{
struct va_macro *va = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(va->regmap, true);
- regcache_mark_dirty(va->regmap);
- if (va->has_npl_clk)
- clk_disable_unprepare(va->npl);
+ ret = pm_clk_suspend(dev);
+ if (ret) {
+ regcache_cache_only(va->regmap, false);
+ return ret;
+ }
- clk_disable_unprepare(va->mclk);
+ regcache_mark_dirty(va->regmap);
return 0;
}
@@ -1731,25 +1737,28 @@ static int va_macro_runtime_suspend(struct device *dev)
static int va_macro_runtime_resume(struct device *dev)
{
struct va_macro *va = dev_get_drvdata(dev);
- int ret;
+ int ret, sret;
- ret = clk_prepare_enable(va->mclk);
+ ret = pm_clk_resume(dev);
if (ret) {
- dev_err(va->dev, "unable to prepare mclk\n");
+ regcache_cache_only(va->regmap, true);
+ regcache_mark_dirty(va->regmap);
return ret;
}
- if (va->has_npl_clk) {
- ret = clk_prepare_enable(va->npl);
- if (ret) {
- clk_disable_unprepare(va->mclk);
- dev_err(va->dev, "unable to prepare npl\n");
- return ret;
- }
- }
-
regcache_cache_only(va->regmap, false);
- regcache_sync(va->regmap);
+
+ ret = regcache_sync(va->regmap);
+ if (ret) {
+ regcache_cache_only(va->regmap, true);
+ regcache_mark_dirty(va->regmap);
+ sret = pm_clk_suspend(dev);
+ if (sret)
+ dev_err(va->dev,
+ "failed to suspend clocks after regcache sync failure: %d\n",
+ sret);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index af521e0988db..cfd2ac0a6cda 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -12,6 +12,7 @@
#include <linux/clk-provider.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
#include <linux/of_platform.h>
#include <sound/tlv.h>
@@ -2529,15 +2530,13 @@ static const struct snd_soc_dapm_route wsa_audio_map[] = {
static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
{
struct regmap *regmap = wsa->regmap;
+ int ret;
if (enable) {
- int ret;
-
- ret = clk_prepare_enable(wsa->mclk);
- if (ret) {
- dev_err(wsa->dev, "failed to enable mclk\n");
+ ret = pm_runtime_resume_and_get(wsa->dev);
+ if (ret < 0)
return ret;
- }
+
wsa_macro_mclk_enable(wsa, true);
regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
@@ -2548,7 +2547,10 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
CDC_WSA_SWR_CLK_EN_MASK, 0);
wsa_macro_mclk_enable(wsa, false);
- clk_disable_unprepare(wsa->mclk);
+
+ ret = pm_runtime_put_autosuspend(wsa->dev);
+ if (ret < 0)
+ dev_warn(wsa->dev, "runtime PM put failed: %d\n", ret);
}
return 0;
@@ -2656,7 +2658,7 @@ static int wsa_macro_register_mclk_output(struct wsa_macro *wsa)
init.num_parents = 1;
wsa->hw.init = &init;
hw = &wsa->hw;
- ret = clk_hw_register(wsa->dev, hw);
+ ret = devm_clk_hw_register(wsa->dev, hw);
if (ret)
return ret;
@@ -2771,28 +2773,31 @@ static int wsa_macro_probe(struct platform_device *pdev)
wsa->dev = dev;
/* set MCLK and NPL rates */
- clk_set_rate(wsa->mclk, WSA_MACRO_MCLK_FREQ);
- clk_set_rate(wsa->npl, WSA_MACRO_MCLK_FREQ);
-
- ret = clk_prepare_enable(wsa->macro);
+ ret = clk_set_rate(wsa->mclk, WSA_MACRO_MCLK_FREQ);
if (ret)
- goto err;
+ return ret;
- ret = clk_prepare_enable(wsa->dcodec);
+ ret = clk_set_rate(wsa->npl, WSA_MACRO_MCLK_FREQ);
if (ret)
- goto err_dcodec;
+ return ret;
- ret = clk_prepare_enable(wsa->mclk);
+ ret = devm_pm_clk_create(dev);
if (ret)
- goto err_mclk;
+ return ret;
- ret = clk_prepare_enable(wsa->npl);
- if (ret)
- goto err_npl;
+ ret = of_pm_clk_add_clks(dev);
+ if (ret < 0)
+ return ret;
- ret = clk_prepare_enable(wsa->fsgen);
+ pm_runtime_set_autosuspend_delay(dev, 100);
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_enable(dev);
if (ret)
- goto err_fsgen;
+ return ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
/* reset swr ip */
regmap_update_bits(wsa->regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
@@ -2809,56 +2814,37 @@ static int wsa_macro_probe(struct platform_device *pdev)
wsa_macro_dai,
ARRAY_SIZE(wsa_macro_dai));
if (ret)
- goto err_clkout;
-
- pm_runtime_set_autosuspend_delay(dev, 3000);
- pm_runtime_use_autosuspend(dev);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ goto err_rpm_put;
ret = wsa_macro_register_mclk_output(wsa);
if (ret)
- goto err_clkout;
+ goto err_rpm_put;
- return 0;
+ ret = pm_runtime_put_autosuspend(dev);
+ if (ret < 0)
+ dev_warn(dev, "runtime PM put failed after probe: %d\n", ret);
-err_clkout:
- clk_disable_unprepare(wsa->fsgen);
-err_fsgen:
- clk_disable_unprepare(wsa->npl);
-err_npl:
- clk_disable_unprepare(wsa->mclk);
-err_mclk:
- clk_disable_unprepare(wsa->dcodec);
-err_dcodec:
- clk_disable_unprepare(wsa->macro);
-err:
+ return 0;
+err_rpm_put:
+ if (pm_runtime_put_sync_suspend(dev) < 0)
+ dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n");
return ret;
-
-}
-
-static void wsa_macro_remove(struct platform_device *pdev)
-{
- struct wsa_macro *wsa = dev_get_drvdata(&pdev->dev);
-
- clk_disable_unprepare(wsa->macro);
- clk_disable_unprepare(wsa->dcodec);
- clk_disable_unprepare(wsa->mclk);
- clk_disable_unprepare(wsa->npl);
- clk_disable_unprepare(wsa->fsgen);
}
static int wsa_macro_runtime_suspend(struct device *dev)
{
struct wsa_macro *wsa = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(wsa->regmap, true);
- regcache_mark_dirty(wsa->regmap);
- clk_disable_unprepare(wsa->fsgen);
- clk_disable_unprepare(wsa->npl);
- clk_disable_unprepare(wsa->mclk);
+ ret = pm_clk_suspend(dev);
+ if (ret) {
+ regcache_cache_only(wsa->regmap, false);
+ return ret;
+ }
+
+ regcache_mark_dirty(wsa->regmap);
return 0;
}
@@ -2866,36 +2852,29 @@ static int wsa_macro_runtime_suspend(struct device *dev)
static int wsa_macro_runtime_resume(struct device *dev)
{
struct wsa_macro *wsa = dev_get_drvdata(dev);
- int ret;
+ int ret, sret;
- ret = clk_prepare_enable(wsa->mclk);
+ ret = pm_clk_resume(dev);
if (ret) {
- dev_err(dev, "unable to prepare mclk\n");
+ regcache_cache_only(wsa->regmap, true);
+ regcache_mark_dirty(wsa->regmap);
return ret;
}
+ regcache_cache_only(wsa->regmap, false);
- ret = clk_prepare_enable(wsa->npl);
- if (ret) {
- dev_err(dev, "unable to prepare mclkx2\n");
- goto err_npl;
- }
-
- ret = clk_prepare_enable(wsa->fsgen);
+ ret = regcache_sync(wsa->regmap);
if (ret) {
- dev_err(dev, "unable to prepare fsgen\n");
- goto err_fsgen;
+ regcache_cache_only(wsa->regmap, true);
+ regcache_mark_dirty(wsa->regmap);
+ sret = pm_clk_suspend(dev);
+ if (sret)
+ dev_err(dev,
+ "failed to suspend clocks after regcache sync failure: %d\n",
+ sret);
+ return ret;
}
- regcache_cache_only(wsa->regmap, false);
- regcache_sync(wsa->regmap);
-
return 0;
-err_fsgen:
- clk_disable_unprepare(wsa->npl);
-err_npl:
- clk_disable_unprepare(wsa->mclk);
-
- return ret;
}
static const struct dev_pm_ops wsa_macro_pm_ops = {
@@ -2929,7 +2908,6 @@ static struct platform_driver wsa_macro_driver = {
.pm = pm_ptr(&wsa_macro_pm_ops),
},
.probe = wsa_macro_probe,
- .remove = wsa_macro_remove,
};
module_platform_driver(wsa_macro_driver);
diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c
index 98d72db599d8..58255844b4df 100644
--- a/sound/soc/codecs/madera.c
+++ b/sound/soc/codecs/madera.c
@@ -6,6 +6,7 @@
// Cirrus Logic International Semiconductor Ltd.
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/gcd.h>
#include <linux/module.h>
@@ -513,7 +514,7 @@ int madera_domain_clk_ev(struct snd_soc_dapm_widget *w,
* We can't rely on the DAPM mutex for locking because we need a lock
* that can safely be called in hw_params
*/
- mutex_lock(&priv->rate_lock);
+ guard(mutex)(&priv->rate_lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -532,8 +533,6 @@ int madera_domain_clk_ev(struct snd_soc_dapm_widget *w,
madera_debug_dump_domain_groups(priv);
- mutex_unlock(&priv->rate_lock);
-
return 0;
}
EXPORT_SYMBOL_GPL(madera_domain_clk_ev);
@@ -875,9 +874,8 @@ static int madera_adsp_rate_get(struct snd_kcontrol *kcontrol,
const int adsp_num = e->shift_l;
int item;
- mutex_lock(&priv->rate_lock);
- cached_rate = priv->adsp_rate_cache[adsp_num];
- mutex_unlock(&priv->rate_lock);
+ scoped_guard(mutex, &priv->rate_lock)
+ cached_rate = priv->adsp_rate_cache[adsp_num];
item = snd_soc_enum_val_to_item(e, cached_rate);
ucontrol->value.enumerated.item[0] = item;
@@ -893,7 +891,6 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
const int adsp_num = e->shift_l;
const unsigned int item = ucontrol->value.enumerated.item[0];
- int ret = 0;
if (item >= e->items)
return -EINVAL;
@@ -903,22 +900,20 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,
* maintain consistent behaviour that rate domains cannot be changed
* while in use since this is a hardware requirement
*/
- mutex_lock(&priv->rate_lock);
+ guard(mutex)(&priv->rate_lock);
if (!madera_can_change_grp_rate(priv, priv->adsp[adsp_num].cs_dsp.base)) {
dev_warn(priv->madera->dev,
"Cannot change '%s' while in use by active audio paths\n",
kcontrol->id.name);
- ret = -EBUSY;
+ return -EBUSY;
} else if (priv->adsp_rate_cache[adsp_num] != e->values[item]) {
/* Volatile register so defer until the codec is powered up */
priv->adsp_rate_cache[adsp_num] = e->values[item];
- ret = 1;
+ return 1;
}
- mutex_unlock(&priv->rate_lock);
-
- return ret;
+ return 0;
}
static const struct soc_enum madera_adsp_rate_enum[] = {
@@ -1061,15 +1056,13 @@ int madera_rate_put(struct snd_kcontrol *kcontrol,
* Prevent the domain powering up while we're checking whether it's
* safe to change rate domain
*/
- mutex_lock(&priv->rate_lock);
+ guard(mutex)(&priv->rate_lock);
val = snd_soc_component_read(component, e->reg);
val >>= e->shift_l;
val &= e->mask;
- if (snd_soc_enum_item_to_val(e, item) == val) {
- ret = 0;
- goto out;
- }
+ if (snd_soc_enum_item_to_val(e, item) == val)
+ return 0;
if (!madera_can_change_grp_rate(priv, e->reg)) {
dev_warn(priv->madera->dev,
@@ -1082,8 +1075,6 @@ int madera_rate_put(struct snd_kcontrol *kcontrol,
ret = snd_soc_put_enum_double(kcontrol, ucontrol);
madera_spin_sysclk(priv);
}
-out:
- mutex_unlock(&priv->rate_lock);
return ret;
}
@@ -3041,12 +3032,11 @@ static int madera_hw_params_rate(struct snd_pcm_substream *substream,
if ((cur & MADERA_AIF1_RATE_MASK) == (tar & MADERA_AIF1_RATE_MASK))
return 0;
- mutex_lock(&priv->rate_lock);
+ guard(mutex)(&priv->rate_lock);
if (!madera_can_change_grp_rate(priv, base + MADERA_AIF_RATE_CTRL)) {
madera_aif_warn(dai, "Cannot change rate while active\n");
- ret = -EBUSY;
- goto out;
+ return -EBUSY;
}
/* Guard the rate change with SYSCLK cycles */
@@ -3055,9 +3045,6 @@ static int madera_hw_params_rate(struct snd_pcm_substream *substream,
MADERA_AIF1_RATE_MASK, tar);
madera_spin_sysclk(priv);
-out:
- mutex_unlock(&priv->rate_lock);
-
return ret;
}
@@ -3345,6 +3332,16 @@ static int madera_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
return 0;
}
+static const u64 madera_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_NB_IF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
const struct snd_soc_dai_ops madera_dai_ops = {
.startup = &madera_startup,
.set_fmt = &madera_set_fmt,
@@ -3352,6 +3349,8 @@ const struct snd_soc_dai_ops madera_dai_ops = {
.hw_params = &madera_hw_params,
.set_sysclk = &madera_dai_set_sysclk,
.set_tristate = &madera_set_tristate,
+ .auto_selectable_formats = &madera_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
EXPORT_SYMBOL_GPL(madera_dai_ops);
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 57bd5a1c34c8..64dc442e9066 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2341,6 +2341,7 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
*
* @component: MAX98090 component
* @jack: jack to report detection events on
+ * @data: can be used if codec driver need extra data for configuring jack
*
* Enable microphone detection via IRQ on the MAX98090. If GPIOs are
* being used to bring out signals to the processor then only platform
@@ -2646,12 +2647,18 @@ static void max98090_i2c_remove(struct i2c_client *client)
static int max98090_runtime_resume(struct device *dev)
{
struct max98090_priv *max98090 = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(max98090->regmap, false);
max98090_reset(max98090);
- regcache_sync(max98090->regmap);
+ ret = regcache_sync(max98090->regmap);
+ if (ret < 0) {
+ regcache_cache_only(max98090->regmap, true);
+ regcache_mark_dirty(max98090->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 130b6694a634..d93436046849 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -5,6 +5,7 @@
* Copyright 2011 Maxim Integrated Products
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -1532,15 +1533,17 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
regsave = snd_soc_component_read(component, M98095_088_CFG_LEVEL);
snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, 0);
- mutex_lock(&max98095->lock);
- snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
- m98095_eq_band(component, channel, 0, coef_set->band1);
- m98095_eq_band(component, channel, 1, coef_set->band2);
- m98095_eq_band(component, channel, 2, coef_set->band3);
- m98095_eq_band(component, channel, 3, coef_set->band4);
- m98095_eq_band(component, channel, 4, coef_set->band5);
- snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, 0);
- mutex_unlock(&max98095->lock);
+ scoped_guard(mutex, &max98095->lock) {
+ snd_soc_component_update_bits(component, M98095_00F_HOST_CFG,
+ M98095_SEG, M98095_SEG);
+ m98095_eq_band(component, channel, 0, coef_set->band1);
+ m98095_eq_band(component, channel, 1, coef_set->band2);
+ m98095_eq_band(component, channel, 2, coef_set->band3);
+ m98095_eq_band(component, channel, 3, coef_set->band4);
+ m98095_eq_band(component, channel, 4, coef_set->band5);
+ snd_soc_component_update_bits(component, M98095_00F_HOST_CFG,
+ M98095_SEG, 0);
+ }
/* Restore the original on/off state */
snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, regsave);
@@ -1683,12 +1686,14 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
regsave = snd_soc_component_read(component, M98095_088_CFG_LEVEL);
snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, 0);
- mutex_lock(&max98095->lock);
- snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
- m98095_biquad_band(component, channel, 0, coef_set->band1);
- m98095_biquad_band(component, channel, 1, coef_set->band2);
- snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, 0);
- mutex_unlock(&max98095->lock);
+ scoped_guard(mutex, &max98095->lock) {
+ snd_soc_component_update_bits(component, M98095_00F_HOST_CFG,
+ M98095_SEG, M98095_SEG);
+ m98095_biquad_band(component, channel, 0, coef_set->band1);
+ m98095_biquad_band(component, channel, 1, coef_set->band2);
+ snd_soc_component_update_bits(component, M98095_00F_HOST_CFG,
+ M98095_SEG, 0);
+ }
/* Restore the original on/off state */
snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, regsave);
diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c
index 099dc5bf6195..0e32b7a94cb0 100644
--- a/sound/soc/codecs/max98363.c
+++ b/sound/soc/codecs/max98363.c
@@ -100,7 +100,12 @@ static int max98363_resume(struct device *dev)
return ret;
regcache_cache_only(max98363->regmap, false);
- regcache_sync(max98363->regmap);
+ ret = regcache_sync(max98363->regmap);
+ if (ret) {
+ regcache_cache_only(max98363->regmap, true);
+ regcache_mark_dirty(max98363->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c
index 8805bd01153c..cbd7ebffa6d6 100644
--- a/sound/soc/codecs/max98373-i2c.c
+++ b/sound/soc/codecs/max98373-i2c.c
@@ -488,10 +488,17 @@ static int max98373_suspend(struct device *dev)
static int max98373_resume(struct device *dev)
{
struct max98373_priv *max98373 = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(max98373->regmap, false);
max98373_reset(max98373, dev);
- regcache_sync(max98373->regmap);
+ ret = regcache_sync(max98373->regmap);
+ if (ret) {
+ regcache_cache_only(max98373->regmap, true);
+ regcache_mark_dirty(max98373->regmap);
+ return ret;
+ }
+
return 0;
}
diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c
index 8fe9c58e1a62..638ef343813b 100644
--- a/sound/soc/codecs/max98373-sdw.c
+++ b/sound/soc/codecs/max98373-sdw.c
@@ -277,7 +277,12 @@ static int max98373_resume(struct device *dev)
}
regcache_cache_only(max98373->regmap, false);
- regcache_sync(max98373->regmap);
+ ret = regcache_sync(max98373->regmap);
+ if (ret) {
+ regcache_cache_only(max98373->regmap, true);
+ regcache_mark_dirty(max98373->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/max98388.c b/sound/soc/codecs/max98388.c
index a4c57152d25f..d97dab41bf0f 100644
--- a/sound/soc/codecs/max98388.c
+++ b/sound/soc/codecs/max98388.c
@@ -863,10 +863,16 @@ static int max98388_suspend(struct device *dev)
static int max98388_resume(struct device *dev)
{
struct max98388_priv *max98388 = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(max98388->regmap, false);
max98388_reset(max98388, dev);
- regcache_sync(max98388->regmap);
+ ret = regcache_sync(max98388->regmap);
+ if (ret) {
+ regcache_cache_only(max98388->regmap, true);
+ regcache_mark_dirty(max98388->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
index 2bbedf84ee5d..2295fc057c71 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -788,7 +788,6 @@ static int max98390_dsm_init(struct snd_soc_component *component)
const char *vendor, *product;
struct max98390_priv *max98390 =
snd_soc_component_get_drvdata(component);
- const struct firmware *fw;
char *dsm_param;
vendor = dmi_get_system_info(DMI_SYS_VENDOR);
@@ -805,6 +804,8 @@ static int max98390_dsm_init(struct snd_soc_component *component)
snprintf(filename, sizeof(filename), "%s",
max98390->dsm_param_name);
}
+
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, filename, component->dev);
if (ret) {
ret = request_firmware(&fw, "dsm_param.bin", component->dev);
@@ -812,7 +813,7 @@ static int max98390_dsm_init(struct snd_soc_component *component)
ret = request_firmware(&fw, "dsmparam.bin",
component->dev);
if (ret)
- goto err;
+ return ret;
}
}
@@ -822,8 +823,7 @@ static int max98390_dsm_init(struct snd_soc_component *component)
if (fw->size < MAX98390_DSM_PARAM_MIN_SIZE) {
dev_err(component->dev,
"param fw is invalid.\n");
- ret = -EINVAL;
- goto err_alloc;
+ return -EINVAL;
}
dsm_param = (char *)fw->data;
param_start_addr = (dsm_param[0] & 0xff) | (dsm_param[1] & 0xff) << 8;
@@ -833,8 +833,7 @@ static int max98390_dsm_init(struct snd_soc_component *component)
fw->size < param_size + MAX98390_DSM_PAYLOAD_OFFSET) {
dev_err(component->dev,
"param fw is invalid.\n");
- ret = -EINVAL;
- goto err_alloc;
+ return -EINVAL;
}
regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x80);
dsm_param += MAX98390_DSM_PAYLOAD_OFFSET;
@@ -842,10 +841,7 @@ static int max98390_dsm_init(struct snd_soc_component *component)
dsm_param, param_size);
regmap_write(max98390->regmap, MAX98390_R23E1_DSP_GLOBAL_EN, 0x01);
-err_alloc:
- release_firmware(fw);
-err:
- return ret;
+ return 0;
}
static void max98390_init_regs(struct snd_soc_component *component)
@@ -952,11 +948,17 @@ static int max98390_suspend(struct device *dev)
static int max98390_resume(struct device *dev)
{
struct max98390_priv *max98390 = dev_get_drvdata(dev);
+ int ret;
dev_dbg(dev, "%s:Enter\n", __func__);
regcache_cache_only(max98390->regmap, false);
- regcache_sync(max98390->regmap);
+ ret = regcache_sync(max98390->regmap);
+ if (ret) {
+ regcache_cache_only(max98390->regmap, true);
+ regcache_mark_dirty(max98390->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c
index 9c1d7213410c..e5a2fe824c03 100644
--- a/sound/soc/codecs/max98396.c
+++ b/sound/soc/codecs/max98396.c
@@ -1600,19 +1600,37 @@ static int max98396_resume(struct device *dev)
if (max98396->pvdd) {
ret = regulator_enable(max98396->pvdd);
if (ret < 0)
- return ret;
+ goto err_core_supplies;
}
if (max98396->vbat) {
ret = regulator_enable(max98396->vbat);
if (ret < 0)
- return ret;
+ goto err_pvdd;
}
regcache_cache_only(max98396->regmap, false);
max98396_reset(max98396, dev);
- regcache_sync(max98396->regmap);
+ ret = regcache_sync(max98396->regmap);
+ if (ret < 0) {
+ regcache_cache_only(max98396->regmap, true);
+ regcache_mark_dirty(max98396->regmap);
+ goto err_vbat;
+ }
+
return 0;
+
+err_vbat:
+ if (max98396->vbat)
+ regulator_disable(max98396->vbat);
+err_pvdd:
+ if (max98396->pvdd)
+ regulator_disable(max98396->pvdd);
+err_core_supplies:
+ regulator_bulk_disable(MAX98396_NUM_CORE_SUPPLIES,
+ max98396->core_supplies);
+
+ return ret;
}
static const struct dev_pm_ops max98396_pm = {
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c
index 0d7ac37850bb..20e288e38669 100644
--- a/sound/soc/codecs/max9860.c
+++ b/sound/soc/codecs/max9860.c
@@ -48,7 +48,6 @@ static int max9860_dvddio_event(struct notifier_block *nb,
}
static const struct reg_default max9860_reg_defaults[] = {
- { MAX9860_PWRMAN, 0x00 },
{ MAX9860_INTEN, 0x00 },
{ MAX9860_SYSCLK, 0x00 },
{ MAX9860_AUDIOCLKHIGH, 0x00 },
@@ -62,6 +61,7 @@ static const struct reg_default max9860_reg_defaults[] = {
{ MAX9860_MICGAIN, 0x00 },
{ MAX9860_MICADC, 0x00 },
{ MAX9860_NOISEGATE, 0x00 },
+ { MAX9860_PWRMAN, 0x00 },
};
static bool max9860_readable(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index 65e6fdb30eec..524300d8fb0b 100644
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -742,11 +742,17 @@ static int max98927_suspend(struct device *dev)
static int max98927_resume(struct device *dev)
{
struct max98927_priv *max98927 = dev_get_drvdata(dev);
+ int ret;
regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET,
MAX98927_SOFT_RESET);
regcache_cache_only(max98927->regmap, false);
- regcache_sync(max98927->regmap);
+ ret = regcache_sync(max98927->regmap);
+ if (ret) {
+ regcache_cache_only(max98927->regmap, true);
+ regcache_mark_dirty(max98927->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index 8a14626d43ff..7209b47c2029 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -224,7 +224,6 @@ static const struct reg_default ml26124_reg[] = {
/* Analog Path Control Register */
{0x54, 0x00}, /* Speaker AMP Output Control */
{0x5a, 0x00}, /* Mic IF Control */
- {0xe8, 0x01}, /* Mic Select Control */
/* Audio Interface Control Register */
{0x60, 0x00}, /* SAI-Trans Control */
@@ -287,6 +286,9 @@ static const struct reg_default ml26124_reg[] = {
{0xd0, 0x01}, /* VIDEO AMP Gain Control */
{0xd2, 0x01}, /* VIDEO AMP Setup 1 */
{0xd4, 0x01}, /* VIDEO AMP Control2 */
+
+ /* Analog Path Control Register */
+ {0xe8, 0x01}, /* Mic Select Control */
};
/* Get sampling rate value of sampling rate setting register (0x0) */
diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c
index 9ca381812975..87f8a47cc293 100644
--- a/sound/soc/codecs/msm8916-wcd-analog.c
+++ b/sound/soc/codecs/msm8916-wcd-analog.c
@@ -217,9 +217,11 @@
#define CDC_A_RX_HPH_BIAS_LDO_OCP (0xf195)
#define CDC_A_RX_HPH_BIAS_CNP (0xf196)
#define CDC_A_RX_HPH_CNP_EN (0xf197)
+#define CDC_A_RX_HPH_L_TEST (0xf19A)
#define CDC_A_RX_HPH_L_PA_DAC_CTL (0xf19B)
#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_MASK BIT(1)
#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_RESET BIT(1)
+#define CDC_A_RX_HPH_R_TEST (0xf19C)
#define CDC_A_RX_HPH_R_PA_DAC_CTL (0xf19D)
#define RX_HPH_R_PA_DAC_CTL_DATA_RESET BIT(1)
#define RX_HPH_R_PA_DAC_CTL_DATA_RESET_MASK BIT(1)
@@ -232,6 +234,8 @@
#define RX_EAR_CTL_PA_SEL_MASK BIT(7)
#define RX_EAR_CTL_PA_SEL BIT(7)
+#define CDC_A_RX_EAR_STATUS (0xf1A1)
+
#define CDC_A_SPKR_DAC_CTL (0xf1B0)
#define SPKR_DAC_CTL_DAC_RESET_MASK BIT(4)
#define SPKR_DAC_CTL_DAC_RESET_NORMAL 0
@@ -250,6 +254,7 @@
SPKR_DRV_CAL_EN | SPKR_DRV_SETTLE_EN | \
SPKR_DRV_FW_EN | SPKR_DRV_BOOST_SET | \
SPKR_DRV_CMFB_SET | SPKR_DRV_GAIN_SET)
+#define CDC_A_SPKR_ANA_BIAS_SET (0xf1B3)
#define CDC_A_SPKR_OCP_CTL (0xf1B4)
#define CDC_A_SPKR_PWRSTG_CTL (0xf1B5)
#define SPKR_PWRSTG_CTL_DAC_EN_MASK BIT(0)
@@ -264,6 +269,7 @@
#define CDC_A_SPKR_DRV_DBG (0xf1B7)
#define CDC_A_CURRENT_LIMIT (0xf1C0)
+#define CDC_A_BYPASS_MODE (0xf1C2)
#define CDC_A_BOOST_EN_CTL (0xf1C3)
#define CDC_A_SLOPE_COMP_IP_ZERO (0xf1C4)
#define CDC_A_SEC_ACCESS (0xf1D0)
@@ -286,6 +292,11 @@ static const char * const supply_names[] = {
#define MBHC_MAX_BUTTONS (5)
+struct wcd_reg_seq {
+ const struct reg_default *seq;
+ int seq_size;
+};
+
struct pm8916_wcd_analog_priv {
u16 pmic_rev;
u16 codec_version;
@@ -696,6 +707,59 @@ static int pm8916_wcd_analog_enable_ear_pa(struct snd_soc_dapm_widget *w,
return 0;
}
+static int pm8916_wcd_analog_enable_hphl_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev);
+
+ /* This quirk is not required for revisions prior to CAJON_2_0 */
+ if (priv->codec_version < 4)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(7000, 7100);
+ snd_soc_component_update_bits(component, CDC_A_RX_HPH_L_TEST,
+ 0x04, 0x04);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* wait 20 ms after the digital codec has powered down */
+ msleep(20);
+ snd_soc_component_update_bits(component, CDC_A_RX_HPH_L_TEST,
+ 0x04, 0x00);
+ break;
+ }
+ return 0;
+}
+
+static int pm8916_wcd_analog_enable_hphr_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev);
+
+ /* This quirk is not required for revisions prior to CAJON_2_0 */
+ if (priv->codec_version < 4)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(7000, 7100);
+ snd_soc_component_update_bits(component, CDC_A_RX_HPH_R_TEST,
+ 0x04, 0x04);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ msleep(20);
+ snd_soc_component_update_bits(component, CDC_A_RX_HPH_R_TEST,
+ 0x04, 0x00);
+ break;
+ }
+ return 0;
+}
+
static const struct reg_default wcd_reg_defaults_2_0[] = {
{CDC_A_RX_COM_OCP_CTL, 0xD1},
{CDC_A_RX_COM_OCP_COUNT, 0xFF},
@@ -715,9 +779,69 @@ static const struct reg_default wcd_reg_defaults_2_0[] = {
{CDC_A_MASTER_BIAS_CTL, 0x30},
};
+static const struct wcd_reg_seq pm8916_data = {
+ .seq = wcd_reg_defaults_2_0,
+ .seq_size = ARRAY_SIZE(wcd_reg_defaults_2_0),
+};
+
+static const struct reg_default wcd_reg_defaults_pm8950[] = {
+ {CDC_A_RX_COM_OCP_CTL, 0xd1},
+ {CDC_A_RX_COM_OCP_COUNT, 0xff},
+ {CDC_D_SEC_ACCESS, 0xa5},
+ {CDC_D_PERPH_RESET_CTL3, 0x0f},
+ {CDC_A_TX_1_2_OPAMP_BIAS, 0x4c},
+ {CDC_A_NCP_FBCTRL, 0xa8},
+ {CDC_A_NCP_VCTRL, 0xa4},
+ {CDC_A_SPKR_DRV_CTL, 0x69},
+ {CDC_A_SPKR_DRV_DBG, 0x01},
+ {CDC_A_SEC_ACCESS, 0xa5},
+ {CDC_A_PERPH_RESET_CTL3, 0x0f},
+ {CDC_A_CURRENT_LIMIT, 0x82},
+ {CDC_A_SPKR_ANA_BIAS_SET, 0x41},
+ {CDC_A_SPKR_DAC_CTL, 0x03},
+ {CDC_A_SPKR_OCP_CTL, 0xe1},
+ {CDC_A_RX_HPH_BIAS_PA, 0xfa},
+ {CDC_A_MASTER_BIAS_CTL, 0x30},
+ {CDC_A_MICB_1_INT_RBIAS, 0x00},
+};
+
+static const struct wcd_reg_seq pm8950_data = {
+ .seq = wcd_reg_defaults_pm8950,
+ .seq_size = ARRAY_SIZE(wcd_reg_defaults_pm8950),
+};
+
+static const struct reg_default wcd_reg_defaults_pm8953[] = {
+ {CDC_A_RX_COM_OCP_CTL, 0xd1},
+ {CDC_A_RX_COM_OCP_COUNT, 0xff},
+ {CDC_D_SEC_ACCESS, 0xa5},
+ {CDC_D_PERPH_RESET_CTL3, 0x0f},
+ {CDC_A_TX_1_2_OPAMP_BIAS, 0x4c},
+ {CDC_A_NCP_FBCTRL, 0xa8},
+ {CDC_A_NCP_VCTRL, 0xa4},
+ {CDC_A_SPKR_DRV_CTL, 0x69},
+ {CDC_A_SPKR_DRV_DBG, 0x01},
+ {CDC_A_SEC_ACCESS, 0xa5},
+ {CDC_A_PERPH_RESET_CTL3, 0x0f},
+ {CDC_A_CURRENT_LIMIT, 0xa2},
+ {CDC_A_BYPASS_MODE, 0x18},
+ {CDC_A_SPKR_ANA_BIAS_SET, 0x41},
+ {CDC_A_SPKR_DAC_CTL, 0x03},
+ {CDC_A_SPKR_OCP_CTL, 0xe1},
+ {CDC_A_RX_HPH_BIAS_PA, 0xfa},
+ {CDC_A_RX_EAR_STATUS, 0x10},
+ {CDC_A_MASTER_BIAS_CTL, 0x30},
+ {CDC_A_MICB_1_INT_RBIAS, 0x00},
+};
+
+static const struct wcd_reg_seq pm8953_data = {
+ .seq = wcd_reg_defaults_pm8953,
+ .seq_size = ARRAY_SIZE(wcd_reg_defaults_pm8953),
+};
+
static int pm8916_wcd_analog_probe(struct snd_soc_component *component)
{
struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev);
+ const struct wcd_reg_seq *wcd_reg_init_data;
int err, reg;
err = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
@@ -738,9 +862,11 @@ static int pm8916_wcd_analog_probe(struct snd_soc_component *component)
snd_soc_component_write(component, CDC_D_PERPH_RESET_CTL4, 0x01);
snd_soc_component_write(component, CDC_A_PERPH_RESET_CTL4, 0x01);
- for (reg = 0; reg < ARRAY_SIZE(wcd_reg_defaults_2_0); reg++)
- snd_soc_component_write(component, wcd_reg_defaults_2_0[reg].reg,
- wcd_reg_defaults_2_0[reg].def);
+ wcd_reg_init_data = of_device_get_match_data(component->dev);
+
+ for (reg = 0; reg < wcd_reg_init_data->seq_size; reg++)
+ snd_soc_component_write(component, wcd_reg_init_data->seq[reg].reg,
+ wcd_reg_init_data->seq[reg].def);
priv->component = component;
@@ -883,11 +1009,15 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = {
SND_SOC_DAPM_MUX("EAR_S", SND_SOC_NOPM, 0, 0, &ear_mux),
SND_SOC_DAPM_SUPPLY("EAR CP", CDC_A_NCP_EN, 4, 0, NULL, 0),
- SND_SOC_DAPM_PGA("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
+ pm8916_wcd_analog_enable_hphl_pa,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, &hphl_mux),
SND_SOC_DAPM_MIXER("HPHL DAC", CDC_A_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL,
0),
- SND_SOC_DAPM_PGA("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
+ pm8916_wcd_analog_enable_hphr_pa,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, &hphr_mux),
SND_SOC_DAPM_MIXER("HPHR DAC", CDC_A_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL,
0),
@@ -1259,7 +1389,9 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
}
static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = {
- { .compatible = "qcom,pm8916-wcd-analog-codec", },
+ { .compatible = "qcom,pm8916-wcd-analog-codec", .data = &pm8916_data },
+ { .compatible = "qcom,pm8950-wcd-analog-codec", .data = &pm8950_data },
+ { .compatible = "qcom,pm8953-wcd-analog-codec", .data = &pm8953_data },
{ }
};
diff --git a/sound/soc/codecs/mt6357.c b/sound/soc/codecs/mt6357.c
index 674cf7df9df4..3b07087e1cab 100644
--- a/sound/soc/codecs/mt6357.c
+++ b/sound/soc/codecs/mt6357.c
@@ -1834,8 +1834,8 @@ static int mt6357_platform_driver_probe(struct platform_device *pdev)
}
static const struct platform_device_id mt6357_platform_ids[] = {
- {"mt6357-sound", 0},
- { /* sentinel */ },
+ { .name = "mt6357-sound" },
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, mt6357_platform_ids);
diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c
index ed34cc15b80e..e1190c644021 100644
--- a/sound/soc/codecs/mt6359-accdet.c
+++ b/sound/soc/codecs/mt6359-accdet.c
@@ -6,6 +6,7 @@
// Author: Argus Lin <argus.lin@mediatek.com>
//
+#include <linux/cleanup.h>
#include <linux/of.h>
#include <linux/input.h>
#include <linux/kthread.h>
@@ -398,14 +399,13 @@ static void mt6359_accdet_work(struct work_struct *work)
struct mt6359_accdet *priv =
container_of(work, struct mt6359_accdet, accdet_work);
- mutex_lock(&priv->res_lock);
+ guard(mutex)(&priv->res_lock);
priv->pre_accdet_status = priv->accdet_status;
check_jack_btn_type(priv);
if (priv->jack_plugged &&
priv->pre_accdet_status != priv->accdet_status)
mt6359_accdet_jack_report(priv);
- mutex_unlock(&priv->res_lock);
}
static void mt6359_accdet_jd_work(struct work_struct *work)
@@ -416,7 +416,7 @@ static void mt6359_accdet_jd_work(struct work_struct *work)
struct mt6359_accdet *priv =
container_of(work, struct mt6359_accdet, jd_work);
- mutex_lock(&priv->res_lock);
+ guard(mutex)(&priv->res_lock);
if (priv->jd_sts == M_PLUG_IN) {
priv->jack_plugged = true;
@@ -450,7 +450,6 @@ static void mt6359_accdet_jd_work(struct work_struct *work)
if (priv->caps & ACCDET_PMIC_EINT_IRQ)
recover_eint_setting(priv);
- mutex_unlock(&priv->res_lock);
}
static irqreturn_t mt6359_accdet_irq(int irq, void *data)
@@ -459,7 +458,7 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data)
unsigned int irq_val = 0, val = 0, value = 0;
int ret;
- mutex_lock(&priv->res_lock);
+ guard(mutex)(&priv->res_lock);
regmap_read(priv->regmap, ACCDET_IRQ_ADDR, &irq_val);
if (irq_val & ACCDET_IRQ_MASK_SFT) {
@@ -474,7 +473,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data)
1000);
if (ret) {
dev_err(priv->dev, "%s(), ret %d\n", __func__, ret);
- mutex_unlock(&priv->res_lock);
return IRQ_NONE;
}
regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
@@ -498,7 +496,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data)
if (ret) {
dev_err(priv->dev, "%s(), ret %d\n", __func__,
ret);
- mutex_unlock(&priv->res_lock);
return IRQ_NONE;
}
regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
@@ -521,7 +518,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data)
if (ret) {
dev_err(priv->dev, "%s(), ret %d\n", __func__,
ret);
- mutex_unlock(&priv->res_lock);
return IRQ_NONE;
}
regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
@@ -540,7 +536,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data)
queue_work(priv->jd_workqueue, &priv->jd_work);
}
- mutex_unlock(&priv->res_lock);
return IRQ_HANDLED;
}
diff --git a/sound/soc/codecs/ntpfw.c b/sound/soc/codecs/ntpfw.c
index 5ced2e966ab7..b6443e24ae8e 100644
--- a/sound/soc/codecs/ntpfw.c
+++ b/sound/soc/codecs/ntpfw.c
@@ -89,7 +89,7 @@ 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 struct firmware *fw __free(firmware) = NULL;
const u8 *data;
size_t leftover;
int ret;
@@ -101,10 +101,8 @@ int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic)
return ret;
}
- if (!ntpfw_verify(dev, fw->data, fw->size, magic)) {
- ret = -EINVAL;
- goto done;
- }
+ if (!ntpfw_verify(dev, fw->data, fw->size, magic))
+ return -EINVAL;
data = fw->data + sizeof(struct ntpfw_header);
leftover = fw->size - sizeof(struct ntpfw_header);
@@ -112,23 +110,18 @@ int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic)
while (leftover) {
chunk = (struct ntpfw_chunk *)data;
- if (!ntpfw_verify_chunk(dev, chunk, leftover)) {
- ret = -EINVAL;
- goto done;
- }
+ if (!ntpfw_verify_chunk(dev, chunk, leftover))
+ return -EINVAL;
ret = ntpfw_send_chunk(i2c, chunk);
if (ret)
- goto done;
+ return ret;
data += be16_to_cpu(chunk->length) + sizeof(*chunk);
leftover -= be16_to_cpu(chunk->length) + sizeof(*chunk);
}
-done:
- release_firmware(fw);
-
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(ntpfw_load);
diff --git a/sound/soc/codecs/ntpfw.h b/sound/soc/codecs/ntpfw.h
index 1cf10d5480ee..efbe9aa1eca5 100644
--- a/sound/soc/codecs/ntpfw.h
+++ b/sound/soc/codecs/ntpfw.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/**
+/*
* ntpfw.h - Firmware helper functions for Neofidelity codecs
*
* Copyright (c) 2024, SaluteDevices. All Rights Reserved.
@@ -13,10 +13,11 @@
/**
* 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.
+ * @i2c: Pointer to amplifier's I2C client.
+ * @name: Firmware file name.
+ * @magic: Magic number to validate firmware.
+ *
+ * Returns: 0 or error code upon error.
*/
int ntpfw_load(struct i2c_client *i2c, const char *name, const u32 magic);
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index cb923cecb47f..60fdbe5c4e05 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -199,10 +199,17 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream,
return pcm1681_set_deemph(component);
}
+static const u64 pcm1681_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
static const struct snd_soc_dai_ops pcm1681_dai_ops = {
.set_fmt = pcm1681_set_dai_fmt,
.hw_params = pcm1681_hw_params,
.mute_stream = pcm1681_mute,
+ .auto_selectable_formats = &pcm1681_selectable_formats,
+ .num_auto_selectable_formats = 1,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/pcm1754.c b/sound/soc/codecs/pcm1754.c
index b68a528000be..bb15da1c24aa 100644
--- a/sound/soc/codecs/pcm1754.c
+++ b/sound/soc/codecs/pcm1754.c
@@ -78,10 +78,16 @@ static int pcm1754_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
+static const u64 pcm1754_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J;
+
static const struct snd_soc_dai_ops pcm1754_dai_ops = {
.set_fmt = pcm1754_set_dai_fmt,
.hw_params = pcm1754_hw_params,
.mute_stream = pcm1754_mute_stream,
+ .auto_selectable_formats = &pcm1754_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_dai_driver pcm1754_dai = {
diff --git a/sound/soc/codecs/pcm1789.c b/sound/soc/codecs/pcm1789.c
index 3ab381e9a856..f06e353743aa 100644
--- a/sound/soc/codecs/pcm1789.c
+++ b/sound/soc/codecs/pcm1789.c
@@ -164,11 +164,18 @@ static int pcm1789_trigger(struct snd_pcm_substream *substream, int cmd,
return ret;
}
+static const u64 pcm1789_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
static const struct snd_soc_dai_ops pcm1789_dai_ops = {
.set_fmt = pcm1789_set_dai_fmt,
.hw_params = pcm1789_hw_params,
.mute_stream = pcm1789_mute,
.trigger = pcm1789_trigger,
+ .auto_selectable_formats = &pcm1789_selectable_formats,
+ .num_auto_selectable_formats = 1,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c
index f52ff66b6e64..cb70927872aa 100644
--- a/sound/soc/codecs/pcm179x.c
+++ b/sound/soc/codecs/pcm179x.c
@@ -142,10 +142,16 @@ static int pcm179x_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static const u64 pcm179x_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J;
+
static const struct snd_soc_dai_ops pcm179x_dai_ops = {
.set_fmt = pcm179x_set_dai_fmt,
.hw_params = pcm179x_hw_params,
.mute_stream = pcm179x_mute,
+ .auto_selectable_formats = &pcm179x_selectable_formats,
+ .num_auto_selectable_formats = 1,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c
index 0d1103fe4e04..461ec74e8752 100644
--- a/sound/soc/codecs/pcm186x.c
+++ b/sound/soc/codecs/pcm186x.c
@@ -473,11 +473,20 @@ static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
return 0;
}
+static const u64 pcm186x_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
static const struct snd_soc_dai_ops pcm186x_dai_ops = {
.set_sysclk = pcm186x_set_dai_sysclk,
.set_tdm_slot = pcm186x_set_tdm_slot,
.set_fmt = pcm186x_set_fmt,
.hw_params = pcm186x_hw_params,
+ .auto_selectable_formats = &pcm186x_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver pcm1863_dai = {
diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c
index 8974200652e7..f01c46583e89 100644
--- a/sound/soc/codecs/pcm3060.c
+++ b/sound/soc/codecs/pcm3060.c
@@ -164,10 +164,18 @@ val_ready:
return 0;
}
+static const u64 pcm3060_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
static const struct snd_soc_dai_ops pcm3060_dai_ops = {
.set_sysclk = pcm3060_set_sysclk,
.set_fmt = pcm3060_set_fmt,
.hw_params = pcm3060_hw_params,
+ .auto_selectable_formats = &pcm3060_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
#define PCM3060_DAI_RATES_ADC (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index fe3b5011fa16..f3e20919042b 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -6,7 +6,7 @@
* Copyright 2014 Linaro Ltd
*/
-
+#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/clk.h>
@@ -78,28 +78,10 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_POWER, 0x00 },
{ PCM512x_MUTE, 0x00 },
{ PCM512x_DSP, 0x00 },
- { PCM512x_PLL_REF, 0x00 },
- { PCM512x_DAC_REF, 0x00 },
- { PCM512x_DAC_ROUTING, 0x11 },
- { PCM512x_DSP_PROGRAM, 0x01 },
- { PCM512x_CLKDET, 0x00 },
- { PCM512x_AUTO_MUTE, 0x00 },
- { PCM512x_ERROR_DETECT, 0x00 },
- { PCM512x_DIGITAL_VOLUME_1, 0x00 },
- { PCM512x_DIGITAL_VOLUME_2, 0x30 },
- { PCM512x_DIGITAL_VOLUME_3, 0x30 },
- { PCM512x_DIGITAL_MUTE_1, 0x22 },
- { PCM512x_DIGITAL_MUTE_2, 0x00 },
- { PCM512x_DIGITAL_MUTE_3, 0x07 },
- { PCM512x_OUTPUT_AMPLITUDE, 0x00 },
- { PCM512x_ANALOG_GAIN_CTRL, 0x00 },
- { PCM512x_UNDERVOLTAGE_PROT, 0x00 },
- { PCM512x_ANALOG_MUTE_CTRL, 0x00 },
- { PCM512x_ANALOG_GAIN_BOOST, 0x00 },
- { PCM512x_VCOM_CTRL_1, 0x00 },
- { PCM512x_VCOM_CTRL_2, 0x01 },
{ PCM512x_BCLK_LRCLK_CFG, 0x00 },
{ PCM512x_MASTER_MODE, 0x7c },
+ { PCM512x_PLL_REF, 0x00 },
+ { PCM512x_DAC_REF, 0x00 },
{ PCM512x_GPIO_DACIN, 0x00 },
{ PCM512x_GPIO_PLLIN, 0x00 },
{ PCM512x_SYNCHRONIZE, 0x10 },
@@ -117,8 +99,26 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_FS_SPEED_MODE, 0x00 },
{ PCM512x_IDAC_1, 0x01 },
{ PCM512x_IDAC_2, 0x00 },
+ { PCM512x_ERROR_DETECT, 0x00 },
{ PCM512x_I2S_1, 0x02 },
{ PCM512x_I2S_2, 0x00 },
+ { PCM512x_DAC_ROUTING, 0x11 },
+ { PCM512x_DSP_PROGRAM, 0x01 },
+ { PCM512x_CLKDET, 0x00 },
+ { PCM512x_AUTO_MUTE, 0x00 },
+ { PCM512x_DIGITAL_VOLUME_1, 0x00 },
+ { PCM512x_DIGITAL_VOLUME_2, 0x30 },
+ { PCM512x_DIGITAL_VOLUME_3, 0x30 },
+ { PCM512x_DIGITAL_MUTE_1, 0x22 },
+ { PCM512x_DIGITAL_MUTE_2, 0x00 },
+ { PCM512x_DIGITAL_MUTE_3, 0x07 },
+ { PCM512x_OUTPUT_AMPLITUDE, 0x00 },
+ { PCM512x_ANALOG_GAIN_CTRL, 0x00 },
+ { PCM512x_UNDERVOLTAGE_PROT, 0x00 },
+ { PCM512x_ANALOG_MUTE_CTRL, 0x00 },
+ { PCM512x_ANALOG_GAIN_BOOST, 0x00 },
+ { PCM512x_VCOM_CTRL_1, 0x00 },
+ { PCM512x_VCOM_CTRL_2, 0x01 },
};
static bool pcm512x_readable(struct device *dev, unsigned int reg)
@@ -399,10 +399,9 @@ static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
- mutex_lock(&pcm512x->mutex);
+ guard(mutex)(&pcm512x->mutex);
ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4);
ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2);
- mutex_unlock(&pcm512x->mutex);
return 0;
}
@@ -414,7 +413,7 @@ static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol,
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
int ret, changed = 0;
- mutex_lock(&pcm512x->mutex);
+ guard(mutex)(&pcm512x->mutex);
if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) {
pcm512x->mute ^= 0x4;
@@ -430,13 +429,10 @@ static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol,
if (ret != 0) {
dev_err(component->dev,
"Failed to update digital mute: %d\n", ret);
- mutex_unlock(&pcm512x->mutex);
return ret;
}
}
- mutex_unlock(&pcm512x->mutex);
-
return changed;
}
@@ -1465,7 +1461,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction)
int ret;
unsigned int mute_det;
- mutex_lock(&pcm512x->mutex);
+ guard(mutex)(&pcm512x->mutex);
if (mute) {
pcm512x->mute |= 0x1;
@@ -1475,7 +1471,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction)
if (ret != 0) {
dev_err(component->dev,
"Failed to set digital mute: %d\n", ret);
- goto unlock;
+ return ret;
}
regmap_read_poll_timeout(pcm512x->regmap,
@@ -1488,7 +1484,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction)
if (ret != 0) {
dev_err(component->dev,
"Failed to update digital mute: %d\n", ret);
- goto unlock;
+ return ret;
}
regmap_read_poll_timeout(pcm512x->regmap,
@@ -1499,18 +1495,24 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction)
200, 10000);
}
-unlock:
- mutex_unlock(&pcm512x->mutex);
-
return ret;
}
+static const u64 pcm512x_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
static const struct snd_soc_dai_ops pcm512x_dai_ops = {
.startup = pcm512x_dai_startup,
.hw_params = pcm512x_hw_params,
.set_fmt = pcm512x_set_fmt,
.mute_stream = pcm512x_mute,
.set_bclk_ratio = pcm512x_set_bclk_ratio,
+ .auto_selectable_formats = &pcm512x_selectable_formats,
+ .num_auto_selectable_formats = 1,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c
index 4ac4448ac3c8..db85ae2f8aed 100644
--- a/sound/soc/codecs/pcm6240.c
+++ b/sound/soc/codecs/pcm6240.c
@@ -12,6 +12,7 @@
// Author: Shenghao Ding <shenghao-ding@ti.com>
//
+#include <linux/cleanup.h>
#include <linux/unaligned.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
@@ -605,7 +606,7 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol,
unsigned int reg = mc->reg;
unsigned int val;
- mutex_lock(&pcm_dev->codec_lock);
+ guard(mutex)(&pcm_dev->codec_lock);
if (pcm_dev->chip_id == PCM1690) {
ret = pcmdev_dev_read(pcm_dev, dev_no, PCM1690_REG_MODE_CTRL,
@@ -613,18 +614,18 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol,
if (ret) {
dev_err(pcm_dev->dev, "%s: read mode err=%d\n",
__func__, ret);
- goto out;
+ return ret;
}
val &= PCM1690_REG_MODE_CTRL_DAMS_MSK;
/* Set to wide-range mode, before using vol ctrl. */
if (!val && vol_ctrl_type == PCMDEV_PCM1690_VOL_CTRL) {
ucontrol->value.integer.value[0] = -25500;
- goto out;
+ return ret;
}
/* Set to fine mode, before using fine vol ctrl. */
if (val && vol_ctrl_type == PCMDEV_PCM1690_FINE_VOL_CTRL) {
ucontrol->value.integer.value[0] = -12750;
- goto out;
+ return ret;
}
}
@@ -632,15 +633,14 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol,
if (ret) {
dev_err(pcm_dev->dev, "%s: read err=%d\n",
__func__, ret);
- goto out;
+ return ret;
}
val = (val >> shift) & mask;
val = (val > max) ? max : val;
val = mc->invert ? max - val : val;
ucontrol->value.integer.value[0] = val;
-out:
- mutex_unlock(&pcm_dev->codec_lock);
+
return ret;
}
@@ -678,7 +678,7 @@ static int pcmdev_put_volsw(struct snd_kcontrol *kcontrol,
unsigned int val, val_mask;
unsigned int reg = mc->reg;
- mutex_lock(&pcm_dev->codec_lock);
+ guard(mutex)(&pcm_dev->codec_lock);
val = ucontrol->value.integer.value[0] & mask;
val = (val > max) ? max : val;
val = mc->invert ? max - val : val;
@@ -702,7 +702,7 @@ static int pcmdev_put_volsw(struct snd_kcontrol *kcontrol,
__func__, rc);
else
rc = 1;
- mutex_unlock(&pcm_dev->codec_lock);
+
return rc;
}
@@ -1577,10 +1577,10 @@ static int pcmdevice_comp_probe(struct snd_soc_component *comp)
{
struct pcmdevice_priv *pcm_dev = snd_soc_component_get_drvdata(comp);
struct i2c_adapter *adap = pcm_dev->client->adapter;
- const struct firmware *fw_entry = NULL;
+ const struct firmware *fw_entry __free(firmware) = NULL;
int ret, i, j;
- mutex_lock(&pcm_dev->codec_lock);
+ guard(mutex)(&pcm_dev->codec_lock);
pcm_dev->component = comp;
@@ -1588,7 +1588,7 @@ static int pcmdevice_comp_probe(struct snd_soc_component *comp)
for (j = 0; j < 2; j++) {
ret = pcmdev_gain_ctrl_add(pcm_dev, i, j);
if (ret < 0)
- goto out;
+ return ret;
}
}
@@ -1621,21 +1621,17 @@ static int pcmdevice_comp_probe(struct snd_soc_component *comp)
if (ret) {
dev_err(pcm_dev->dev, "%s: request %s err = %d\n", __func__,
pcm_dev->bin_name, ret);
- goto out;
+ return ret;
}
ret = pcmdev_regbin_ready(fw_entry, pcm_dev);
if (ret) {
dev_err(pcm_dev->dev, "%s: %s parse err = %d\n", __func__,
pcm_dev->bin_name, ret);
- goto out;
+ return ret;
}
- ret = pcmdev_profile_ctrl_add(pcm_dev);
-out:
- release_firmware(fw_entry);
- mutex_unlock(&pcm_dev->codec_lock);
- return ret;
+ return pcmdev_profile_ctrl_add(pcm_dev);
}
@@ -1645,9 +1641,8 @@ static void pcmdevice_comp_remove(struct snd_soc_component *codec)
if (!pcm_dev)
return;
- mutex_lock(&pcm_dev->codec_lock);
+ guard(mutex)(&pcm_dev->codec_lock);
pcmdevice_config_info_remove(pcm_dev);
- mutex_unlock(&pcm_dev->codec_lock);
}
static const struct snd_soc_dapm_widget pcmdevice_dapm_widgets[] = {
@@ -1890,9 +1885,9 @@ static int pcmdevice_mute(struct snd_soc_dai *dai, int mute, int stream)
else
block_type = PCMDEVICE_BIN_BLK_PRE_POWER_UP;
- mutex_lock(&pcm_dev->codec_lock);
+ guard(mutex)(&pcm_dev->codec_lock);
pcmdevice_select_cfg_blk(pcm_dev, pcm_dev->cur_conf, block_type);
- mutex_unlock(&pcm_dev->codec_lock);
+
return 0;
}
diff --git a/sound/soc/codecs/peb2466.c b/sound/soc/codecs/peb2466.c
index 2d71d204d8fa..f1ded68c2d75 100644
--- a/sound/soc/codecs/peb2466.c
+++ b/sound/soc/codecs/peb2466.c
@@ -6,6 +6,7 @@
//
// Author: Herve Codina <herve.codina@bootlin.com>
+#include <linux/cleanup.h>
#include <linux/unaligned.h>
#include <linux/clk.h>
#include <linux/firmware.h>
@@ -1537,17 +1538,14 @@ static int peb2466_fw_parse(struct snd_soc_component *component,
static int peb2466_load_coeffs(struct snd_soc_component *component, const char *fw_name)
{
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
int ret;
ret = request_firmware(&fw, fw_name, component->dev);
if (ret)
return ret;
- ret = peb2466_fw_parse(component, fw->data, fw->size);
- release_firmware(fw);
-
- return ret;
+ return peb2466_fw_parse(component, fw->data, fw->size);
}
static int peb2466_component_probe(struct snd_soc_component *component)
@@ -1704,13 +1702,11 @@ static int peb2466_chip_gpio_update_bits(struct peb2466 *peb2466, unsigned int x
* So, a specific cache value is used.
*/
- mutex_lock(&peb2466->gpio.lock);
+ guard(mutex)(&peb2466->gpio.lock);
cache = peb2466_chip_gpio_get_cache(peb2466, xr_reg);
- if (!cache) {
- ret = -EINVAL;
- goto end;
- }
+ if (!cache)
+ return -EINVAL;
tmp = *cache;
tmp &= ~mask;
@@ -1718,14 +1714,11 @@ static int peb2466_chip_gpio_update_bits(struct peb2466 *peb2466, unsigned int x
ret = regmap_write(peb2466->regmap, xr_reg, tmp);
if (ret)
- goto end;
+ return ret;
*cache = tmp;
- ret = 0;
-end:
- mutex_unlock(&peb2466->gpio.lock);
- return ret;
+ return 0;
}
static int peb2466_chip_gpio_set(struct gpio_chip *c, unsigned int offset,
diff --git a/sound/soc/codecs/pm4125-sdw.c b/sound/soc/codecs/pm4125-sdw.c
index 1c612ae4a4b2..182ff396301a 100644
--- a/sound/soc/codecs/pm4125-sdw.c
+++ b/sound/soc/codecs/pm4125-sdw.c
@@ -126,8 +126,8 @@ static const struct reg_default pm4125_defaults[] = {
{ PM4125_ANA_HPHPA_FSM_CLK, 0x12 },
{ PM4125_ANA_HPHPA_L_GAIN, 0x00 },
{ PM4125_ANA_HPHPA_R_GAIN, 0x00 },
- { PM4125_SWR_HPHPA_HD2, 0x1B },
{ PM4125_ANA_HPHPA_SPARE_CTL, 0x02 },
+ { PM4125_SWR_HPHPA_HD2, 0x1B },
{ PM4125_ANA_SURGE_EN, 0x38 },
{ PM4125_ANA_COMBOPA_CTL, 0x35 },
{ PM4125_ANA_COMBOPA_CTL_4, 0x84 },
@@ -464,10 +464,16 @@ static int __maybe_unused pm4125_sdw_runtime_suspend(struct device *dev)
static int __maybe_unused pm4125_sdw_runtime_resume(struct device *dev)
{
struct pm4125_sdw_priv *priv = dev_get_drvdata(dev);
+ int ret;
if (priv->regmap) {
regcache_cache_only(priv->regmap, false);
- regcache_sync(priv->regmap);
+ ret = regcache_sync(priv->regmap);
+ if (ret) {
+ regcache_cache_only(priv->regmap, true);
+ regcache_mark_dirty(priv->regmap);
+ return ret;
+ }
}
return 0;
diff --git a/sound/soc/codecs/pm4125.c b/sound/soc/codecs/pm4125.c
index 29655175ea28..674a2fbc4eda 100644
--- a/sound/soc/codecs/pm4125.c
+++ b/sound/soc/codecs/pm4125.c
@@ -5,6 +5,7 @@
#include <linux/component.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -1295,7 +1296,7 @@ static const struct irq_domain_ops pm4125_domain_ops = {
static int pm4125_irq_init(struct pm4125_priv *pm4125, struct device *dev)
{
- pm4125->virq = irq_domain_add_linear(NULL, 1, &pm4125_domain_ops, NULL);
+ pm4125->virq = irq_domain_create_linear(NULL, 1, &pm4125_domain_ops, NULL);
if (!(pm4125->virq)) {
dev_err(dev, "%s: Failed to add IRQ domain\n", __func__);
return -EINVAL;
diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c
index 95405cea8143..caf75e5657ef 100644
--- a/sound/soc/codecs/rt1017-sdca-sdw.c
+++ b/sound/soc/codecs/rt1017-sdca-sdw.c
@@ -784,7 +784,12 @@ static int rt1017_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(rt1017->regmap, false);
- regcache_sync(rt1017->regmap);
+ ret = regcache_sync(rt1017->regmap);
+ if (ret) {
+ regcache_cache_only(rt1017->regmap, true);
+ regcache_mark_dirty(rt1017->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/rt1017-sdca-sdw.h b/sound/soc/codecs/rt1017-sdca-sdw.h
index 4932b5dbe3c0..1604e1cfd85e 100644
--- a/sound/soc/codecs/rt1017-sdca-sdw.h
+++ b/sound/soc/codecs/rt1017-sdca-sdw.h
@@ -165,19 +165,19 @@ static const struct reg_default rt1017_sdca_reg_defaults[] = {
{ 0xdb09, 0x0f },
{ 0xdb0a, 0xff },
{ 0xdb14, 0x00 },
-
- { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
- RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU,
RT1017_SDCA_CTL_FU_MUTE, 0x01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22,
RT1017_SDCA_CTL_BYPASS, 0), 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
- RT1017_SDCA_CTL_FS_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22,
RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
+ RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
+ RT1017_SDCA_CTL_FS_INDEX, 0), 0x09 },
};
#endif /* __RT1017_SDW_H__ */
diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
index ca318dbd946e..2ef47a82c984 100644
--- a/sound/soc/codecs/rt1316-sdw.c
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -59,13 +59,13 @@ static const struct reg_default rt1316_reg_defaults[] = {
{ 0xd101, 0x00 },
{ 0xd102, 0x30 },
{ 0xd103, 0x00 },
- { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_XU24, RT1316_SDCA_CTL_BYPASS, 0), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE23, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE22, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE24, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
};
static const struct reg_sequence rt1316_blind_write[] = {
@@ -756,7 +756,12 @@ static int rt1316_dev_resume(struct device *dev)
}
regcache_cache_only(rt1316->regmap, false);
- regcache_sync(rt1316->regmap);
+ ret = regcache_sync(rt1316->regmap);
+ if (ret) {
+ regcache_cache_only(rt1316->regmap, true);
+ regcache_mark_dirty(rt1316->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c
index c038ac0e3b76..efadb6b1b82d 100644
--- a/sound/soc/codecs/rt1318-sdw.c
+++ b/sound/soc/codecs/rt1318-sdw.c
@@ -235,10 +235,10 @@ static const struct reg_default rt1318_reg_defaults[] = {
{ 0xf805, 0x00 },
{ 0xf806, 0x07 },
{ 0xf807, 0xff },
- { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, RT1318_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
};
@@ -830,7 +830,12 @@ static int rt1318_dev_resume(struct device *dev)
return ret;
regcache_cache_only(rt1318->regmap, false);
- regcache_sync(rt1318->regmap);
+ ret = regcache_sync(rt1318->regmap);
+ if (ret) {
+ regcache_cache_only(rt1318->regmap, true);
+ regcache_mark_dirty(rt1318->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/rt1318.c b/sound/soc/codecs/rt1318.c
index d13fd0e14125..55607f1b9a1e 100644
--- a/sound/soc/codecs/rt1318.c
+++ b/sound/soc/codecs/rt1318.c
@@ -337,6 +337,8 @@ static const struct reg_default rt1318_reg[] = {
{ 0xdd08, 0x40 },
{ 0xdd12, 0x00 },
{ 0xdd35, 0x00 },
+ { 0xdd93, 0x00 },
+ { 0xdd94, 0x64 },
{ 0xddb5, 0x00 },
{ 0xddb6, 0x40 },
{ 0xddb7, 0x00 },
@@ -345,8 +347,6 @@ static const struct reg_default rt1318_reg[] = {
{ 0xddc6, 0x00 },
{ 0xddc7, 0x00 },
{ 0xddc8, 0x00 },
- { 0xdd93, 0x00 },
- { 0xdd94, 0x64 },
{ 0xdf00, 0x00 },
{ 0xdf5f, 0x00 },
{ 0xdf60, 0x00 },
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index 42acb6cef77a..90333779971d 100644
--- a/sound/soc/codecs/rt1320-sdw.c
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -410,6 +410,402 @@ static const struct reg_sequence rt1321_blind_write[] = {
{ 0x41001988, 0x03 },
};
+static const struct reg_sequence rt1321_va1_blind_write[] = {
+ { 0x0000c003, 0xf0 },
+ { 0x0000c01b, 0xfc },
+ { 0x0000c5c3, 0xf2 },
+ { 0x0000c5c2, 0x00 },
+ { 0x0000c5c1, 0x10 },
+ { 0x0000c5c0, 0x04 },
+ { 0x0000c5c7, 0x03 },
+ { 0x0000c5c6, 0x10 },
+ { 0x0000c526, 0x47 },
+ { 0x0000c5c4, 0x12 },
+ { 0x0000c5c5, 0x60 },
+ { 0x0000c520, 0x10 },
+ { 0x0000c521, 0x32 },
+ { 0x0000c5c7, 0x00 },
+ { 0x0000c5c8, 0x03 },
+ { 0x0000c5d3, 0x08 },
+ { 0x0000c5d2, 0x0a },
+ { 0x0000c5d1, 0x49 },
+ { 0x0000c5d0, 0x0f },
+ { 0x0000c580, 0x10 },
+ { 0x0000c581, 0x32 },
+ { 0x0000c582, 0x01 },
+ { 0x0000c682, 0x60 },
+ { 0x0000c019, 0x10 },
+ { 0x0000c5f0, 0x01 },
+ { 0x0000c5f7, 0x22 },
+ { 0x0000c5f6, 0x22 },
+ { 0x0000c057, 0x51 },
+ { 0x0000c054, 0x55 },
+ { 0x0000c053, 0x55 },
+ { 0x0000c052, 0x55 },
+ { 0x0000c051, 0x01 },
+ { 0x0000c050, 0x15 },
+ { 0x0000c060, 0x99 },
+ { 0x0000c030, 0x55 },
+ { 0x0000c061, 0x55 },
+ { 0x0000c063, 0x55 },
+ { 0x0000c065, 0xa5 },
+ { 0x0000c06b, 0x0a },
+ { 0x0000ca05, 0xd6 },
+ { 0x0000ca06, 0x11 },
+ { 0x0000ca07, 0x1e },
+ { 0x0000ca25, 0xd6 },
+ { 0x0000ca26, 0x11 },
+ { 0x0000ca27, 0x1e },
+ { 0x0000cd00, 0x05 },
+ { 0x0000cd81, 0x49 },
+ { 0x0000cd82, 0x49 },
+ { 0x0000c604, 0x40 },
+ { 0x0000c609, 0x40 },
+ { 0x0000c046, 0xf7 },
+ { 0x0000c045, 0xff },
+ { 0x0000c044, 0xff },
+ { 0x0000c043, 0xff },
+ { 0x0000c042, 0xff },
+ { 0x0000c041, 0xff },
+ { 0x0000c040, 0xff },
+ { 0x0000c049, 0xff },
+ { 0x0000c028, 0x3f },
+ { 0x0000c020, 0x3f },
+ { 0x0000c032, 0x13 },
+ { 0x0000c033, 0x01 },
+ { 0x0000cc10, 0x01 },
+ { 0x0000dc20, 0x03 },
+ { 0x0000de03, 0x05 },
+ { 0x0000dc00, 0x00 },
+ { 0x0000c700, 0xf0 },
+ { 0x0000c701, 0x13 },
+ { 0x0000c900, 0xc3 },
+ { 0x0000c570, 0x08 },
+ { 0x0000c086, 0x02 },
+ { 0x0000c085, 0x7f },
+ { 0x0000c084, 0x00 },
+ { 0x0000c081, 0xff },
+ { 0x0000f084, 0x0f },
+ { 0x0000f083, 0xff },
+ { 0x0000f082, 0xff },
+ { 0x0000f081, 0xff },
+ { 0x0000f080, 0xff },
+ { 0x20003003, 0x3f },
+ { 0x20005818, 0x81 },
+ { 0x20009018, 0x81 },
+ { 0x2000301c, 0x81 },
+ { 0x0000c003, 0xc0 },
+ { 0x0000c047, 0x80 },
+ { 0x0000d541, 0x80 },
+ { 0x0000d487, 0x0b },
+ { 0x0000d487, 0x3b },
+ { 0x0000d486, 0xc3 },
+ { 0x0000d470, 0x89 },
+ { 0x0000d471, 0x3a },
+ { 0x0000d472, 0x3d },
+ { 0x0000d474, 0x11 },
+ { 0x0000d475, 0x32 },
+ { 0x0000d476, 0x64 },
+ { 0x0000d477, 0x10 },
+ { 0x0000d478, 0xff },
+ { 0x0000d479, 0x20 },
+ { 0x0000d47a, 0x10 },
+ { 0x0000d73c, 0xb7 },
+ { 0x0000d73d, 0xd7 },
+ { 0x0000d73e, 0x00 },
+ { 0x0000d73f, 0x10 },
+ { 0x1000cd56, 0x00 },
+ { 0x3fc2dfc0, 0x03 },
+ { 0x3fc2dfc1, 0x00 },
+ { 0x3fc2dfc2, 0x00 },
+ { 0x3fc2dfc3, 0x00 },
+ { 0x3fc2dfc4, 0x01 },
+ { 0x3fc2dfc5, 0x00 },
+ { 0x3fc2dfc6, 0x00 },
+ { 0x3fc2dfc7, 0x00 },
+ { 0x3fc2df80, 0x00 },
+ { 0x3fc2df81, 0x00 },
+ { 0x3fc2df82, 0x00 },
+ { 0x3fc2df83, 0x00 },
+ { 0x0000d541, 0x40 },
+ { 0x0000d486, 0x43 },
+ { 0x1000db00, 0x04 },
+ { 0x1000db01, 0x00 },
+ { 0x1000db02, 0x10 },
+ { 0x1000db03, 0x00 },
+ { 0x1000db04, 0x00 },
+ { 0x1000db05, 0x45 },
+ { 0x1000db06, 0x0d },
+ { 0x1000db07, 0x01 },
+ { 0x1000db08, 0x00 },
+ { 0x1000db09, 0x00 },
+ { 0x1000db0a, 0xbf },
+ { 0x1000db0b, 0x0b },
+ { 0x1000db0c, 0x11 },
+ { 0x1000db0d, 0x00 },
+ { 0x1000db0e, 0x00 },
+ { 0x1000db0f, 0x00 },
+ { 0x1000db10, 0x2c },
+ { 0x1000db11, 0xfa },
+ { 0x1000db12, 0x00 },
+ { 0x1000db13, 0x00 },
+ { 0x1000db14, 0x09 },
+ { 0x0000d540, 0x21 },
+ { 0x0000c570, 0x08 },
+ { 0x0000d714, 0x17 },
+ { 0x0000c5c3, 0xf2 },
+ { 0x0000c5c8, 0x03 },
+ { 0x20009012, 0x00 },
+ { 0x0000dd08, 0x17 },
+ { 0x0000dd09, 0x0e },
+ { 0x0000dd0a, 0x17 },
+ { 0x0000dd0b, 0x0e },
+ { 0x0000c570, 0x08 },
+ { 0x0000d471, 0x3a },
+ { 0x0000db00, 0x00 },
+ { 0x0000db01, 0x00 },
+ { 0x0000db02, 0x73 },
+ { 0x0000db03, 0x00 },
+ { 0x0000db04, 0x00 },
+ { 0x0000db05, 0x00 },
+ { 0x0000db06, 0x00 },
+ { 0x0000db07, 0x00 },
+ { 0x0000db08, 0x7f },
+ { 0x0000db09, 0x00 },
+ { 0x0000db1a, 0x00 },
+ { 0x0000db1b, 0x00 },
+ { 0x0000db19, 0x00 },
+};
+
+static const struct reg_sequence rt1321_va2_blind_write[] = {
+ { 0x0000c003, 0xf0 },
+ { 0x0000c01b, 0xfc },
+ { 0x0000c5c3, 0xf2 },
+ { 0x0000c5c2, 0x00 },
+ { 0x0000c5c1, 0x10 },
+ { 0x0000c5c0, 0x04 },
+ { 0x0000c5c7, 0x03 },
+ { 0x0000c5c6, 0x10 },
+ { 0x0000c526, 0x47 },
+ { 0x0000c5c4, 0x12 },
+ { 0x0000c5c5, 0x60 },
+ { 0x0000c520, 0x10 },
+ { 0x0000c521, 0x32 },
+ { 0x0000c5c7, 0x00 },
+ { 0x0000c5c8, 0x03 },
+ { 0x0000c5d3, 0x08 },
+ { 0x0000c5d2, 0x0a },
+ { 0x0000c5d1, 0x49 },
+ { 0x0000c5d0, 0x0f },
+ { 0x0000c580, 0x10 },
+ { 0x0000c581, 0x32 },
+ { 0x0000c582, 0x01 },
+ { 0x0000c682, 0x60 },
+ { 0x0000c019, 0x10 },
+ { 0x0000c5f0, 0x01 },
+ { 0x0000c5f7, 0x22 },
+ { 0x0000c5f6, 0x22 },
+ { 0x0000c057, 0x51 },
+ { 0x0000c054, 0x55 },
+ { 0x0000c053, 0x55 },
+ { 0x0000c052, 0x55 },
+ { 0x0000c051, 0x01 },
+ { 0x0000c050, 0x15 },
+ { 0x0000c060, 0x99 },
+ { 0x0000c030, 0x55 },
+ { 0x0000c061, 0x55 },
+ { 0x0000c063, 0x55 },
+ { 0x0000c065, 0xa5 },
+ { 0x0000c06b, 0x0a },
+ { 0x0000ca05, 0xd6 },
+ { 0x0000ca06, 0x11 },
+ { 0x0000ca07, 0x1e },
+ { 0x0000ca25, 0xd6 },
+ { 0x0000ca26, 0x11 },
+ { 0x0000ca27, 0x1e },
+ { 0x0000cd00, 0x05 },
+ { 0x0000cd81, 0x49 },
+ { 0x0000cd82, 0x49 },
+ { 0x0000c604, 0x40 },
+ { 0x0000c609, 0x40 },
+ { 0x0000c046, 0xf7 },
+ { 0x0000c045, 0xff },
+ { 0x0000c044, 0xff },
+ { 0x0000c043, 0xff },
+ { 0x0000c042, 0xff },
+ { 0x0000c041, 0xff },
+ { 0x0000c040, 0xff },
+ { 0x0000c049, 0xff },
+ { 0x0000c028, 0x3f },
+ { 0x0000c020, 0x3f },
+ { 0x0000c032, 0x13 },
+ { 0x0000c033, 0x01 },
+ { 0x0000cc10, 0x01 },
+ { 0x0000dc20, 0x03 },
+ { 0x0000de03, 0x05 },
+ { 0x0000dc00, 0x00 },
+ { 0x0000c700, 0xf0 },
+ { 0x0000c701, 0x13 },
+ { 0x0000c900, 0xc3 },
+ { 0x0000c570, 0x08 },
+ { 0x0000c086, 0x02 },
+ { 0x0000c085, 0x7f },
+ { 0x0000c084, 0x00 },
+ { 0x0000c081, 0xff },
+ { 0x0000f084, 0x0f },
+ { 0x0000f083, 0xff },
+ { 0x0000f082, 0xff },
+ { 0x0000f081, 0xff },
+ { 0x0000f080, 0xff },
+ { 0x20003003, 0x3f },
+ { 0x20005818, 0x81 },
+ { 0x20009018, 0x81 },
+ { 0x2000301c, 0x81 },
+ { 0x0000c003, 0xc0 },
+ { 0x0000c047, 0x80 },
+ { 0x0000d541, 0x80 },
+ { 0x0000d487, 0x0b },
+ { 0x0000d487, 0x3b },
+ { 0x0000d486, 0xc3 },
+ { 0x0000d470, 0x89 },
+ { 0x0000d471, 0x3a },
+ { 0x0000d472, 0x3d },
+ { 0x0000d474, 0x11 },
+ { 0x0000d475, 0x32 },
+ { 0x0000d476, 0x64 },
+ { 0x0000d477, 0x10 },
+ { 0x0000d478, 0xff },
+ { 0x0000d479, 0x20 },
+ { 0x0000d47a, 0x10 },
+ { 0x10008000, 0x67 },
+ { 0x10008001, 0x80 },
+ { 0x10008002, 0x00 },
+ { 0x10008003, 0x00 },
+ { 0x1000cd56, 0x00 },
+ { 0x0000d486, 0x43 },
+ { 0x3fc2dfc3, 0x00 },
+ { 0x3fc2dfc2, 0x00 },
+ { 0x3fc2dfc1, 0x00 },
+ { 0x3fc2dfc0, 0x03 },
+ { 0x3fc2dfc7, 0x00 },
+ { 0x3fc2dfc6, 0x00 },
+ { 0x3fc2dfc5, 0x00 },
+ { 0x3fc2dfc4, 0x01 },
+ { 0x3fc2dfa3, 0x00 },
+ { 0x3fc2dfa2, 0x00 },
+ { 0x3fc2dfa1, 0x00 },
+ { 0x3fc2dfa0, 0x00 },
+ { 0x3fc2df80, 0x10 },
+ { 0x3fc2df81, 0x20 },
+ { 0x3fc2df82, 0x00 },
+ { 0x3fc2df83, 0x00 },
+ { 0x3fc2df84, 0x50 },
+ { 0x3fc2df85, 0x19 },
+ { 0x3fc2df86, 0x00 },
+ { 0x3fc2df87, 0x00 },
+ { 0x3fc2df88, 0x52 },
+ { 0x3fc2df89, 0x23 },
+ { 0x3fc2df8a, 0x00 },
+ { 0x3fc2df8b, 0x00 },
+ { 0x3fc2df8c, 0xe0 },
+ { 0x3fc2df8d, 0x2e },
+ { 0x3fc2df8e, 0x00 },
+ { 0x3fc2df8f, 0x00 },
+ { 0x3fc2df90, 0xe0 },
+ { 0x3fc2df91, 0x2e },
+ { 0x3fc2df92, 0x00 },
+ { 0x3fc2df93, 0x00 },
+ { 0x3fc2df94, 0x01 },
+ { 0x3fc2df95, 0x08 },
+ { 0x3fc2df96, 0x00 },
+ { 0x3fc2df97, 0x00 },
+ { 0x3fc2df40, 0x80 },
+ { 0x3fc2df41, 0xbb },
+ { 0x3fc2df42, 0x00 },
+ { 0x3fc2df43, 0x00 },
+ { 0x3fc2df44, 0xc0 },
+ { 0x3fc2df45, 0x99 },
+ { 0x3fc2df46, 0x01 },
+ { 0x3fc2df47, 0x00 },
+ { 0x3fc2df48, 0x00 },
+ { 0x3fc2df49, 0x00 },
+ { 0x3fc2df4a, 0x00 },
+ { 0x3fc2df4b, 0x00 },
+ { 0x3fc2df4c, 0x00 },
+ { 0x3fc2df4d, 0x00 },
+ { 0x3fc2df4e, 0x00 },
+ { 0x3fc2df4f, 0x00 },
+ { 0x3fc2df50, 0x01 },
+ { 0x3fc2df51, 0x00 },
+ { 0x3fc2df52, 0x00 },
+ { 0x3fc2df53, 0x00 },
+ { 0x3fc2df54, 0x01 },
+ { 0x3fc2df55, 0x00 },
+ { 0x3fc2df56, 0x00 },
+ { 0x3fc2df57, 0x00 },
+ { 0x3fc2df58, 0x00 },
+ { 0x3fc2df59, 0x00 },
+ { 0x3fc2df5a, 0x00 },
+ { 0x3fc2df5b, 0x00 },
+ { 0x3fc2df5c, 0x01 },
+ { 0x3fc2df5d, 0x00 },
+ { 0x3fc2df5e, 0x00 },
+ { 0x3fc2df5f, 0x00 },
+ { 0x3fc2df60, 0x00 },
+ { 0x3fc2df61, 0x00 },
+ { 0x3fc2df62, 0x00 },
+ { 0x3fc2df63, 0x00 },
+ { 0x3fc2df64, 0x00 },
+ { 0x3fc2df65, 0x00 },
+ { 0x3fc2df66, 0x00 },
+ { 0x3fc2df67, 0x10 },
+ { 0x3fc2df68, 0x01 },
+ { 0x3fc2df69, 0x00 },
+ { 0x3fc2df6a, 0x00 },
+ { 0x3fc2df6b, 0x00 },
+ { 0x3fc2df6c, 0x01 },
+ { 0x3fc2df6d, 0x00 },
+ { 0x3fc2df6e, 0x00 },
+ { 0x3fc2df6f, 0x00 },
+ { 0x3fc2df70, 0x04 },
+ { 0x3fc2df71, 0x00 },
+ { 0x3fc2df72, 0x00 },
+ { 0x3fc2df73, 0x00 },
+ { 0x3fc2df74, 0x01 },
+ { 0x3fc2df75, 0x00 },
+ { 0x3fc2df76, 0x00 },
+ { 0x3fc2df77, 0x00 },
+ { 0x1000db00, 0x04 },
+ { 0x1000db01, 0x00 },
+ { 0x1000db02, 0x10 },
+ { 0x1000db03, 0x00 },
+ { 0x1000db04, 0x00 },
+ { 0x1000db05, 0x45 },
+ { 0x1000db06, 0x0d },
+ { 0x1000db07, 0x01 },
+ { 0x1000db08, 0x00 },
+ { 0x1000db09, 0x00 },
+ { 0x1000db0a, 0xbf },
+ { 0x1000db0b, 0x0b },
+ { 0x1000db0c, 0x11 },
+ { 0x1000db0d, 0x00 },
+ { 0x1000db0e, 0x00 },
+ { 0x1000db0f, 0x00 },
+ { 0x1000db10, 0x2c },
+ { 0x1000db11, 0xfa },
+ { 0x1000db12, 0x00 },
+ { 0x1000db13, 0x00 },
+ { 0x1000db14, 0x09 },
+ { 0x0000d540, 0x21 },
+ { 0x0000d714, 0x17 },
+ { 0x0000dd0b, 0x0d },
+ { 0x0000dd0a, 0xff },
+ { 0x0000dd09, 0x0d },
+ { 0x0000dd08, 0xff },
+ { 0x0000c5fb, 0x12 },
+ { 0x0000c570, 0x08 },
+};
+
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 },
@@ -440,6 +836,7 @@ static const struct reg_default rt1320_mbq_defaults[] = {
static bool rt1320_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case 0x004d:
case 0xc000 ... 0xc086:
case 0xc400 ... 0xc409:
case 0xc480 ... 0xc48f:
@@ -497,10 +894,15 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg)
case RT1321_PATCH_MAIN_VER ... RT1321_PATCH_BETA_VER:
case 0x1000f008:
case 0x1000f021:
- case 0x2000300f:
+ case 0x20003000 ... 0x2000300f:
case 0x2000301c:
- case 0x2000900f:
+ case 0x20003040 ... 0x20003059:
+ case 0x20005800 ... 0x2000580f:
+ case 0x20005818:
+ case 0x20005840 ... 0x20005859:
+ case 0x20009000 ... 0x2000900f:
case 0x20009018:
+ case 0x20009040 ... 0x20009059:
case 0x3fc000c0 ... 0x3fc2dfc8:
case 0x3fe00000 ... 0x3fe36fff:
/* 0x40801508/0x40801809/0x4080180a/0x40801909/0x4080190a */
@@ -545,6 +947,7 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg)
static bool rt1320_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case 0x004d:
case 0xc000:
case 0xc003:
case 0xc081:
@@ -596,15 +999,20 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg)
case 0x1000c000 ... 0x1000dfff:
case 0x1000f008:
case 0x1000f021:
- case 0x2000300f:
+ case 0x2000300e ... 0x2000300f:
case 0x2000301c:
- case 0x2000900f:
+ case 0x20003040 ... 0x20003059:
+ case 0x2000580e ... 0x2000580f:
+ case 0x20005818:
+ case 0x20005840 ... 0x20005859:
+ case 0x2000900e ... 0x2000900f:
case 0x20009018:
+ case 0x20009040 ... 0x20009059:
case 0x3fc2ab80 ... 0x3fc2ac4c:
case 0x3fc2b780:
case 0x3fc2bf80 ... 0x3fc2bf83:
case 0x3fc2bfc0 ... 0x3fc2bfc8:
- case 0x3fc2d300 ... 0x3fc2d354:
+ case 0x3fc2d300 ... 0x3fc2d3cc:
case 0x3fc2dfc0 ... 0x3fc2dfc8:
case 0x3fe2e000 ... 0x3fe2e003:
case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0):
@@ -892,6 +1300,42 @@ static int rt1320_check_fw_ready(struct rt1320_sdw_priv *rt1320)
return 0;
}
+static int rt1320_dspfw_status(struct rt1320_sdw_priv *rt1320)
+{
+ struct device *dev = &rt1320->sdw_slave->dev;
+ unsigned int fw_status_addr, fw_ready;
+ unsigned int dspfw_run;
+
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
+ break;
+ case RT1321_DEV_ID:
+ fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
+ break;
+ default:
+ dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
+ return -EINVAL;
+ }
+
+ regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
+ fw_ready &= 0x1;
+
+ if (rt1320->dev_id == RT1321_DEV_ID) {
+ regmap_read(rt1320->regmap, 0xf01e, &dspfw_run);
+ dspfw_run &= 0x1;
+ fw_ready = (!dspfw_run && fw_ready);
+ }
+
+ if (fw_ready) {
+ dev_dbg(dev, "%s, DSP FW was already\n", __func__);
+ return 1;
+ }
+
+ dev_dbg(dev, "%s, DSP FW is NOT ready. Please load DSP FW first\n", __func__);
+ return 0;
+}
+
static int rt1320_check_power_state_ready(struct rt1320_sdw_priv *rt1320, enum rt1320_power_state ps)
{
struct device *dev = &rt1320->sdw_slave->dev;
@@ -982,6 +1426,9 @@ static int rt1320_fw_param_protocol(struct rt1320_sdw_priv *rt1320, enum rt1320_
if (!tempbuf)
return -ENOMEM;
+ if (rt1320->dev_id == RT1321_DEV_ID && rt1320->version_id == RT1321_VA2)
+ paramid += 0x0bff0000;
+
paramhr.moudleid = 1;
paramhr.commandtype = cmdid;
/* 8 is "sizeof(paramid) + sizeof(paramlength)" */
@@ -1120,45 +1567,73 @@ static void rt1320_calc_r0(struct rt1320_sdw_priv *rt1320)
l_calir0, l_calir0_lo, r_calir0, r_calir0_lo);
}
+static int rt1320_pilot_tone_output(struct rt1320_sdw_priv *rt1320)
+{
+ struct device *dev = &rt1320->sdw_slave->dev;
+ int l_targetpostgain, r_targetpostgain;
+ unsigned long long factor = (1 << 12);
+ int l_pilotgain[9], r_pilotgain[9];
+ const int postgain_step = 234;
+ int targetGain;
+
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ targetGain = -320000;
+ break;
+ case RT1321_DEV_ID:
+ targetGain = -420000;
+ if (rt1320->version_id == RT1321_VA0)
+ targetGain = -320000;
+ break;
+ default:
+ dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
+ return -EINVAL;
+ }
+
+ rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 70, &l_pilotgain[0], sizeof(l_pilotgain));
+ rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 71, &r_pilotgain[0], sizeof(r_pilotgain));
+ dev_dbg(dev, "%s, LR pilotgain %d, %d\n", __func__, l_pilotgain[2], r_pilotgain[2]);
+
+ /* calculate pilot tone gain */
+ l_pilotgain[2] = (l_pilotgain[2] * 10000) / factor;
+ r_pilotgain[2] = (r_pilotgain[2] * 10000) / factor;
+
+ /* calculate post gain to meet target gain */
+ l_targetpostgain = abs(targetGain - l_pilotgain[2]) / postgain_step;
+ r_targetpostgain = abs(targetGain - r_pilotgain[2]) / postgain_step;
+ l_targetpostgain = 0xfff - l_targetpostgain;
+ r_targetpostgain = 0xfff - r_targetpostgain;
+ dev_dbg(dev, "%s, LR targetpostgain=0x%x, 0x%x\n", __func__, l_targetpostgain, r_targetpostgain);
+
+ regmap_write(rt1320->regmap, 0xdd0b, (l_targetpostgain & 0xf00) >> 8);
+ regmap_write(rt1320->regmap, 0xdd0a, l_targetpostgain & 0xff);
+ regmap_write(rt1320->regmap, 0xdd09, (r_targetpostgain & 0xf00) >> 8);
+ regmap_write(rt1320->regmap, 0xdd08, r_targetpostgain & 0xff);
+
+ return 0;
+}
+
static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320)
{
struct device *dev = &rt1320->sdw_slave->dev;
struct rt1320_datafixpoint audfixpoint[2];
unsigned int reg_c5fb, reg_c570, reg_cd00;
- unsigned int vol_reg[4], fw_ready;
+ unsigned int vol_reg[4];
unsigned long long l_meanr0, r_meanr0;
- unsigned int fw_status_addr;
int l_re[5], r_re[5];
int ret, tmp;
unsigned long long factor = (1 << 27);
unsigned short l_advancegain, r_advancegain;
unsigned int delay_s = 7; /* delay seconds for the calibration */
+ int dspfw_status;
if (!rt1320->component)
return;
- switch (rt1320->dev_id) {
- case RT1320_DEV_ID:
- fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
- break;
- case RT1321_DEV_ID:
- fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
- break;
- default:
- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
- return;
- }
-
- /* set volume 0dB */
regmap_read(rt1320->regmap, 0xdd0b, &vol_reg[3]);
regmap_read(rt1320->regmap, 0xdd0a, &vol_reg[2]);
regmap_read(rt1320->regmap, 0xdd09, &vol_reg[1]);
regmap_read(rt1320->regmap, 0xdd08, &vol_reg[0]);
- regmap_write(rt1320->regmap, 0xdd0b, 0x0f);
- regmap_write(rt1320->regmap, 0xdd0a, 0xff);
- regmap_write(rt1320->regmap, 0xdd09, 0x0f);
- regmap_write(rt1320->regmap, 0xdd08, 0xff);
-
regmap_read(rt1320->regmap, 0xc5fb, &reg_c5fb);
regmap_read(rt1320->regmap, 0xc570, &reg_c570);
regmap_read(rt1320->regmap, 0xcd00, &reg_cd00);
@@ -1171,9 +1646,8 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320)
goto _finish_;
}
- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
- fw_ready &= 0x1;
- if (!fw_ready) {
+ dspfw_status = rt1320_dspfw_status(rt1320);
+ if (dspfw_status <= 0) {
dev_dbg(dev, "%s, DSP FW is NOT ready. Please load DSP FW first\n", __func__);
goto _finish_;
}
@@ -1184,8 +1658,19 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320)
goto _finish_;
}
- if (rt1320->dev_id == RT1320_DEV_ID)
- regmap_write(rt1320->regmap, 0xc5fb, 0x00);
+ /* fine tune pilot tone output */
+ ret = rt1320_pilot_tone_output(rt1320);
+ if (ret < 0) {
+ dev_dbg(dev, "%s, Failed to tune pilot tone output\n", __func__);
+ goto _finish_;
+ }
+
+ if (rt1320->dev_id == RT1321_DEV_ID) {
+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x00);
+ regmap_write(rt1320->regmap, 0xc5c4, 0x12);
+ }
+
+ regmap_write(rt1320->regmap, 0xc5fb, 0x00);
regmap_write(rt1320->regmap, 0xc570, 0x0b);
regmap_write(rt1320->regmap, 0xcd00, 0xc5);
@@ -1246,6 +1731,11 @@ _finish_:
SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03);
rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x03);
+ if (rt1320->dev_id == RT1321_DEV_ID) {
+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x80);
+ regmap_write(rt1320->regmap, 0xc5c4, 0x10);
+ }
+
/* advance gain will be set when R0 load, not here */
regmap_write(rt1320->regmap, 0xdd0b, vol_reg[3]);
regmap_write(rt1320->regmap, 0xdd0a, vol_reg[2]);
@@ -1296,7 +1786,7 @@ static int rt1320_r0_cali_put(struct snd_kcontrol *kcontrol,
static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320)
{
struct sdw_slave *slave = rt1320->sdw_slave;
- const struct firmware *patch;
+ const struct firmware *patch __free(firmware) = NULL;
const char *filename;
unsigned int addr, val, min_addr, max_addr;
const unsigned char *ptr;
@@ -1312,6 +1802,9 @@ static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320)
max_addr = 0x10007fff;
break;
case RT1321_DEV_ID:
+ if (rt1320->version_id == RT1321_VA2)
+ return;
+
filename = RT1321_VA_MCU_PATCH;
min_addr = 0x10008000;
max_addr = 0x10008fff;
@@ -1347,17 +1840,15 @@ static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320)
if (addr > max_addr || addr < min_addr) {
dev_err(&slave->dev, "%s: the address 0x%x is wrong", __func__, addr);
- goto _exit_;
+ return;
}
if (val > 0xff) {
dev_err(&slave->dev, "%s: the value 0x%x is wrong", __func__, val);
- goto _exit_;
+ return;
}
regmap_write(rt1320->regmap, addr, val);
}
}
-_exit_:
- release_firmware(patch);
}
}
@@ -1382,30 +1873,17 @@ static void rt1320_vab_preset(struct rt1320_sdw_priv *rt1320)
static void rt1320_t0_load(struct rt1320_sdw_priv *rt1320, unsigned int l_t0, unsigned int r_t0)
{
struct device *dev = &rt1320->sdw_slave->dev;
- unsigned int factor = (1 << 22), fw_ready;
+ unsigned int factor = (1 << 22);
int l_t0_data[38], r_t0_data[38];
- unsigned int fw_status_addr;
-
- switch (rt1320->dev_id) {
- case RT1320_DEV_ID:
- fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
- break;
- case RT1321_DEV_ID:
- fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
- break;
- default:
- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
- return;
- }
+ int dspfw_status;
regmap_write(rt1320->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00);
rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00);
- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
- fw_ready &= 0x1;
- if (!fw_ready) {
+ dspfw_status = rt1320_dspfw_status(rt1320);
+ if (dspfw_status <= 0) {
dev_warn(dev, "%s, DSP FW is NOT ready\n", __func__);
goto _exit_;
}
@@ -1444,7 +1922,7 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320)
struct device *dev = &rt1320->sdw_slave->dev;
static const char func_tag[] = "FUNC";
static const char xu_tag[] = "XU";
- const struct firmware *rae_fw = NULL;
+ const struct firmware *rae_fw __free(firmware) = NULL;
unsigned int fw_offset;
unsigned char *fw_data;
unsigned char *param_data;
@@ -1483,22 +1961,46 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320)
request_firmware(&rae_fw, rae_filename, dev);
if (rae_fw) {
- /* RAE CRC clear */
- regmap_write(rt1320->regmap, 0xe80b, 0x0f);
-
- /* RAE stop & CRC disable */
- regmap_update_bits(rt1320->regmap, 0xe803, 0xbc, 0x00);
-
- while (--retry) {
- regmap_read(rt1320->regmap, 0xe83f, &value);
- if (value & 0x40)
- break;
- usleep_range(1000, 1100);
- }
- if (!retry && !(value & 0x40)) {
- dev_err(dev, "%s: RAE is not ready to load\n", __func__);
- release_firmware(rae_fw);
- return -ETIMEDOUT;
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ /* RAE CRC clear */
+ regmap_write(rt1320->regmap, 0xe80b, 0x0f);
+ /* RAE stop & CRC disable */
+ regmap_update_bits(rt1320->regmap, 0xe803, 0xbc, 0x00);
+ while (--retry) {
+ regmap_read(rt1320->regmap, 0xe83f, &value);
+ if (value & 0x40)
+ break;
+ usleep_range(1000, 1100);
+ }
+ if (!retry && !(value & 0x40)) {
+ dev_err(dev, "%s: RAE is not ready to load\n", __func__);
+ return -ETIMEDOUT;
+ }
+ break;
+ case RT1321_DEV_ID:
+ /* RAE CRC clear */
+ regmap_write(rt1320->regmap, 0x2000300e, 0xc0);
+ regmap_write(rt1320->regmap, 0x2000300f, 0x0f);
+ /* RAE stop & Phase sync & CRC disable */
+ regmap_update_bits(rt1320->regmap, 0x20003003, 0xfe, 0x00);
+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x01, 0x00);
+ /* check whether write state is ready */
+ while (--retry) {
+ regmap_read(rt1320->regmap, 0x20003043, &value);
+ if (value & 0x40)
+ break;
+ usleep_range(1000, 1100);
+ }
+ if (!retry && !(value & 0x40)) {
+ dev_err(dev, "%s: RAE is not ready to load\n", __func__);
+ return -ETIMEDOUT;
+ }
+ break;
+ default:
+ dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
+ return -EINVAL;
}
dev_dbg(dev, "%s, rae_fw size=0x%zx\n", __func__, rae_fw->size);
@@ -1551,7 +2053,6 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320)
}
regcache_cache_bypass(rt1320->regmap, false);
- release_firmware(rae_fw);
} else {
dev_err(dev, "%s: Failed to load %s firmware\n", __func__, rae_filename);
@@ -1559,18 +2060,34 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320)
goto _exit_;
}
- /* RAE CRC enable */
- regmap_update_bits(rt1320->regmap, 0xe803, 0x0c, 0x0c);
-
- /* RAE update */
- regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x00);
- regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x80);
-
- /* RAE run */
- regmap_update_bits(rt1320->regmap, 0xe803, 0x80, 0x80);
-
- regmap_read(rt1320->regmap, 0xe80b, &value);
- dev_dbg(dev, "%s: CAE run => 0xe80b reg = 0x%x\n", __func__, value);
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ /* RAE CRC enable */
+ regmap_update_bits(rt1320->regmap, 0xe803, 0x0c, 0x0c);
+ /* RAE update */
+ regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x80);
+ /* RAE run */
+ regmap_update_bits(rt1320->regmap, 0xe803, 0x80, 0x80);
+ regmap_read(rt1320->regmap, 0xe80b, &value);
+ dev_dbg(dev, "%s: CAE run => 0xe80b reg = 0x%x\n", __func__, value);
+ break;
+ case RT1321_DEV_ID:
+ /* RAE CRC enable */
+ regmap_update_bits(rt1320->regmap, 0x20003003, 0x30, 0x30);
+ /* RAE update */
+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x80, 0x80);
+ regmap_update_bits(rt1320->regmap, 0x20009018, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0x20009018, 0x80, 0x80);
+ regmap_update_bits(rt1320->regmap, 0x20005818, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0x20005818, 0x80, 0x80);
+ /* RAE run */
+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x01, 0x01);
+ /* Phase sync eanble */
+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x80);
+ break;
+ }
rt1320->rae_update_done = true;
@@ -1598,32 +2115,21 @@ struct rt1320_dspfwheader {
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt1320->component);
struct device *dev = &rt1320->sdw_slave->dev;
- unsigned int val, i, fw_offset, fw_ready;
- unsigned int fw_status_addr;
+ unsigned int val, i, fw_offset;
struct rt1320_dspfwheader *fwheader;
struct rt1320_imageinfo *ptr_img;
struct sdw_bpt_section sec[10];
- const struct firmware *fw = NULL;
+ const struct firmware *fw __free(firmware) = NULL;
unsigned char *fw_data;
bool dev_fw_match = false;
static const char hdr_sig[] = "AFX";
unsigned int hdr_size = 0;
const char *dmi_vendor, *dmi_product, *dmi_sku;
int len_vendor, len_product, len_sku;
+ unsigned char boot_mode = 0; /* 0: from RAM; 1: from ROM */
+ unsigned char has_0x3fc00000 = 0;
char filename[512];
- switch (rt1320->dev_id) {
- case RT1320_DEV_ID:
- fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
- break;
- case RT1321_DEV_ID:
- fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
- break;
- default:
- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
- return;
- }
-
dmi_vendor = dmi_get_system_info(DMI_SYS_VENDOR);
dmi_product = dmi_get_system_info(DMI_PRODUCT_NAME);
dmi_sku = dmi_get_system_info(DMI_PRODUCT_SKU);
@@ -1653,17 +2159,12 @@ struct rt1320_dspfwheader {
RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00);
rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00);
- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
- fw_ready &= 0x1;
- if (fw_ready) {
+ if (rt1320_dspfw_status(rt1320)) {
dev_dbg(dev, "%s, DSP FW was already\n", __func__);
rt1320->fw_load_done = true;
goto _exit_;
}
- /* change to IRAM */
- regmap_update_bits(rt1320->regmap, 0xf01e, 0x80, 0x00);
-
request_firmware(&fw, filename, dev);
if (fw) {
fwheader = (struct rt1320_dspfwheader *)fw->data;
@@ -1672,7 +2173,6 @@ struct rt1320_dspfwheader {
if (fwheader->sync != 0x0a1c5679) {
dev_err(dev, "%s: FW sync error\n", __func__);
- release_firmware(fw);
goto _exit_;
}
@@ -1709,9 +2209,11 @@ struct rt1320_dspfwheader {
dev_fw_match = true;
break;
case RT1321_DEV_ID:
- if (ptr_img->addr == 0x3fc00000)
- if (fw_data[9] == '1')
+ if (ptr_img->addr == 0x3fc00000) {
+ if (fw_data[7] == '1')
dev_fw_match = true;
+ has_0x3fc00000 = 1;
+ }
break;
default:
dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
@@ -1721,6 +2223,22 @@ struct rt1320_dspfwheader {
fw_offset += ptr_img->size;
}
+ if (rt1320->dev_id == RT1321_DEV_ID && rt1320->version_id == RT1321_VA2) {
+ /*
+ * For 1321 VA2, if the FW doesn't include the section for address 0x3fc00000,
+ * it means the FW will boot from ROM and force dev_fw_match to true to download FW by BRA.
+ */
+ if (!has_0x3fc00000) {
+ boot_mode = 1;
+ dev_fw_match = true;
+ }
+ dev_dbg(dev, "%s: Boot from %s for VA2\n", __func__, (boot_mode ? "ROM" : "RAM"));
+ }
+
+ /* change to IRAM */
+ if (!boot_mode)
+ regmap_update_bits(rt1320->regmap, 0xf01e, 0x80, 0x00);
+
if (dev_fw_match) {
dev_dbg(dev, "%s, starting BRA downloading FW..\n", __func__);
rt1320->bra_msg.dev_num = rt1320->sdw_slave->dev_num;
@@ -1732,7 +2250,6 @@ struct rt1320_dspfwheader {
}
regcache_cache_bypass(rt1320->regmap, false);
- release_firmware(fw);
if (!dev_fw_match) {
dev_err(dev, "%s: FW file doesn't match to device\n", __func__);
@@ -1743,24 +2260,39 @@ struct rt1320_dspfwheader {
goto _exit_;
}
- /* run RAM code */
- regmap_read(rt1320->regmap, 0x3fc2bfc0, &val);
- val |= 0x8;
- regmap_write(rt1320->regmap, 0x3fc2bfc0, val);
-
- /* clear frame counter */
switch (rt1320->dev_id) {
case RT1320_DEV_ID:
+ /* run RAM code */
+ regmap_read(rt1320->regmap, 0x3fc2bfc0, &val);
+ val |= 0x8;
+ regmap_write(rt1320->regmap, 0x3fc2bfc0, val);
+ /* clear frame counter */
regmap_write(rt1320->regmap, 0x3fc2bfcb, 0x00);
regmap_write(rt1320->regmap, 0x3fc2bfca, 0x00);
regmap_write(rt1320->regmap, 0x3fc2bfc9, 0x00);
regmap_write(rt1320->regmap, 0x3fc2bfc8, 0x00);
break;
case RT1321_DEV_ID:
+ if (!boot_mode) {
+ /* run RAM code */
+ regmap_read(rt1320->regmap, 0x3fc2dfc0, &val);
+ val |= 0x8;
+ regmap_write(rt1320->regmap, 0x3fc2dfc0, val);
+ }
+ /* clear frame counter */
regmap_write(rt1320->regmap, 0x3fc2dfcb, 0x00);
regmap_write(rt1320->regmap, 0x3fc2dfca, 0x00);
regmap_write(rt1320->regmap, 0x3fc2dfc9, 0x00);
regmap_write(rt1320->regmap, 0x3fc2dfc8, 0x00);
+ /* enable handshake */
+ regmap_write(rt1320->regmap, 0x3fc2dfc4, 0x00);
+ regmap_write(rt1320->regmap, 0xd470, 0xad);
+ /* minimum phase settings */
+ regmap_write(rt1320->regmap, 0xc5c4, 0x10);
+ regmap_write(rt1320->regmap, 0x20003003, 0x31);
+ regmap_update_bits(rt1320->regmap, 0x20003002, 0x40, 0x00);
+ regmap_write(rt1320->regmap, 0xc5b3, 0x01);
+ regmap_write(rt1320->regmap, 0xc052, 0x11);
break;
}
@@ -1843,14 +2375,35 @@ static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320)
static void rt1321_preset(struct rt1320_sdw_priv *rt1320)
{
+ const struct reg_sequence *blindwrite;
unsigned int i, reg, val, delay;
+ unsigned int array_size;
+
+ switch (rt1320->version_id) {
+ case RT1321_VA0:
+ blindwrite = rt1321_blind_write;
+ array_size = ARRAY_SIZE(rt1321_blind_write);
+ break;
+ case RT1321_VA1:
+ blindwrite = rt1321_va1_blind_write;
+ array_size = ARRAY_SIZE(rt1321_va1_blind_write);
+ break;
+ case RT1321_VA2:
+ blindwrite = rt1321_va2_blind_write;
+ array_size = ARRAY_SIZE(rt1321_va2_blind_write);
+ break;
+ default:
+ dev_err(&rt1320->sdw_slave->dev, "%s: Unknown version ID %d\n",
+ __func__, rt1320->version_id);
+ return;
+ }
- for (i = 0; i < ARRAY_SIZE(rt1321_blind_write); i++) {
- reg = rt1321_blind_write[i].reg;
- val = rt1321_blind_write[i].def;
- delay = rt1321_blind_write[i].delay_us;
+ for (i = 0; i < array_size; i++) {
+ reg = blindwrite[i].reg;
+ val = blindwrite[i].def;
+ delay = blindwrite[i].delay_us;
- if (reg == 0x3fc2dfc3)
+ if (reg == 0x1000cd56)
rt1320_load_mcu_patch(rt1320);
regmap_write(rt1320->regmap, reg, val);
@@ -1892,6 +2445,24 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave)
regmap_read(rt1320->regmap, RT1320_DEV_ID_0, &val);
regmap_read(rt1320->regmap, RT1320_DEV_ID_1, &tmp);
rt1320->dev_id = (val << 8) | tmp;
+
+ /* This is a workaround that reads the value twice to obtain the correct result. */
+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_0, &val);
+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_1, &tmp);
+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_0, &val);
+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_1, &tmp);
+ val = (val << 8) | tmp;
+
+ if (rt1320->dev_id == RT1321_DEV_ID) {
+ if (rt1320->version_id == 0x01)
+ rt1320->version_id = RT1321_VA2;
+ else if (val == RT1321_DEV_HV_VA0_ID)
+ rt1320->version_id = RT1321_VA0;
+ else if (val == RT1321_DEV_HV_VA1_ID)
+ rt1320->version_id = RT1321_VA1;
+ else
+ dev_err(dev, "%s: Unknown version ID 0x%x for RT1321\n", __func__, rt1320->version_id);
+ }
}
regmap_read(rt1320->regmap,
@@ -2326,25 +2897,12 @@ static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
static int rt1320_r0_load(struct rt1320_sdw_priv *rt1320)
{
struct device *dev = regmap_get_device(rt1320->regmap);
- unsigned int fw_status_addr;
- unsigned int fw_ready;
+ int dspfw_status;
int ret = 0;
if (!rt1320->r0_l_reg || !rt1320->r0_r_reg)
return -EINVAL;
- switch (rt1320->dev_id) {
- case RT1320_DEV_ID:
- fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
- break;
- case RT1321_DEV_ID:
- fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
- break;
- default:
- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
- return -EINVAL;
- }
-
regmap_write(rt1320->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00);
ret = rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00);
@@ -2353,9 +2911,8 @@ static int rt1320_r0_load(struct rt1320_sdw_priv *rt1320)
goto _timeout_;
}
- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
- fw_ready &= 0x1;
- if (!fw_ready) {
+ dspfw_status = rt1320_dspfw_status(rt1320);
+ if (dspfw_status <= 0) {
dev_dbg(dev, "%s, DSP FW is NOT ready\n", __func__);
goto _timeout_;
}
@@ -2458,7 +3015,7 @@ static int rt1320_dspfw_load_put(struct snd_kcontrol *kcontrol,
if (!rt1320->hw_init)
return 0;
- ret = pm_runtime_resume(component->dev);
+ ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -2469,6 +3026,8 @@ static int rt1320_dspfw_load_put(struct snd_kcontrol *kcontrol,
if (!ucontrol->value.integer.value[0])
rt1320->fw_load_done = false;
+ pm_runtime_mark_last_busy(component->dev);
+ pm_runtime_put_autosuspend(component->dev);
return 0;
}
@@ -2819,6 +3378,37 @@ static int rt1320_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
return 0;
}
+static int rt1320_bus_config(struct sdw_slave *slave,
+ struct sdw_bus_params *params)
+{
+ struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(&slave->dev);
+ unsigned int clk_base;
+
+ regmap_read(rt1320->regmap, 0x004d, &clk_base);
+ dev_dbg(&rt1320->sdw_slave->dev, "%s clk_base=%x", __func__, clk_base);
+
+ switch (clk_base) {
+ case RT1320_CLK_FREQ_19_2_MHZ:
+ case RT1320_CLK_FREQ_24MHZ:
+ regmap_write(rt1320->regmap, 0xc600, 0x04);
+ regmap_write(rt1320->regmap, 0xc601, 0x83);
+ regmap_write(rt1320->regmap, 0xc602, 0x1f);
+ regmap_write(rt1320->regmap, 0xc603, 0x40);
+ break;
+ case RT1320_CLK_FREQ_24_576MHZ:
+ case RT1320_CLK_FREQ_22_5792MHZ:
+ regmap_write(rt1320->regmap, 0xc600, 0x07);
+ regmap_write(rt1320->regmap, 0xc601, 0x80);
+ regmap_write(rt1320->regmap, 0xc602, 0x0f);
+ regmap_write(rt1320->regmap, 0xc603, 0x40);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/*
* slave_ops: callbacks for get_clock_stop_mode, clock_stop and
* port_prep are not defined for now
@@ -2826,12 +3416,13 @@ static int rt1320_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
static const struct sdw_slave_ops rt1320_slave_ops = {
.read_prop = rt1320_read_prop,
.update_status = rt1320_update_status,
+ .bus_config = rt1320_bus_config,
};
static int rt1320_sdw_component_probe(struct snd_soc_component *component)
{
- int ret;
struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ int ret;
rt1320->component = component;
@@ -3062,10 +3653,23 @@ static int rt1320_dev_resume(struct device *dev)
return ret;
regcache_cache_only(rt1320->regmap, false);
- regcache_sync(rt1320->regmap);
+ ret = regcache_sync(rt1320->regmap);
+ if (ret)
+ goto err_sync;
+
regcache_cache_only(rt1320->mbq_regmap, false);
- regcache_sync(rt1320->mbq_regmap);
+ ret = regcache_sync(rt1320->mbq_regmap);
+ if (ret)
+ goto err_sync;
+
return 0;
+
+err_sync:
+ regcache_cache_only(rt1320->regmap, true);
+ regcache_cache_only(rt1320->mbq_regmap, true);
+ regcache_mark_dirty(rt1320->regmap);
+ regcache_mark_dirty(rt1320->mbq_regmap);
+ return ret;
}
static const struct dev_pm_ops rt1320_pm = {
diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h
index a7b573883dd0..df9ccdf92d36 100644
--- a/sound/soc/codecs/rt1320-sdw.h
+++ b/sound/soc/codecs/rt1320-sdw.h
@@ -17,12 +17,17 @@
#define RT1320_DEV_ID 0x6981
#define RT1321_DEV_ID 0x7045
+#define RT1321_DEV_HV_VA0_ID 0x6997
+#define RT1321_DEV_HV_VA1_ID 0x7071
/* imp-defined registers */
#define RT1320_DEV_VERSION_ID_1 0xc404
#define RT1320_DEV_ID_1 0xc405
#define RT1320_DEV_ID_0 0xc406
+#define RT1320_HV_DEV_ID_0 0xf622
+#define RT1320_HV_DEV_ID_1 0xf623
+
#define RT1320_POWER_STATE 0xc560
#define RT1321_PATCH_MAIN_VER 0x1000cffe
@@ -94,6 +99,12 @@ enum rt1320_version_id {
RT1320_VC,
};
+enum rt1321_version_id {
+ RT1321_VA0,
+ RT1321_VA1,
+ RT1321_VA2,
+};
+
#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"
@@ -121,6 +132,7 @@ struct rt1320_datafixpoint {
int invrs;
};
+/* FW parameter id 1300 */
typedef struct FwPara_HwSwGain {
unsigned int SwAdvGain;
unsigned int SwBasGain;
@@ -163,6 +175,13 @@ enum rt1320_rw_type {
RT1320_PARAM_READ = 3,
};
+enum {
+ RT1320_CLK_FREQ_19_2_MHZ = 1,
+ RT1320_CLK_FREQ_24MHZ = 2,
+ RT1320_CLK_FREQ_24_576MHZ = 3,
+ RT1320_CLK_FREQ_22_5792MHZ = 4,
+};
+
struct rt1320_sdw_priv {
struct snd_soc_component *component;
struct regmap *regmap;
diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c
index 63b5fc439773..f8c370106504 100644
--- a/sound/soc/codecs/rt274.c
+++ b/sound/soc/codecs/rt274.c
@@ -184,8 +184,10 @@ static const struct reg_default rt274_reg[] = {
{ 0x0023a000, 0x00000057 },
{ 0x00270500, 0x00000400 },
{ 0x00370500, 0x00000400 },
+ { 0x00830000, 0x00000097 },
{ 0x00870500, 0x00000400 },
{ 0x00920000, 0x00000031 },
+ { 0x00930000, 0x00000097 },
{ 0x00935000, 0x00000097 },
{ 0x00936000, 0x00000097 },
{ 0x00970500, 0x00000400 },
@@ -195,10 +197,12 @@ static const struct reg_default rt274_reg[] = {
{ 0x00c37000, 0x00000400 },
{ 0x00c37100, 0x00000400 },
{ 0x01270500, 0x00000400 },
+ { 0x01270700, 0x00000000 },
{ 0x01370500, 0x00000400 },
{ 0x01371f00, 0x411111f0 },
{ 0x01937000, 0x00000000 },
{ 0x01970500, 0x00000400 },
+ { 0x01970700, 0x00000020 },
{ 0x02050000, 0x0000001b },
{ 0x02139000, 0x00000080 },
{ 0x0213a000, 0x00000080 },
@@ -207,10 +211,6 @@ static const struct reg_default rt274_reg[] = {
{ 0x02170700, 0x00000000 },
{ 0x02270100, 0x00000000 },
{ 0x02370100, 0x00000000 },
- { 0x01970700, 0x00000020 },
- { 0x00830000, 0x00000097 },
- { 0x00930000, 0x00000097 },
- { 0x01270700, 0x00000000 },
};
static bool rt274_volatile_register(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index ded0ea332480..4217467904d6 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -77,8 +77,10 @@ static const struct reg_default rt286_reg[] = {
{ 0x0023a000, 0x0000007f },
{ 0x00270500, 0x00000400 },
{ 0x00370500, 0x00000400 },
+ { 0x00830000, 0x000000c3 },
{ 0x00870500, 0x00000400 },
{ 0x00920000, 0x00000031 },
+ { 0x00930000, 0x000000c3 },
{ 0x00935000, 0x000000c3 },
{ 0x00936000, 0x000000c3 },
{ 0x00970500, 0x00000400 },
@@ -88,16 +90,18 @@ static const struct reg_default rt286_reg[] = {
{ 0x00c37000, 0x00000000 },
{ 0x00c37100, 0x00000080 },
{ 0x01270500, 0x00000400 },
+ { 0x01270700, 0x00000000 },
{ 0x01370500, 0x00000400 },
{ 0x01371f00, 0x411111f0 },
{ 0x01439000, 0x00000080 },
{ 0x0143a000, 0x00000080 },
- { 0x01470700, 0x00000000 },
+ { 0x01470100, 0x00000000 },
{ 0x01470500, 0x00000400 },
+ { 0x01470700, 0x00000000 },
{ 0x01470c00, 0x00000000 },
- { 0x01470100, 0x00000000 },
{ 0x01837000, 0x00000000 },
{ 0x01870500, 0x00000400 },
+ { 0x01870700, 0x00000020 },
{ 0x02050000, 0x00000000 },
{ 0x02139000, 0x00000080 },
{ 0x0213a000, 0x00000080 },
@@ -106,10 +110,6 @@ static const struct reg_default rt286_reg[] = {
{ 0x02170700, 0x00000000 },
{ 0x02270100, 0x00000000 },
{ 0x02370100, 0x00000000 },
- { 0x01870700, 0x00000020 },
- { 0x00830000, 0x000000c3 },
- { 0x00930000, 0x000000c3 },
- { 0x01270700, 0x00000000 },
};
static bool rt286_volatile_register(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index 5414a1712b57..09aed08b5b79 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -78,8 +78,10 @@ static const struct reg_default rt298_reg[] = {
{ 0x0023a000, 0x0000007f },
{ 0x00270500, 0x00000400 },
{ 0x00370500, 0x00000400 },
+ { 0x00830000, 0x000000c3 },
{ 0x00870500, 0x00000400 },
{ 0x00920000, 0x00000031 },
+ { 0x00930000, 0x000000c3 },
{ 0x00935000, 0x000000c3 },
{ 0x00936000, 0x000000c3 },
{ 0x00970500, 0x00000400 },
@@ -89,16 +91,18 @@ static const struct reg_default rt298_reg[] = {
{ 0x00c37000, 0x00000000 },
{ 0x00c37100, 0x00000080 },
{ 0x01270500, 0x00000400 },
+ { 0x01270700, 0x00000000 },
{ 0x01370500, 0x00000400 },
{ 0x01371f00, 0x411111f0 },
{ 0x01439000, 0x00000080 },
{ 0x0143a000, 0x00000080 },
- { 0x01470700, 0x00000000 },
+ { 0x01470100, 0x00000000 },
{ 0x01470500, 0x00000400 },
+ { 0x01470700, 0x00000000 },
{ 0x01470c00, 0x00000000 },
- { 0x01470100, 0x00000000 },
{ 0x01837000, 0x00000000 },
{ 0x01870500, 0x00000400 },
+ { 0x01870700, 0x00000020 },
{ 0x02050000, 0x00000000 },
{ 0x02139000, 0x00000080 },
{ 0x0213a000, 0x00000080 },
@@ -107,10 +111,6 @@ static const struct reg_default rt298_reg[] = {
{ 0x02170700, 0x00000000 },
{ 0x02270100, 0x00000000 },
{ 0x02370100, 0x00000000 },
- { 0x01870700, 0x00000020 },
- { 0x00830000, 0x000000c3 },
- { 0x00930000, 0x000000c3 },
- { 0x01270700, 0x00000000 },
};
static bool rt298_volatile_register(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 199507d12841..91290bfe8daa 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -6,6 +6,7 @@
* Author: Oder Chiou <oder_chiou@realtek.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/spi/spi.h>
@@ -79,17 +80,17 @@ static void rt5514_spi_copy_work(struct work_struct *work)
unsigned int cur_wp, remain_data;
u8 buf[8];
- mutex_lock(&rt5514_dsp->dma_lock);
+ guard(mutex)(&rt5514_dsp->dma_lock);
if (!rt5514_dsp->substream) {
dev_err(rt5514_dsp->dev, "No pcm substream\n");
- goto done;
+ return;
}
runtime = rt5514_dsp->substream->runtime;
period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream);
if (!period_bytes) {
schedule_delayed_work(&rt5514_dsp->copy_work, 5);
- goto done;
+ return;
}
if (rt5514_dsp->buf_size % period_bytes)
@@ -111,7 +112,7 @@ static void rt5514_spi_copy_work(struct work_struct *work)
if (remain_data < period_bytes) {
schedule_delayed_work(&rt5514_dsp->copy_work, 5);
- goto done;
+ return;
}
}
@@ -146,9 +147,6 @@ static void rt5514_spi_copy_work(struct work_struct *work)
snd_pcm_period_elapsed(rt5514_dsp->substream);
schedule_delayed_work(&rt5514_dsp->copy_work, 5);
-
-done:
- mutex_unlock(&rt5514_dsp->dma_lock);
}
static void rt5514_schedule_copy(struct rt5514_dsp *rt5514_dsp)
@@ -216,7 +214,7 @@ static int rt5514_spi_hw_params(struct snd_soc_component *component,
snd_soc_component_get_drvdata(component);
u8 buf[8];
- mutex_lock(&rt5514_dsp->dma_lock);
+ guard(mutex)(&rt5514_dsp->dma_lock);
rt5514_dsp->substream = substream;
rt5514_dsp->dma_offset = 0;
@@ -225,8 +223,6 @@ static int rt5514_spi_hw_params(struct snd_soc_component *component,
if (buf[0] & RT5514_IRQ_STATUS_BIT)
rt5514_schedule_copy(rt5514_dsp);
- mutex_unlock(&rt5514_dsp->dma_lock);
-
return 0;
}
@@ -236,9 +232,8 @@ static int rt5514_spi_hw_free(struct snd_soc_component *component,
struct rt5514_dsp *rt5514_dsp =
snd_soc_component_get_drvdata(component);
- mutex_lock(&rt5514_dsp->dma_lock);
- rt5514_dsp->substream = NULL;
- mutex_unlock(&rt5514_dsp->dma_lock);
+ scoped_guard(mutex, &rt5514_dsp->dma_lock)
+ rt5514_dsp->substream = NULL;
cancel_delayed_work_sync(&rt5514_dsp->copy_work);
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 00a4a208d2fa..58aecd4c83a6 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -1073,12 +1073,18 @@ static int rt5514_set_bias_level(struct snd_soc_component *component,
* settings to make sure recording properly.
*/
if (rt5514->dsp_enabled) {
- rt5514->dsp_enabled = 0;
- regmap_multi_reg_write(rt5514->i2c_regmap,
- rt5514_i2c_patch,
- ARRAY_SIZE(rt5514_i2c_patch));
+ ret = regmap_multi_reg_write(rt5514->i2c_regmap,
+ rt5514_i2c_patch,
+ ARRAY_SIZE(rt5514_i2c_patch));
+ if (ret)
+ return ret;
+
regcache_mark_dirty(rt5514->regmap);
- regcache_sync(rt5514->regmap);
+ ret = regcache_sync(rt5514->regmap);
+ if (ret)
+ return ret;
+
+ rt5514->dsp_enabled = 0;
}
}
break;
diff --git a/sound/soc/codecs/rt5575-spi.c b/sound/soc/codecs/rt5575-spi.c
index d5b3a57c8866..750f1f7169e6 100644
--- a/sound/soc/codecs/rt5575-spi.c
+++ b/sound/soc/codecs/rt5575-spi.c
@@ -93,7 +93,6 @@ static void rt5575_spi_burst_write(struct spi_device *spi, u32 addr, const u8 *t
int rt5575_spi_fw_load(struct spi_device *spi)
{
struct device *dev = &spi->dev;
- const struct firmware *firmware;
int i, ret;
static const char * const fw_path[] = {
"realtek/rt5575/rt5575_fw1.bin",
@@ -104,6 +103,7 @@ int rt5575_spi_fw_load(struct spi_device *spi)
static const u32 fw_addr[] = { 0x5f400000, 0x5f600000, 0x5f7fe000, 0x5f7ff000 };
for (i = 0; i < ARRAY_SIZE(fw_addr); i++) {
+ const struct firmware *firmware __free(firmware) = NULL;
ret = request_firmware(&firmware, fw_path[i], dev);
if (ret) {
dev_err(dev, "Request firmware failure: %d\n", ret);
@@ -111,7 +111,6 @@ int rt5575_spi_fw_load(struct spi_device *spi)
}
rt5575_spi_burst_write(spi, fw_addr[i], firmware->data, firmware->size);
- release_firmware(firmware);
}
return 0;
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index e7e39671a576..7313ea71c958 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -6,6 +6,7 @@
* Author: Bard Liao <bardliao@realtek.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -3323,93 +3324,90 @@ static void rt5645_jack_detect_work(struct work_struct *work)
if (!rt5645->component)
return;
- mutex_lock(&rt5645->jd_mutex);
-
- switch (rt5645->pdata.jd_mode) {
- case 0: /* Not using rt5645 JD */
- if (rt5645->gpiod_hp_det) {
- gpio_state = gpiod_get_value(rt5645->gpiod_hp_det);
- if (rt5645->pdata.inv_hp_pol)
- gpio_state ^= 1;
- dev_dbg(rt5645->component->dev, "gpio_state = %d\n",
- gpio_state);
- report = rt5645_jack_detect(rt5645->component, gpio_state);
+ scoped_guard(mutex, &rt5645->jd_mutex) {
+ switch (rt5645->pdata.jd_mode) {
+ case 0: /* Not using rt5645 JD */
+ if (rt5645->gpiod_hp_det) {
+ gpio_state = gpiod_get_value(rt5645->gpiod_hp_det);
+ if (rt5645->pdata.inv_hp_pol)
+ gpio_state ^= 1;
+ dev_dbg(rt5645->component->dev, "gpio_state = %d\n",
+ gpio_state);
+ report = rt5645_jack_detect(rt5645->component, gpio_state);
+ }
+ snd_soc_jack_report(rt5645->hp_jack,
+ report, SND_JACK_HEADPHONE);
+ snd_soc_jack_report(rt5645->mic_jack,
+ report, SND_JACK_MICROPHONE);
+ return;
+ case 4:
+ val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020;
+ break;
+ default: /* read rt5645 jd1_1 status */
+ val = snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000;
+ break;
}
- snd_soc_jack_report(rt5645->hp_jack,
- report, SND_JACK_HEADPHONE);
- snd_soc_jack_report(rt5645->mic_jack,
- report, SND_JACK_MICROPHONE);
- mutex_unlock(&rt5645->jd_mutex);
- return;
- case 4:
- val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020;
- break;
- default: /* read rt5645 jd1_1 status */
- val = snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000;
- break;
- }
-
- if (!val && (rt5645->jack_type == 0)) { /* jack in */
- report = rt5645_jack_detect(rt5645->component, 1);
- } else if (!val && rt5645->jack_type == SND_JACK_HEADSET) {
- /* for push button and jack out */
- btn_type = 0;
- if (snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x4) {
- /* button pressed */
- report = SND_JACK_HEADSET;
- btn_type = rt5645_button_detect(rt5645->component);
- /* rt5650 can report three kinds of button behavior,
- one click, double click and hold. However,
- currently we will report button pressed/released
- event. So all the three button behaviors are
- treated as button pressed. */
- switch (btn_type) {
- case 0x8000:
- case 0x4000:
- case 0x2000:
- report |= SND_JACK_BTN_0;
- break;
- case 0x1000:
- case 0x0800:
- case 0x0400:
- report |= SND_JACK_BTN_1;
- break;
- case 0x0200:
- case 0x0100:
- case 0x0080:
- report |= SND_JACK_BTN_2;
- break;
- case 0x0040:
- case 0x0020:
- case 0x0010:
- report |= SND_JACK_BTN_3;
- break;
- case 0x0000: /* unpressed */
- break;
- default:
- dev_err(rt5645->component->dev,
- "Unexpected button code 0x%04x\n",
- btn_type);
- break;
+ if (!val && rt5645->jack_type == 0) { /* jack in */
+ report = rt5645_jack_detect(rt5645->component, 1);
+ } else if (!val && rt5645->jack_type == SND_JACK_HEADSET) {
+ /* for push button and jack out */
+ btn_type = 0;
+ if (snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x4) {
+ /* button pressed */
+ report = SND_JACK_HEADSET;
+ btn_type = rt5645_button_detect(rt5645->component);
+ /*
+ * rt5650 can report three kinds of button behavior,
+ * one click, double click and hold. However,
+ * currently we will report button pressed/released
+ * event. So all the three button behaviors are
+ * treated as button pressed.
+ */
+ switch (btn_type) {
+ case 0x8000:
+ case 0x4000:
+ case 0x2000:
+ report |= SND_JACK_BTN_0;
+ break;
+ case 0x1000:
+ case 0x0800:
+ case 0x0400:
+ report |= SND_JACK_BTN_1;
+ break;
+ case 0x0200:
+ case 0x0100:
+ case 0x0080:
+ report |= SND_JACK_BTN_2;
+ break;
+ case 0x0040:
+ case 0x0020:
+ case 0x0010:
+ report |= SND_JACK_BTN_3;
+ break;
+ case 0x0000: /* unpressed */
+ break;
+ default:
+ dev_err(rt5645->component->dev,
+ "Unexpected button code 0x%04x\n",
+ btn_type);
+ break;
+ }
}
+ if (btn_type == 0)/* button release */
+ report = rt5645->jack_type;
+ else
+ mod_timer(&rt5645->btn_check_timer,
+ msecs_to_jiffies(100));
+ } else {
+ /* jack out */
+ report = 0;
+ snd_soc_component_update_bits(rt5645->component,
+ RT5645_INT_IRQ_ST, 0x1, 0x0);
+ rt5645_jack_detect(rt5645->component, 0);
}
- if (btn_type == 0)/* button release */
- report = rt5645->jack_type;
- else {
- mod_timer(&rt5645->btn_check_timer,
- msecs_to_jiffies(100));
- }
- } else {
- /* jack out */
- report = 0;
- snd_soc_component_update_bits(rt5645->component,
- RT5645_INT_IRQ_ST, 0x1, 0x0);
- rt5645_jack_detect(rt5645->component, 0);
}
- mutex_unlock(&rt5645->jd_mutex);
-
snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE);
snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE);
if (rt5645->en_button_func)
@@ -3522,9 +3520,15 @@ static int rt5645_suspend(struct snd_soc_component *component)
static int rt5645_resume(struct snd_soc_component *component)
{
struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+ int ret;
regcache_cache_only(rt5645->regmap, false);
- regcache_sync(rt5645->regmap);
+ ret = regcache_sync(rt5645->regmap);
+ if (ret) {
+ regcache_cache_only(rt5645->regmap, true);
+ regcache_mark_dirty(rt5645->regmap);
+ return ret;
+ }
return 0;
}
@@ -4335,9 +4339,15 @@ static int rt5645_sys_suspend(struct device *dev)
static int rt5645_sys_resume(struct device *dev)
{
struct rt5645_priv *rt5645 = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(rt5645->regmap, false);
- regcache_sync(rt5645->regmap);
+ ret = regcache_sync(rt5645->regmap);
+ if (ret) {
+ regcache_cache_only(rt5645->regmap, true);
+ regcache_mark_dirty(rt5645->regmap);
+ return ret;
+ }
if (rt5645->hp_jack) {
rt5645->jack_type = 0;
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index 48f57cd0920d..1d987472ba42 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -6,6 +6,7 @@
* Author: Bard Liao <bardliao@realtek.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -1208,7 +1209,7 @@ static void rt5665_jack_detect_handler(struct work_struct *work)
usleep_range(10000, 15000);
}
- mutex_lock(&rt5665->calibrate_mutex);
+ guard(mutex)(&rt5665->calibrate_mutex);
val = snd_soc_component_read(rt5665->component, RT5665_AJD1_CTRL) & 0x0010;
if (!val) {
@@ -1274,8 +1275,6 @@ static void rt5665_jack_detect_handler(struct work_struct *work)
schedule_delayed_work(&rt5665->jd_check_work, 0);
else
cancel_delayed_work_sync(&rt5665->jd_check_work);
-
- mutex_unlock(&rt5665->calibrate_mutex);
}
static const char * const rt5665_clk_sync[] = {
@@ -4564,7 +4563,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665)
{
int value, count;
- mutex_lock(&rt5665->calibrate_mutex);
+ guard(mutex)(&rt5665->calibrate_mutex);
regcache_cache_bypass(rt5665->regmap, true);
@@ -4601,7 +4600,8 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665)
pr_err("HP Calibration Failure\n");
regmap_write(rt5665->regmap, RT5665_RESET, 0);
regcache_cache_bypass(rt5665->regmap, false);
- goto out_unlock;
+ rt5665->calibration_done = true;
+ return;
}
count++;
@@ -4620,7 +4620,8 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665)
pr_err("MONO Calibration Failure\n");
regmap_write(rt5665->regmap, RT5665_RESET, 0);
regcache_cache_bypass(rt5665->regmap, false);
- goto out_unlock;
+ rt5665->calibration_done = true;
+ return;
}
count++;
@@ -4635,9 +4636,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665)
regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602);
regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120);
-out_unlock:
rt5665->calibration_done = true;
- mutex_unlock(&rt5665->calibrate_mutex);
}
static void rt5665_calibrate_handler(struct work_struct *work)
diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c
index fed6de40b8c8..4154bad27610 100644
--- a/sound/soc/codecs/rt5668.c
+++ b/sound/soc/codecs/rt5668.c
@@ -6,6 +6,7 @@
* Author: Bard Liao <bardliao@realtek.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -986,7 +987,7 @@ static void rt5668_jack_detect_handler(struct work_struct *work)
return;
}
- mutex_lock(&rt5668->calibrate_mutex);
+ guard(mutex)(&rt5668->calibrate_mutex);
val = snd_soc_component_read(rt5668->component, RT5668_AJD1_CTRL)
& RT5668_JDH_RS_MASK;
@@ -1053,8 +1054,6 @@ static void rt5668_jack_detect_handler(struct work_struct *work)
schedule_delayed_work(&rt5668->jd_check_work, 0);
else
cancel_delayed_work_sync(&rt5668->jd_check_work);
-
- mutex_unlock(&rt5668->calibrate_mutex);
}
static const struct snd_kcontrol_new rt5668_snd_controls[] = {
@@ -2356,7 +2355,7 @@ static void rt5668_calibrate(struct rt5668_priv *rt5668)
{
int value, count;
- mutex_lock(&rt5668->calibrate_mutex);
+ guard(mutex)(&rt5668->calibrate_mutex);
rt5668_reset(rt5668->regmap);
regmap_write(rt5668->regmap, RT5668_PWR_ANLG_1, 0xa2bf);
@@ -2400,9 +2399,6 @@ static void rt5668_calibrate(struct rt5668_priv *rt5668)
/* restore settings */
regmap_write(rt5668->regmap, RT5668_STO1_ADC_MIXER, 0xc0c4);
regmap_write(rt5668->regmap, RT5668_PWR_DIG_1, 0x0000);
-
- mutex_unlock(&rt5668->calibrate_mutex);
-
}
static int rt5668_i2c_probe(struct i2c_client *i2c)
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
index 1bcafd5f4468..ebc527115ea5 100644
--- a/sound/soc/codecs/rt5677-spi.c
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -6,6 +6,7 @@
* Author: Oder Chiou <oder_chiou@realtek.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/spi/spi.h>
@@ -133,9 +134,8 @@ static int rt5677_spi_hw_params(
struct rt5677_dsp *rt5677_dsp =
snd_soc_component_get_drvdata(component);
- mutex_lock(&rt5677_dsp->dma_lock);
+ guard(mutex)(&rt5677_dsp->dma_lock);
rt5677_dsp->substream = substream;
- mutex_unlock(&rt5677_dsp->dma_lock);
return 0;
}
@@ -147,9 +147,8 @@ static int rt5677_spi_hw_free(
struct rt5677_dsp *rt5677_dsp =
snd_soc_component_get_drvdata(component);
- mutex_lock(&rt5677_dsp->dma_lock);
+ guard(mutex)(&rt5677_dsp->dma_lock);
rt5677_dsp->substream = NULL;
- mutex_unlock(&rt5677_dsp->dma_lock);
return 0;
}
@@ -311,17 +310,17 @@ static void rt5677_spi_copy_work(struct work_struct *work)
int ret = 0;
/* Ensure runtime->dma_area buffer does not go away while copying. */
- mutex_lock(&rt5677_dsp->dma_lock);
+ guard(mutex)(&rt5677_dsp->dma_lock);
if (!rt5677_dsp->substream) {
dev_err(rt5677_dsp->dev, "No pcm substream\n");
- goto done;
+ return;
}
runtime = rt5677_dsp->substream->runtime;
if (rt5677_spi_mic_write_offset(&mic_write_offset)) {
dev_err(rt5677_dsp->dev, "No mic_write_offset\n");
- goto done;
+ return;
}
/* If this is the first time that we've asked for streaming data after
@@ -355,7 +354,7 @@ static void rt5677_spi_copy_work(struct work_struct *work)
ret = rt5677_spi_copy(rt5677_dsp, copy_bytes);
if (ret) {
dev_err(rt5677_dsp->dev, "Copy failed %d\n", ret);
- goto done;
+ return;
}
rt5677_dsp->avail_bytes += copy_bytes;
if (rt5677_dsp->avail_bytes >= period_bytes) {
@@ -367,8 +366,6 @@ static void rt5677_spi_copy_work(struct work_struct *work)
delay = bytes_to_frames(runtime, period_bytes) / runtime->rate;
schedule_delayed_work(&rt5677_dsp->copy_work, secs_to_jiffies(delay));
-done:
- mutex_unlock(&rt5677_dsp->dma_lock);
}
static int rt5677_spi_pcm_new(struct snd_soc_component *component,
@@ -507,10 +504,8 @@ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len)
header[3] = ((addr + offset) & 0x0000ff00) >> 8;
header[4] = ((addr + offset) & 0x000000ff) >> 0;
- mutex_lock(&spi_mutex);
- status |= spi_sync(g_spi, &m);
- mutex_unlock(&spi_mutex);
-
+ scoped_guard(mutex, &spi_mutex)
+ status |= spi_sync(g_spi, &m);
/* Copy data back to caller buffer */
rt5677_spi_reverse(cb + offset, len - offset, body, t[1].len);
@@ -564,9 +559,8 @@ int rt5677_spi_write(u32 addr, const void *txbuf, size_t len)
offset += t.len;
t.len += RT5677_SPI_HEADER + 1;
- mutex_lock(&spi_mutex);
- status |= spi_sync(g_spi, &m);
- mutex_unlock(&spi_mutex);
+ scoped_guard(mutex, &spi_mutex)
+ status |= spi_sync(g_spi, &m);
}
return status;
}
@@ -591,10 +585,10 @@ void rt5677_spi_hotword_detected(void)
return;
}
- mutex_lock(&rt5677_dsp->dma_lock);
- dev_info(rt5677_dsp->dev, "Hotword detected\n");
- rt5677_dsp->new_hotword = true;
- mutex_unlock(&rt5677_dsp->dma_lock);
+ scoped_guard(mutex, &rt5677_dsp->dma_lock) {
+ dev_info(rt5677_dsp->dev, "Hotword detected\n");
+ rt5677_dsp->new_hotword = true;
+ }
schedule_delayed_work(&rt5677_dsp->copy_work, 0);
}
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index ac084ca008f3..4757017cc83d 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -6,6 +6,8 @@
* Author: Oder Chiou <oder_chiou@realtek.com>
*/
+#include <linux/cleanup.h>
+#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/fs.h>
@@ -563,46 +565,43 @@ static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677,
struct snd_soc_component *component = rt5677->component;
int ret;
- mutex_lock(&rt5677->dsp_cmd_lock);
+ guard(mutex)(&rt5677->dsp_cmd_lock);
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB,
addr >> 16);
if (ret < 0) {
dev_err(component->dev, "Failed to set addr msb value: %d\n", ret);
- goto err;
+ return ret;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB,
addr & 0xffff);
if (ret < 0) {
dev_err(component->dev, "Failed to set addr lsb value: %d\n", ret);
- goto err;
+ return ret;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB,
value >> 16);
if (ret < 0) {
dev_err(component->dev, "Failed to set data msb value: %d\n", ret);
- goto err;
+ return ret;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB,
value & 0xffff);
if (ret < 0) {
dev_err(component->dev, "Failed to set data lsb value: %d\n", ret);
- goto err;
+ return ret;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE,
opcode);
if (ret < 0) {
dev_err(component->dev, "Failed to set op code value: %d\n", ret);
- goto err;
+ return ret;
}
-err:
- mutex_unlock(&rt5677->dsp_cmd_lock);
-
return ret;
}
@@ -622,36 +621,33 @@ static int rt5677_dsp_mode_i2c_read_addr(
int ret;
unsigned int msb, lsb;
- mutex_lock(&rt5677->dsp_cmd_lock);
+ guard(mutex)(&rt5677->dsp_cmd_lock);
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB,
addr >> 16);
if (ret < 0) {
dev_err(component->dev, "Failed to set addr msb value: %d\n", ret);
- goto err;
+ return ret;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB,
addr & 0xffff);
if (ret < 0) {
dev_err(component->dev, "Failed to set addr lsb value: %d\n", ret);
- goto err;
+ return ret;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE,
0x0002);
if (ret < 0) {
dev_err(component->dev, "Failed to set op code value: %d\n", ret);
- goto err;
+ return ret;
}
regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, &msb);
regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, &lsb);
*value = (msb << 16) | lsb;
-err:
- mutex_unlock(&rt5677->dsp_cmd_lock);
-
return ret;
}
@@ -853,11 +849,11 @@ static int rt5677_parse_and_load_dsp(struct rt5677_priv *rt5677, const u8 *buf,
static int rt5677_load_dsp_from_file(struct rt5677_priv *rt5677)
{
- const struct firmware *fwp;
struct device *dev = rt5677->component->dev;
- int ret = 0;
+ int ret;
/* Load dsp firmware from rt5677_elf_vad file */
+ const struct firmware *fwp __free(firmware) = NULL;
ret = request_firmware(&fwp, "rt5677_elf_vad", dev);
if (ret) {
dev_err(dev, "Request rt5677_elf_vad failed %d\n", ret);
@@ -865,9 +861,7 @@ static int rt5677_load_dsp_from_file(struct rt5677_priv *rt5677)
}
dev_info(dev, "Requested rt5677_elf_vad (%zu)\n", fwp->size);
- ret = rt5677_parse_and_load_dsp(rt5677, fwp->data, fwp->size);
- release_firmware(fwp);
- return ret;
+ return rt5677_parse_and_load_dsp(rt5677, fwp->data, fwp->size);
}
static int rt5677_set_dsp_vad(struct snd_soc_component *component, bool on)
@@ -940,21 +934,20 @@ static void rt5677_dsp_work(struct work_struct *work)
activity = false;
/* Don't turn off the DSP while handling irqs */
- mutex_lock(&rt5677->irq_lock);
- /* Set DSP CPU to Stop */
- regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1,
- RT5677_PWR_DSP_CPU, RT5677_PWR_DSP_CPU);
+ scoped_guard(mutex, &rt5677->irq_lock) {
+ /* Set DSP CPU to Stop */
+ regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1,
+ RT5677_PWR_DSP_CPU, RT5677_PWR_DSP_CPU);
- rt5677_set_dsp_mode(rt5677, false);
+ rt5677_set_dsp_mode(rt5677, false);
- /* Disable and clear VAD interrupt */
- regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, 0x2184);
-
- /* Set GPIO1 pin back to be IRQ output for jack detect */
- regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1,
- RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ);
+ /* Disable and clear VAD interrupt */
+ regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, 0x2184);
- mutex_unlock(&rt5677->irq_lock);
+ /* Set GPIO1 pin back to be IRQ output for jack detect */
+ regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1,
+ RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ);
+ }
}
}
@@ -4767,6 +4760,21 @@ static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
return rt5677_update_gpio_bits(rt5677, offset, m, v);
}
+static int rt5677_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+ struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+ unsigned int shift = RT5677_GPIOx_DIR_SFT + (offset % 5) * 3;
+ unsigned int bank = offset / 5;
+ unsigned int reg = bank ? RT5677_GPIO_CTRL3 : RT5677_GPIO_CTRL2;
+ int ret;
+
+ ret = regmap_test_bits(rt5677->regmap, reg, BIT(shift));
+ if (ret < 0)
+ return ret;
+
+ return ret ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
+}
+
/*
* Configures the GPIO as
* 0 - floating
@@ -4834,6 +4842,7 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset)
static const struct gpio_chip rt5677_template_chip = {
.label = RT5677_DRV_NAME,
.owner = THIS_MODULE,
+ .get_direction = rt5677_gpio_get_direction,
.direction_output = rt5677_gpio_direction_out,
.set = rt5677_gpio_set,
.direction_input = rt5677_gpio_direction_in,
@@ -4980,11 +4989,11 @@ static int rt5677_read(void *context, unsigned int reg, unsigned int *val)
if (rt5677->is_dsp_mode) {
if (reg > 0xff) {
- mutex_lock(&rt5677->dsp_pri_lock);
- rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
- reg & 0xff);
- rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val);
- mutex_unlock(&rt5677->dsp_pri_lock);
+ scoped_guard(mutex, &rt5677->dsp_pri_lock) {
+ rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
+ reg & 0xff);
+ rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val);
+ }
} else {
rt5677_dsp_mode_i2c_read(rt5677, reg, val);
}
@@ -5002,12 +5011,12 @@ static int rt5677_write(void *context, unsigned int reg, unsigned int val)
if (rt5677->is_dsp_mode) {
if (reg > 0xff) {
- mutex_lock(&rt5677->dsp_pri_lock);
- rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
- reg & 0xff);
- rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA,
- val);
- mutex_unlock(&rt5677->dsp_pri_lock);
+ scoped_guard(mutex, &rt5677->dsp_pri_lock) {
+ rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
+ reg & 0xff);
+ rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA,
+ val);
+ }
} else {
rt5677_dsp_mode_i2c_write(rt5677, reg, val);
}
@@ -5399,7 +5408,7 @@ static void rt5677_resume_irq_check(struct work_struct *work)
* Without this explicit check, unplug the headset right after suspend
* starts, then after resume the headset is still shown as plugged in.
*/
- mutex_lock(&rt5677->irq_lock);
+ guard(mutex)(&rt5677->irq_lock);
for (i = 0; i < RT5677_IRQ_NUM; i++) {
if (rt5677->irq_en & rt5677_irq_descs[i].enable_mask) {
virq = irq_find_mapping(rt5677->domain, i);
@@ -5407,7 +5416,6 @@ static void rt5677_resume_irq_check(struct work_struct *work)
handle_nested_irq(virq);
}
}
- mutex_unlock(&rt5677->irq_lock);
}
static void rt5677_irq_bus_lock(struct irq_data *data)
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index dec8c2147d68..23c7d2a9dbee 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -6,6 +6,7 @@
// Author: Oder Chiou <oder_chiou@realtek.com>
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -410,7 +411,9 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
if (rt5682->first_hw_init) {
regcache_cache_bypass(rt5682->regmap, false);
regcache_mark_dirty(rt5682->regmap);
- regcache_sync(rt5682->regmap);
+ ret = regcache_sync(rt5682->regmap);
+ if (ret)
+ goto err_sync;
/* volatile registers */
regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_2,
@@ -472,8 +475,16 @@ reinit:
/* Mark Slave initialization complete */
rt5682->hw_init = true;
rt5682->first_hw_init = true;
+ goto out;
+
+err_sync:
+ regcache_cache_bypass(rt5682->regmap, false);
+ regcache_cache_only(rt5682->sdw_regmap, true);
+ regcache_cache_only(rt5682->regmap, true);
+ regcache_mark_dirty(rt5682->regmap);
err_nodev:
+out:
pm_runtime_put_autosuspend(&slave->dev);
dev_dbg(&slave->dev, "%s hw_init complete: %d\n", __func__, ret);
@@ -660,12 +671,11 @@ static int rt5682_interrupt_callback(struct sdw_slave *slave,
dev_dbg(&slave->dev,
"%s control_port_stat=%x", __func__, status->control_port);
- mutex_lock(&rt5682->disable_irq_lock);
+ guard(mutex)(&rt5682->disable_irq_lock);
if (status->control_port & 0x4 && !rt5682->disable_irq) {
mod_delayed_work(system_power_efficient_wq,
&rt5682->jack_detect_work, msecs_to_jiffies(rt5682->irq_work_delay_time));
}
- mutex_unlock(&rt5682->disable_irq_lock);
return 0;
}
@@ -736,11 +746,11 @@ static int rt5682_dev_system_suspend(struct device *dev)
* deferred work completes and before the parent disables
* interrupts on the link
*/
- mutex_lock(&rt5682->disable_irq_lock);
- rt5682->disable_irq = true;
- ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
- SDW_SCP_INT1_IMPL_DEF, 0);
- mutex_unlock(&rt5682->disable_irq_lock);
+ scoped_guard(mutex, &rt5682->disable_irq_lock) {
+ rt5682->disable_irq = true;
+ ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
+ SDW_SCP_INT1_IMPL_DEF, 0);
+ }
if (ret < 0) {
/* log but don't prevent suspend from happening */
@@ -760,12 +770,12 @@ static int rt5682_dev_resume(struct device *dev)
return 0;
if (!slave->unattach_request) {
- mutex_lock(&rt5682->disable_irq_lock);
- if (rt5682->disable_irq == true) {
- sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF);
- rt5682->disable_irq = false;
+ scoped_guard(mutex, &rt5682->disable_irq_lock) {
+ if (rt5682->disable_irq) {
+ sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF);
+ rt5682->disable_irq = false;
+ }
}
- mutex_unlock(&rt5682->disable_irq_lock);
}
ret = sdw_slave_wait_for_init(slave, RT5682_PROBE_TIMEOUT);
@@ -776,7 +786,13 @@ static int rt5682_dev_resume(struct device *dev)
regcache_cache_only(rt5682->sdw_regmap, false);
regcache_cache_only(rt5682->regmap, false);
- regcache_sync(rt5682->regmap);
+ ret = regcache_sync(rt5682->regmap);
+ if (ret) {
+ regcache_cache_only(rt5682->sdw_regmap, true);
+ regcache_cache_only(rt5682->regmap, true);
+ regcache_mark_dirty(rt5682->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index 4b82e07d3b2c..6f7e68c20d13 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -6,6 +6,7 @@
// Author: Bard Liao <bardliao@realtek.com>
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -3125,7 +3126,7 @@ void rt5682_calibrate(struct rt5682_priv *rt5682)
{
int value, count;
- mutex_lock(&rt5682->calibrate_mutex);
+ guard(mutex)(&rt5682->calibrate_mutex);
rt5682_reset(rt5682);
regmap_write(rt5682->regmap, RT5682_I2C_CTRL, 0x000f);
@@ -3175,8 +3176,6 @@ void rt5682_calibrate(struct rt5682_priv *rt5682)
regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005);
regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4);
regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0c0c);
-
- mutex_unlock(&rt5682->calibrate_mutex);
}
EXPORT_SYMBOL_GPL(rt5682_calibrate);
diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c
index 3624067950c0..34997cfb465b 100644
--- a/sound/soc/codecs/rt5682s.c
+++ b/sound/soc/codecs/rt5682s.c
@@ -6,6 +6,7 @@
// Author: Derek Fang <derek.fang@realtek.com>
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -648,7 +649,7 @@ static void rt5682s_sar_power_mode(struct snd_soc_component *component, int mode
{
struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
- mutex_lock(&rt5682s->sar_mutex);
+ guard(mutex)(&rt5682s->sar_mutex);
switch (mode) {
case SAR_PWR_SAVING:
@@ -695,8 +696,6 @@ static void rt5682s_sar_power_mode(struct snd_soc_component *component, int mode
dev_err(component->dev, "Invalid SAR Power mode: %d\n", mode);
break;
}
-
- mutex_unlock(&rt5682s->sar_mutex);
}
static void rt5682s_enable_push_button_irq(struct snd_soc_component *component)
@@ -2534,7 +2533,7 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw)
if (!rt5682s_clk_check(rt5682s))
return -EINVAL;
- mutex_lock(&rt5682s->wclk_mutex);
+ guard(mutex)(&rt5682s->wclk_mutex);
snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1,
RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB,
@@ -2556,8 +2555,6 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw)
rt5682s->wclk_enabled = 1;
- mutex_unlock(&rt5682s->wclk_mutex);
-
return 0;
}
@@ -2570,7 +2567,7 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw)
if (!rt5682s_clk_check(rt5682s))
return;
- mutex_lock(&rt5682s->wclk_mutex);
+ guard(mutex)(&rt5682s->wclk_mutex);
if (!rt5682s->jack_type)
snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1,
@@ -2585,8 +2582,6 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw)
rt5682s_set_pllb_power(rt5682s, 0);
rt5682s->wclk_enabled = 0;
-
- mutex_unlock(&rt5682s->wclk_mutex);
}
static unsigned long rt5682s_wclk_recalc_rate(struct clk_hw *hw,
@@ -2997,7 +2992,7 @@ static void rt5682s_calibrate(struct rt5682s_priv *rt5682s)
{
unsigned int count, value;
- mutex_lock(&rt5682s->calibrate_mutex);
+ guard(mutex)(&rt5682s->calibrate_mutex);
regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0xaa80);
usleep_range(15000, 20000);
@@ -3034,8 +3029,6 @@ static void rt5682s_calibrate(struct rt5682s_priv *rt5682s)
regmap_write(rt5682s->regmap, RT5682S_PWR_DIG_1, 0x00c0);
regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0x0800);
regmap_write(rt5682s->regmap, RT5682S_GLB_CLK, 0x0000);
-
- mutex_unlock(&rt5682s->calibrate_mutex);
}
static const struct regmap_config rt5682s_regmap = {
diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c
index a451d5d1f8ab..3ba0cc37acd9 100644
--- a/sound/soc/codecs/rt700-sdw.c
+++ b/sound/soc/codecs/rt700-sdw.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/soundwire/sdw.h>
@@ -415,12 +416,11 @@ static int rt700_interrupt_callback(struct sdw_slave *slave,
dev_dbg(&slave->dev,
"%s control_port_stat=%x", __func__, status->control_port);
- mutex_lock(&rt700->disable_irq_lock);
+ guard(mutex)(&rt700->disable_irq_lock);
if (status->control_port & 0x4 && !rt700->disable_irq) {
mod_delayed_work(system_power_efficient_wq,
&rt700->jack_detect_work, msecs_to_jiffies(250));
}
- mutex_unlock(&rt700->disable_irq_lock);
return 0;
}
@@ -458,10 +458,8 @@ static void rt700_sdw_remove(struct sdw_slave *slave)
{
struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev);
- if (rt700->hw_init) {
- cancel_delayed_work_sync(&rt700->jack_detect_work);
- cancel_delayed_work_sync(&rt700->jack_btn_check_work);
- }
+ cancel_delayed_work_sync(&rt700->jack_detect_work);
+ cancel_delayed_work_sync(&rt700->jack_btn_check_work);
pm_runtime_disable(&slave->dev);
}
@@ -501,11 +499,11 @@ static int rt700_dev_system_suspend(struct device *dev)
* deferred work completes and before the parent disables
* interrupts on the link
*/
- mutex_lock(&rt700->disable_irq_lock);
- rt700->disable_irq = true;
- ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
- SDW_SCP_INT1_IMPL_DEF, 0);
- mutex_unlock(&rt700->disable_irq_lock);
+ scoped_guard(mutex, &rt700->disable_irq_lock) {
+ rt700->disable_irq = true;
+ ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
+ SDW_SCP_INT1_IMPL_DEF, 0);
+ }
if (ret < 0) {
/* log but don't prevent suspend from happening */
diff --git a/sound/soc/codecs/rt700-sdw.h b/sound/soc/codecs/rt700-sdw.h
index 4ad0dcfd16fd..002f94493b01 100644
--- a/sound/soc/codecs/rt700-sdw.h
+++ b/sound/soc/codecs/rt700-sdw.h
@@ -313,17 +313,16 @@ static const struct reg_default rt700_reg_defaults[] = {
{ 0x3122, 0x0000 },
{ 0x3123, 0x0000 },
{ 0x7303, 0x0057 },
- { 0x7303, 0x0057 },
- { 0x8383, 0x0057 },
{ 0x7308, 0x0097 },
- { 0x8388, 0x0097 },
{ 0x7309, 0x0097 },
- { 0x8389, 0x0097 },
{ 0x7312, 0x0000 },
- { 0x8392, 0x0000 },
{ 0x7313, 0x0000 },
- { 0x8393, 0x0000 },
{ 0x7319, 0x0000 },
+ { 0x8383, 0x0057 },
+ { 0x8388, 0x0097 },
+ { 0x8389, 0x0097 },
+ { 0x8392, 0x0000 },
+ { 0x8393, 0x0000 },
{ 0x8399, 0x0000 },
{ 0x75201a, 0x8003 },
{ 0x752045, 0x5289 },
diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c
index e028a1c3a9ac..e292b28b029e 100644
--- a/sound/soc/codecs/rt711-sdca-sdw.c
+++ b/sound/soc/codecs/rt711-sdca-sdw.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/soundwire/sdw_registers.h>
@@ -415,13 +416,13 @@ static int rt711_sdca_dev_system_suspend(struct device *dev)
* deferred work completes and before the parent disables
* interrupts on the link
*/
- mutex_lock(&rt711_sdca->disable_irq_lock);
- rt711_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(&rt711_sdca->disable_irq_lock);
+ scoped_guard(mutex, &rt711_sdca->disable_irq_lock) {
+ rt711_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);
+ }
if (ret1 < 0 || ret2 < 0) {
/* log but don't prevent suspend from happening */
@@ -443,13 +444,15 @@ static int rt711_sdca_dev_resume(struct device *dev)
return 0;
if (!slave->unattach_request) {
- mutex_lock(&rt711->disable_irq_lock);
- if (rt711->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);
- rt711->disable_irq = false;
+ scoped_guard(mutex, &rt711->disable_irq_lock) {
+ if (rt711->disable_irq) {
+ 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);
+ rt711->disable_irq = false;
+ }
}
- mutex_unlock(&rt711->disable_irq_lock);
}
ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT);
diff --git a/sound/soc/codecs/rt711-sdca-sdw.h b/sound/soc/codecs/rt711-sdca-sdw.h
index 0d774e473ab9..9aa22b52d556 100644
--- a/sound/soc/codecs/rt711-sdca-sdw.h
+++ b/sound/soc/codecs/rt711-sdca-sdw.h
@@ -58,12 +58,12 @@ static const struct reg_default rt711_sdca_reg_defaults[] = {
{ 0x2f0f, 0x00 },
{ 0x2f50, 0x03 },
{ 0x2f5a, 0x00 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_CS01, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDE28, RT711_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_CS01, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
};
@@ -86,14 +86,14 @@ static const struct reg_default rt711_sdca_mbq_defaults[] = {
{ 0x610003f, 0xff12 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_L), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_L), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
};
#endif /* __RT711_SDW_SDCA_H__ */
diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c
index 3a26c782d800..9781f289f8ad 100644
--- a/sound/soc/codecs/rt711-sdca.c
+++ b/sound/soc/codecs/rt711-sdca.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -450,7 +451,7 @@ io_error:
static void rt711_sdca_jack_init(struct rt711_sdca_priv *rt711)
{
- mutex_lock(&rt711->calibrate_mutex);
+ guard(mutex)(&rt711->calibrate_mutex);
if (rt711->hs_jack) {
/* Enable HID1 event & set button RTC mode */
@@ -515,8 +516,6 @@ static void rt711_sdca_jack_init(struct rt711_sdca_priv *rt711)
dev_dbg(&rt711->slave->dev, "in %s disable\n", __func__);
}
-
- mutex_unlock(&rt711->calibrate_mutex);
}
static int rt711_sdca_set_jack_detect(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c
index a0c6a9efa840..4ad2b1da1954 100644
--- a/sound/soc/codecs/rt711-sdw.c
+++ b/sound/soc/codecs/rt711-sdw.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/soundwire/sdw.h>
@@ -422,12 +423,11 @@ static int rt711_interrupt_callback(struct sdw_slave *slave,
dev_dbg(&slave->dev,
"%s control_port_stat=%x", __func__, status->control_port);
- mutex_lock(&rt711->disable_irq_lock);
+ guard(mutex)(&rt711->disable_irq_lock);
if (status->control_port & 0x4 && !rt711->disable_irq) {
mod_delayed_work(system_power_efficient_wq,
&rt711->jack_detect_work, msecs_to_jiffies(250));
}
- mutex_unlock(&rt711->disable_irq_lock);
return 0;
}
@@ -509,11 +509,11 @@ static int rt711_dev_system_suspend(struct device *dev)
* deferred work completes and before the parent disables
* interrupts on the link
*/
- mutex_lock(&rt711->disable_irq_lock);
- rt711->disable_irq = true;
- ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
- SDW_SCP_INT1_IMPL_DEF, 0);
- mutex_unlock(&rt711->disable_irq_lock);
+ scoped_guard(mutex, &rt711->disable_irq_lock) {
+ rt711->disable_irq = true;
+ ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
+ SDW_SCP_INT1_IMPL_DEF, 0);
+ }
if (ret < 0) {
/* log but don't prevent suspend from happening */
@@ -535,12 +535,12 @@ static int rt711_dev_resume(struct device *dev)
return 0;
if (!slave->unattach_request) {
- mutex_lock(&rt711->disable_irq_lock);
- if (rt711->disable_irq == true) {
- sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF);
- rt711->disable_irq = false;
+ scoped_guard(mutex, &rt711->disable_irq_lock) {
+ if (rt711->disable_irq) {
+ sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF);
+ rt711->disable_irq = false;
+ }
}
- mutex_unlock(&rt711->disable_irq_lock);
}
ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT);
diff --git a/sound/soc/codecs/rt711-sdw.h b/sound/soc/codecs/rt711-sdw.h
index 6acf9858330d..82da0e62d9d7 100644
--- a/sound/soc/codecs/rt711-sdw.h
+++ b/sound/soc/codecs/rt711-sdw.h
@@ -256,16 +256,16 @@ static const struct reg_default rt711_reg_defaults[] = {
{ 0x3122, 0x00 },
{ 0x3123, 0x00 },
{ 0x7303, 0x57 },
- { 0x8383, 0x57 },
{ 0x7308, 0x97 },
- { 0x8388, 0x97 },
{ 0x7309, 0x97 },
- { 0x8389, 0x97 },
{ 0x7312, 0x00 },
- { 0x8392, 0x00 },
{ 0x7313, 0x00 },
- { 0x8393, 0x00 },
{ 0x7319, 0x00 },
+ { 0x8383, 0x57 },
+ { 0x8388, 0x97 },
+ { 0x8389, 0x97 },
+ { 0x8392, 0x00 },
+ { 0x8393, 0x00 },
{ 0x8399, 0x00 },
{ 0x752008, 0xa807 },
{ 0x752009, 0x1029 },
diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c
index 5dbe9b67703e..3e49c3d0f25b 100644
--- a/sound/soc/codecs/rt711.c
+++ b/sound/soc/codecs/rt711.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -89,24 +90,24 @@ static int rt711_calibration(struct rt711_priv *rt711)
struct regmap *regmap = rt711->regmap;
int ret = 0;
- mutex_lock(&rt711->calibrate_mutex);
+ guard(mutex)(&rt711->calibrate_mutex);
regmap_write(rt711->regmap,
- RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
+ RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
dev = regmap_get_device(regmap);
/* Calibration manual mode */
rt711_index_update_bits(regmap, RT711_VENDOR_REG, RT711_FSM_CTL,
- 0xf, 0x0);
+ 0xf, 0x0);
/* trigger */
rt711_index_update_bits(regmap, RT711_VENDOR_CALI,
- RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER,
- RT711_DAC_DC_CALI_TRIGGER);
+ RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER,
+ RT711_DAC_DC_CALI_TRIGGER);
/* wait for calibration process */
rt711_index_read(regmap, RT711_VENDOR_CALI,
- RT711_DAC_DC_CALI_CTL1, &val);
+ RT711_DAC_DC_CALI_CTL1, &val);
while (val & RT711_DAC_DC_CALI_TRIGGER) {
if (loop >= 500) {
@@ -119,16 +120,15 @@ static int rt711_calibration(struct rt711_priv *rt711)
usleep_range(10000, 11000);
rt711_index_read(regmap, RT711_VENDOR_CALI,
- RT711_DAC_DC_CALI_CTL1, &val);
+ RT711_DAC_DC_CALI_CTL1, &val);
}
/* depop mode */
rt711_index_update_bits(regmap, RT711_VENDOR_REG,
- RT711_FSM_CTL, 0xf, RT711_DEPOP_CTL);
+ RT711_FSM_CTL, 0xf, RT711_DEPOP_CTL);
regmap_write(rt711->regmap,
- RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
- mutex_unlock(&rt711->calibrate_mutex);
+ RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
dev_dbg(dev, "%s calibration complete, ret=%d\n", __func__, ret);
return ret;
@@ -362,24 +362,24 @@ static void rt711_jack_init(struct rt711_priv *rt711)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt711->component);
- mutex_lock(&rt711->calibrate_mutex);
+ guard(mutex)(&rt711->calibrate_mutex);
/* power on */
if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt711->regmap,
- RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
+ RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
if (rt711->hs_jack) {
/* unsolicited response & IRQ control */
regmap_write(rt711->regmap,
- RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x82);
+ RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x82);
regmap_write(rt711->regmap,
- RT711_SET_HP_UNSOLICITED_ENABLE, 0x81);
+ RT711_SET_HP_UNSOLICITED_ENABLE, 0x81);
regmap_write(rt711->regmap,
- RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x83);
+ RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x83);
rt711_index_write(rt711->regmap, RT711_VENDOR_REG,
- 0x10, 0x2420);
+ 0x10, 0x2420);
rt711_index_write(rt711->regmap, RT711_VENDOR_REG,
- 0x19, 0x2e11);
+ 0x19, 0x2e11);
switch (rt711->jd_src) {
case RT711_JD1:
@@ -449,8 +449,7 @@ static void rt711_jack_init(struct rt711_priv *rt711)
/* power off */
if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt711->regmap,
- RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
- mutex_unlock(&rt711->calibrate_mutex);
+ RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
}
static int rt711_set_jack_detect(struct snd_soc_component *component,
@@ -511,7 +510,7 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol,
unsigned int read_ll, read_rl;
int i;
- mutex_lock(&rt711->calibrate_mutex);
+ guard(mutex)(&rt711->calibrate_mutex);
/* Can't use update bit function, so read the original value first */
addr_h = mc->reg;
@@ -599,7 +598,6 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol,
regmap_write(rt711->regmap,
RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
- mutex_unlock(&rt711->calibrate_mutex);
return 0;
}
@@ -908,11 +906,11 @@ static int rt711_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- mutex_lock(&rt711->calibrate_mutex);
- regmap_write(rt711->regmap,
- RT711_SET_AUDIO_POWER_STATE,
- AC_PWRST_D3);
- mutex_unlock(&rt711->calibrate_mutex);
+ scoped_guard(mutex, &rt711->calibrate_mutex) {
+ regmap_write(rt711->regmap,
+ RT711_SET_AUDIO_POWER_STATE,
+ AC_PWRST_D3);
+ }
break;
default:
diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c
index 85779547653e..8860d81134e7 100644
--- a/sound/soc/codecs/rt712-sdca-dmic.c
+++ b/sound/soc/codecs/rt712-sdca-dmic.c
@@ -916,10 +916,23 @@ static int rt712_sdca_dmic_dev_resume(struct device *dev)
}
regcache_cache_only(rt712->regmap, false);
- regcache_sync(rt712->regmap);
+ ret = regcache_sync(rt712->regmap);
+ if (ret)
+ goto err_sync;
+
regcache_cache_only(rt712->mbq_regmap, false);
- regcache_sync(rt712->mbq_regmap);
+ ret = regcache_sync(rt712->mbq_regmap);
+ if (ret)
+ goto err_sync;
+
return 0;
+
+err_sync:
+ regcache_cache_only(rt712->regmap, true);
+ regcache_cache_only(rt712->mbq_regmap, true);
+ regcache_mark_dirty(rt712->regmap);
+ regcache_mark_dirty(rt712->mbq_regmap);
+ return ret;
}
static const struct dev_pm_ops rt712_sdca_dmic_pm = {
diff --git a/sound/soc/codecs/rt712-sdca-dmic.h b/sound/soc/codecs/rt712-sdca-dmic.h
index 110154e74efe..2f08e58ed519 100644
--- a/sound/soc/codecs/rt712-sdca-dmic.h
+++ b/sound/soc/codecs/rt712-sdca-dmic.h
@@ -36,6 +36,7 @@ struct rt712_sdca_dmic_kctrl_priv {
#define CH_03 0x03
#define CH_04 0x04
+/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */
static const struct reg_default rt712_sdca_dmic_reg_defaults[] = {
{ 0x201a, 0x00 },
{ 0x201b, 0x00 },
@@ -72,15 +73,16 @@ static const struct reg_default rt712_sdca_dmic_reg_defaults[] = {
{ 0x2f59, 0x07 },
{ 0x3201, 0x01 },
{ 0x320c, 0x00 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_IT26, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_03), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_04), 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_IT26, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
};
+/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */
static const struct reg_default rt712_sdca_dmic_mbq_defaults[] = {
{ 0x0590001e, 0x0020 },
{ 0x06100000, 0x0010 },
diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c
index 70d661ce2ef2..c50e74e20a88 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/module.h>
@@ -427,13 +428,13 @@ static int rt712_sdca_dev_system_suspend(struct device *dev)
* deferred work completes and before the parent disables
* interrupts on the link
*/
- mutex_lock(&rt712_sdca->disable_irq_lock);
- rt712_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(&rt712_sdca->disable_irq_lock);
+ scoped_guard(mutex, &rt712_sdca->disable_irq_lock) {
+ rt712_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);
+ }
if (ret1 < 0 || ret2 < 0) {
/* log but don't prevent suspend from happening */
@@ -455,14 +456,15 @@ static int rt712_sdca_dev_resume(struct device *dev)
return 0;
if (!slave->unattach_request) {
- mutex_lock(&rt712->disable_irq_lock);
- if (rt712->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);
- rt712->disable_irq = false;
+ scoped_guard(mutex, &rt712->disable_irq_lock) {
+ if (rt712->disable_irq) {
+ 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);
+ rt712->disable_irq = false;
+ }
}
- mutex_unlock(&rt712->disable_irq_lock);
}
ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT);
@@ -472,9 +474,20 @@ static int rt712_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(rt712->regmap, false);
- regcache_sync(rt712->regmap);
+ ret = regcache_sync(rt712->regmap);
+ if (ret) {
+ regcache_cache_only(rt712->regmap, true);
+ return ret;
+ }
+
regcache_cache_only(rt712->mbq_regmap, false);
- regcache_sync(rt712->mbq_regmap);
+ ret = regcache_sync(rt712->mbq_regmap);
+ if (ret) {
+ regcache_cache_only(rt712->mbq_regmap, true);
+ regcache_cache_only(rt712->regmap, true);
+ return ret;
+ }
+
return 0;
}
diff --git a/sound/soc/codecs/rt712-sdca-sdw.h b/sound/soc/codecs/rt712-sdca-sdw.h
index 99fd2d67f04d..7ad25cc27f62 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.h
+++ b/sound/soc/codecs/rt712-sdca-sdw.h
@@ -11,21 +11,21 @@
#include <linux/regmap.h>
#include <linux/soundwire/sdw_registers.h>
+/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */
static const struct reg_default rt712_sdca_reg_defaults[] = {
-
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE12, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_03), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_04), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
@@ -34,6 +34,7 @@ static const struct reg_default rt712_sdca_reg_defaults[] = {
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
};
+/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */
static const struct reg_default rt712_sdca_mbq_defaults[] = {
{ 0x2000004, 0xaa01 },
{ 0x200000e, 0x21e0 },
diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c
index d6353af07380..2218f9918ae3 100644
--- a/sound/soc/codecs/rt712-sdca.c
+++ b/sound/soc/codecs/rt712-sdca.c
@@ -7,6 +7,7 @@
//
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <sound/core.h>
#include <linux/delay.h>
#include <linux/init.h>
@@ -403,7 +404,7 @@ io_error:
static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712)
{
- mutex_lock(&rt712->calibrate_mutex);
+ guard(mutex)(&rt712->calibrate_mutex);
if (rt712->hs_jack) {
/* Enable HID1 event & set button RTC mode */
@@ -450,8 +451,6 @@ static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712)
dev_dbg(&rt712->slave->dev, "in %s disable\n", __func__);
}
-
- mutex_unlock(&rt712->calibrate_mutex);
}
static int rt712_sdca_set_jack_detect(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/rt715-sdca-sdw.h b/sound/soc/codecs/rt715-sdca-sdw.h
index 0cbc14844f8c..d408f2d7d0f2 100644
--- a/sound/soc/codecs/rt715-sdca-sdw.h
+++ b/sound/soc/codecs/rt715-sdca-sdw.h
@@ -76,8 +76,6 @@ static const struct reg_default rt715_reg_defaults_sdca[] = {
{ 0x2f52, 0x01 },
{ 0x2f5a, 0x02 },
{ 0x2f5b, 0x05 },
- { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN,
- RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
@@ -98,14 +96,12 @@ static const struct reg_default rt715_reg_defaults_sdca[] = {
RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN,
+ RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x02 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00), 0x00 },
- { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
- RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
- { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
- RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
};
static const struct reg_default rt715_mbq_reg_defaults_sdca[] = {
@@ -149,8 +145,6 @@ static const struct reg_default rt715_mbq_reg_defaults_sdca[] = {
RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 },
- { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
- RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), 0x00 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
@@ -165,6 +159,8 @@ static const struct reg_default rt715_mbq_reg_defaults_sdca[] = {
RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
};
diff --git a/sound/soc/codecs/rt715-sdw.h b/sound/soc/codecs/rt715-sdw.h
index 5d7661e335ae..f19fafb913f0 100644
--- a/sound/soc/codecs/rt715-sdw.h
+++ b/sound/soc/codecs/rt715-sdw.h
@@ -281,8 +281,8 @@ static const struct reg_default rt715_reg_defaults[] = {
{ 0x371b, 0x00 },
{ 0x371d, 0x00 },
{ 0x3729, 0x00 },
- { 0x385e, 0x00 },
{ 0x3859, 0x00 },
+ { 0x385e, 0x00 },
{ 0x4c12, 0x411111f0 },
{ 0x4c13, 0x411111f0 },
{ 0x4c1d, 0x411111f0 },
@@ -300,36 +300,36 @@ static const struct reg_default rt715_reg_defaults[] = {
{ 0x4f1d, 0x411111f0 },
{ 0x4f29, 0x411111f0 },
{ 0x7207, 0x00 },
- { 0x8287, 0x00 },
{ 0x7208, 0x00 },
- { 0x8288, 0x00 },
{ 0x7209, 0x00 },
- { 0x8289, 0x00 },
{ 0x7227, 0x00 },
- { 0x82a7, 0x00 },
{ 0x7307, 0x97 },
- { 0x8387, 0x97 },
{ 0x7308, 0x97 },
- { 0x8388, 0x97 },
{ 0x7309, 0x97 },
- { 0x8389, 0x97 },
{ 0x7312, 0x00 },
- { 0x8392, 0x00 },
{ 0x7313, 0x00 },
- { 0x8393, 0x00 },
{ 0x7318, 0x00 },
- { 0x8398, 0x00 },
{ 0x7319, 0x00 },
- { 0x8399, 0x00 },
{ 0x731a, 0x00 },
- { 0x839a, 0x00 },
{ 0x731b, 0x00 },
- { 0x839b, 0x00 },
{ 0x731d, 0x00 },
- { 0x839d, 0x00 },
{ 0x7327, 0x97 },
- { 0x83a7, 0x97 },
{ 0x7329, 0x00 },
+ { 0x8287, 0x00 },
+ { 0x8288, 0x00 },
+ { 0x8289, 0x00 },
+ { 0x82a7, 0x00 },
+ { 0x8387, 0x97 },
+ { 0x8388, 0x97 },
+ { 0x8389, 0x97 },
+ { 0x8392, 0x00 },
+ { 0x8393, 0x00 },
+ { 0x8398, 0x00 },
+ { 0x8399, 0x00 },
+ { 0x839a, 0x00 },
+ { 0x839b, 0x00 },
+ { 0x839d, 0x00 },
+ { 0x83a7, 0x97 },
{ 0x83a9, 0x00 },
{ 0x752039, 0xa500 },
};
diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c
index 041b381e582b..eae7d662efae 100644
--- a/sound/soc/codecs/rt721-sdca-sdw.c
+++ b/sound/soc/codecs/rt721-sdca-sdw.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/module.h>
@@ -466,13 +467,13 @@ static int rt721_sdca_dev_system_suspend(struct device *dev)
* 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);
+ scoped_guard(mutex, &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);
+ }
if (ret1 < 0 || ret2 < 0) {
/* log but don't prevent suspend from happening */
@@ -494,13 +495,15 @@ static int rt721_sdca_dev_resume(struct device *dev)
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;
+ scoped_guard(mutex, &rt721->disable_irq_lock) {
+ if (rt721->disable_irq) {
+ 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);
}
ret = sdw_slave_wait_for_init(slave, RT721_PROBE_TIMEOUT);
@@ -510,9 +513,20 @@ static int rt721_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(rt721->regmap, false);
- regcache_sync(rt721->regmap);
+ ret = regcache_sync(rt721->regmap);
+ if (ret) {
+ regcache_cache_only(rt721->regmap, true);
+ return ret;
+ }
+
regcache_cache_only(rt721->mbq_regmap, false);
- regcache_sync(rt721->mbq_regmap);
+ ret = regcache_sync(rt721->mbq_regmap);
+ if (ret) {
+ regcache_cache_only(rt721->mbq_regmap, true);
+ regcache_cache_only(rt721->regmap, true);
+ return ret;
+ }
+
return 0;
}
diff --git a/sound/soc/codecs/rt721-sdca-sdw.h b/sound/soc/codecs/rt721-sdca-sdw.h
index 214b31b82583..13d6227f3392 100644
--- a/sound/soc/codecs/rt721-sdca-sdw.h
+++ b/sound/soc/codecs/rt721-sdca-sdw.h
@@ -29,14 +29,6 @@ static const struct reg_default rt721_sdca_reg_defaults[] = {
{ 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,
@@ -45,6 +37,14 @@ static const struct reg_default rt721_sdca_reg_defaults[] = {
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_JACK_CODEC, RT721_SDCA_ENT_PDE12,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { 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_PDE40,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ 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,
@@ -53,30 +53,30 @@ static const struct reg_default rt721_sdca_reg_defaults[] = {
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_PDE2A,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ 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_CS31,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ 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 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23,
+ RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
};
static const struct reg_default rt721_sdca_mbq_defaults[] = {
diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c
index 35960c225224..159c35d19dba 100644
--- a/sound/soc/codecs/rt721-sdca.c
+++ b/sound/soc/codecs/rt721-sdca.c
@@ -5,7 +5,7 @@
// Copyright(c) 2024 Realtek Semiconductor Corp.
//
//
-
+#include <linux/cleanup.h>
#include <linux/bitops.h>
#include <sound/core.h>
#include <linux/delay.h>
@@ -289,7 +289,7 @@ static void rt721_sdca_jack_preset(struct rt721_sdca_priv *rt721)
static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721)
{
- mutex_lock(&rt721->calibrate_mutex);
+ guard(mutex)(&rt721->calibrate_mutex);
if (rt721->hs_jack) {
sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK1,
SDW_SCP_SDCA_INTMASK_SDCA_0);
@@ -309,7 +309,6 @@ static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721)
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,
diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
index 7482a9a8d198..5bc9aed58d14 100644
--- a/sound/soc/codecs/rt722-sdca-sdw.c
+++ b/sound/soc/codecs/rt722-sdca-sdw.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/module.h>
@@ -517,13 +518,13 @@ static int rt722_sdca_dev_system_suspend(struct device *dev)
* deferred work completes and before the parent disables
* interrupts on the link
*/
- mutex_lock(&rt722_sdca->disable_irq_lock);
- rt722_sdca->disable_irq = true;
- ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
- SDW_SCP_SDCA_INTMASK_SDCA_0, 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);
+ scoped_guard(mutex, &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, 0);
+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
+ }
if (ret1 < 0 || ret2 < 0) {
/* log but don't prevent suspend from happening */
@@ -545,13 +546,15 @@ static int rt722_sdca_dev_resume(struct device *dev)
return 0;
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_0);
- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8);
- rt722->disable_irq = false;
+ scoped_guard(mutex, &rt722->disable_irq_lock) {
+ if (rt722->disable_irq) {
+ 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;
+ }
}
- mutex_unlock(&rt722->disable_irq_lock);
}
ret = sdw_slave_wait_for_init(slave, RT722_PROBE_TIMEOUT);
@@ -561,7 +564,13 @@ static int rt722_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(rt722->regmap, false);
- regcache_sync(rt722->regmap);
+ ret = regcache_sync(rt722->regmap);
+ if (ret) {
+ regcache_cache_only(rt722->regmap, true);
+ regcache_mark_dirty(rt722->regmap);
+ return ret;
+ }
+
return 0;
}
diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c
index 6b509eb65d77..4cbe9e909585 100644
--- a/sound/soc/codecs/rt722-sdca.c
+++ b/sound/soc/codecs/rt722-sdca.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/dmi.h>
@@ -294,7 +295,7 @@ io_error:
static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722)
{
- mutex_lock(&rt722->calibrate_mutex);
+ guard(mutex)(&rt722->calibrate_mutex);
if (rt722->hs_jack) {
/* set SCP_SDCA_IntMask1[0]=1 */
sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1,
@@ -317,7 +318,6 @@ static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722)
rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL,
RT722_GE_RELATED_CTL2, 0x4000, 0x4000);
}
- mutex_unlock(&rt722->calibrate_mutex);
}
static int rt722_sdca_set_jack_detect(struct snd_soc_component *component,
@@ -352,8 +352,6 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722)
static const char func_tag[] = "FUNC";
static const char xu_tag[] = "XU";
const char *dmi_vendor, *dmi_product, *dmi_sku;
- char *cae_filename;
- const struct firmware *cae_fw = NULL;
unsigned int cae_st_spk, cae_st_hp, cae_st_mic;
unsigned int func, value;
unsigned int combined_val;
@@ -385,7 +383,8 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722)
space = strchr(dmi_sku, ' ');
s_len = space ? space - dmi_sku : strlen(dmi_sku);
- cae_filename = kasprintf(GFP_KERNEL,
+ char *cae_filename __free(kfree) =
+ kasprintf(GFP_KERNEL,
"realtek/rt722/rt722_RAE_%.*s_%.*s_%.*s.dat",
v_len, dmi_vendor,
p_len, dmi_product,
@@ -399,8 +398,8 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722)
regmap_write(rt722->regmap, RT722_MIC_CAE_PARAM39, 0x5f);
usleep_range(50000, 60000);
+ const struct firmware *cae_fw __free(firmware) = NULL;
request_firmware(&cae_fw, cae_filename, dev);
- kfree(cae_filename);
if (!cae_fw) {
dev_err(dev, "%s: Failed to load CAE firmware\n", __func__);
return -ENOENT;
@@ -555,7 +554,6 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722)
regcache_cache_bypass(rt722->regmap, false);
rt722->cae_update_done = 1;
dev_dbg(dev, "%s: CAE FW update done.\n", __func__);
- release_firmware(cae_fw);
return 0;
verify_abort:
@@ -565,7 +563,6 @@ verify_abort:
out_release:
rt722_sdca_index_update_bits(rt722, RT722_VENDOR_REG,
RT722_MISC_CTRL1, 0x8000, 0x0000);
- release_firmware(cae_fw);
dev_err(dev, "%s: CAE FW update aborted (ret=%d).\n", __func__, ret);
return ret;
}
@@ -1906,6 +1903,9 @@ int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
rt722_sdca_amp_preset(rt722);
rt722_sdca_jack_preset(rt722);
+ if (rt722->hs_jack && (!rt722->first_hw_init))
+ rt722_sdca_jack_init(rt722);
+
if (rt722->first_hw_init) {
regcache_cache_bypass(rt722->regmap, false);
regcache_mark_dirty(rt722->regmap);
diff --git a/sound/soc/codecs/rt766-sdca-sdw.c b/sound/soc/codecs/rt766-sdca-sdw.c
new file mode 100644
index 000000000000..5d60c3bcc6cd
--- /dev/null
+++ b/sound/soc/codecs/rt766-sdca-sdw.c
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt766-sdca-sdw.c -- rt766 SDCA ALSA SoC audio driver
+//
+// Copyright(c) 2026 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/sdca.h>
+#include <sound/sdca_function.h>
+#include "rt766-sdca.h"
+#include "rt766-sdca-sdw.h"
+
+#define RT766_PROBE_TIMEOUT 5000
+
+static bool rt766_sdca_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SDW_SCP_SDCA_INT1 ... SDW_SCP_SDCA_INTMASK4:
+ case RT766_VERSION_ID ... RT766_BOND_LATCH_ID:
+ case 0xc344 ... 0xc345:
+ case 0xc900:
+ case 0xc920:
+ case 0xd540 ... 0xd542:
+ case 0xf01e:
+ case RT766_HP_POWER_STATE ... RT766_HP_FSM_CTL2_1:
+ case 0x310100:
+ case RT766_MCU_PATCH_ADDR1_START ... RT766_MCU_PATCH_ADDR1_END:
+ case RT766_MCU_PATCH_ADDR2_START ... RT766_MCU_PATCH_ADDR2_END:
+ case RT766_MUTE_REG(UAJ, USER_FU41, 1):
+ case RT766_MUTE_REG(UAJ, USER_FU41, 2):
+ case RT766_VOLUME_REG(UAJ, USER_FU41, 1):
+ case RT766_VOLUME_REG(UAJ, USER_FU41, 2):
+ case RT766_MUTE_REG(UAJ, USER_FU36, 1):
+ case RT766_MUTE_REG(UAJ, USER_FU36, 2):
+ case RT766_VOLUME_REG(UAJ, USER_FU36, 1):
+ case RT766_VOLUME_REG(UAJ, USER_FU36, 2):
+ case RT766_PDE_REQ_REG(UAJ, PDE47):
+ case RT766_PDE_REQ_REG(UAJ, PDE34):
+ case RT766_SDCA_CTL(UAJ, CS41, SDCA_CTL_CS_SAMPLERATEINDEX):
+ case RT766_SDCA_CTL(UAJ, CS36, SDCA_CTL_CS_SAMPLERATEINDEX):
+ case RT766_FUNC_STATUS_REG(UAJ): /* 0x40480000 */
+ case RT766_PDE_ACTUAL_REG(UAJ, PDE47): /* 0x40481400 */
+ case RT766_PDE_ACTUAL_REG(UAJ, PDE34): /* 0x40481480 */
+ case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1):
+ case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2):
+ case RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_SELECTED_MODE):
+ case RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE): /* 0x40600490 */
+ case RT766_PDE_REQ_REG(MIC, PDE11):
+ case RT766_MUTE_REG(MIC, USER_FU113, 1):
+ case RT766_MUTE_REG(MIC, USER_FU113, 2):
+ case RT766_MUTE_REG(MIC, USER_FU113, 3):
+ case RT766_MUTE_REG(MIC, USER_FU113, 4):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 1):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 2):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 3):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 4):
+ case RT766_FUNC_STATUS_REG(MIC): /* 0x40880000 */
+ case RT766_SDCA_CTL(MIC, CS113, SDCA_CTL_CS_SAMPLERATEINDEX):
+ case RT766_PDE_ACTUAL_REG(MIC, PDE11): /* 0x40881500 */
+ case RT766_FUNC_STATUS_REG(HID): /* 0x40c80000 */
+ /* 0x40c80080 - 0x40c80098 */
+ case RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER) ...
+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH):
+ case RT766_MUTE_REG(AMP, USER_FU21, 1):
+ case RT766_MUTE_REG(AMP, USER_FU21, 2):
+ case RT766_VOLUME_REG(AMP, USER_FU21, 1):
+ case RT766_VOLUME_REG(AMP, USER_FU21, 2):
+ case RT766_PDE_REQ_REG(AMP, PDE23):
+ case RT766_FUNC_STATUS_REG(AMP): /* 0x41080000 */
+ case RT766_SDCA_CTL(AMP, PPU21, SDCA_CTL_PPU_POSTURENUMBER):
+ case RT766_SDCA_CTL(AMP, CS21, SDCA_CTL_CS_SAMPLERATEINDEX):
+ case RT766_PDE_ACTUAL_REG(AMP, PDE23): /* 0x41081980 */
+ case RT766_BUF_ADDR_HID1 ... RT766_BUF_ADDR_HID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt766_sdca_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SDW_SCP_SDCA_INT1 ... SDW_SCP_SDCA_INTMASK4:
+ case RT766_VERSION_ID ... RT766_BOND_LATCH_ID:
+ case 0xc344 ... 0xc345:
+ case 0xc900:
+ case 0xc920:
+ case 0xd540 ... 0xd542:
+ case 0xf01e:
+ case RT766_HP_POWER_STATE ... RT766_HP_FSM_CTL2_1:
+ case 0x310100:
+ case RT766_MCU_PATCH_ADDR1_START ... RT766_MCU_PATCH_ADDR1_END:
+ case RT766_MCU_PATCH_ADDR2_START ... RT766_MCU_PATCH_ADDR2_END:
+ case RT766_FUNC_STATUS_REG(UAJ):
+ case RT766_PDE_ACTUAL_REG(UAJ, PDE47):
+ case RT766_PDE_ACTUAL_REG(UAJ, PDE34):
+ case RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE):
+ case RT766_FUNC_STATUS_REG(MIC):
+ case RT766_PDE_ACTUAL_REG(MIC, PDE11):
+ case RT766_FUNC_STATUS_REG(HID):
+ case RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER) ...
+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH):
+ case RT766_FUNC_STATUS_REG(AMP):
+ case RT766_PDE_ACTUAL_REG(AMP, PDE23):
+ case RT766_BUF_ADDR_HID1 ... RT766_BUF_ADDR_HID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int rt766_sdca_mbq_size(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT766_VOLUME_REG(UAJ, USER_FU41, 1):
+ case RT766_VOLUME_REG(UAJ, USER_FU41, 2):
+ case RT766_VOLUME_REG(UAJ, USER_FU36, 1):
+ case RT766_VOLUME_REG(UAJ, USER_FU36, 2):
+ case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1):
+ case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 1):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 2):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 3):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 4):
+ case RT766_VOLUME_REG(AMP, USER_FU21, 1):
+ case RT766_VOLUME_REG(AMP, USER_FU21, 2):
+ return 2;
+ default:
+ return 1;
+ }
+}
+
+static const struct regmap_sdw_mbq_cfg rt766_sdca_mbq_cfg = {
+ .mbq_size = rt766_sdca_mbq_size,
+};
+
+static const struct regmap_config rt766_sdca_regmap = {
+ .reg_bits = 32,
+ .val_bits = 16,
+ .readable_reg = rt766_sdca_readable_register,
+ .volatile_reg = rt766_sdca_volatile_register,
+ .reg_defaults = rt766_sdca_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt766_sdca_defaults),
+ .max_register = SDW_SDCA_MAX_REGISTER,
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt766_sdca_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(&slave->dev);
+
+ if (status == SDW_SLAVE_UNATTACHED)
+ rt766->hw_init = false;
+
+ if (status == SDW_SLAVE_ATTACHED) {
+ if (rt766->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 rt766_sdca_jack_init set.
+ */
+ sdw_write_no_pm(rt766->slave, SDW_SCP_SDCA_INTMASK3,
+ SDW_SCP_SDCA_INTMASK_SDCA_16);
+ sdw_write_no_pm(rt766->slave, SDW_SCP_SDCA_INTMASK4,
+ SDW_SCP_SDCA_INTMASK_SDCA_24);
+ }
+ }
+
+ /*
+ * Perform initialization only if slave status is present and
+ * hw_init flag is false
+ */
+ if (rt766->hw_init || status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt766_sdca_io_init(&slave->dev, slave);
+}
+
+static int rt766_sdca_read_prop(struct sdw_slave *slave)
+{
+ struct sdw_slave_prop *prop = &slave->prop;
+ int ret;
+
+ ret = sdw_slave_read_prop(slave);
+ if (ret < 0)
+ return ret;
+
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+ /*
+ * SDCA interrupts are routed through SoundWire domain IRQ.
+ */
+ prop->use_domain_irq = true;
+
+ return 0;
+}
+
+static const struct sdw_slave_ops rt766_sdca_slave_ops = {
+ .read_prop = rt766_sdca_read_prop,
+ .update_status = rt766_sdca_update_status,
+};
+
+static int rt766_sdca_sdw_probe(struct sdw_slave *slave,
+ const struct sdw_device_id *id)
+{
+ struct regmap *regmap;
+
+ /* Regmap Initialization */
+ regmap = devm_regmap_init_sdw_mbq_cfg(&slave->dev, slave,
+ &rt766_sdca_regmap, &rt766_sdca_mbq_cfg);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt766_sdca_init(&slave->dev, regmap, slave);
+}
+
+static void rt766_sdca_sdw_remove(struct sdw_slave *slave)
+{
+ pm_runtime_disable(&slave->dev);
+}
+
+static const struct sdw_device_id rt766_sdca_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x766, 0x3, 0x1, 0),
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x767, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt766_sdca_id);
+
+static int rt766_sdca_dev_suspend(struct device *dev)
+{
+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev);
+
+ if (!rt766->hw_init)
+ return 0;
+
+ regcache_cache_only(rt766->regmap, true);
+ return 0;
+}
+
+static int rt766_sdca_dev_system_suspend(struct device *dev)
+{
+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev);
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ int ret1, ret2;
+
+ if (!rt766->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(&rt766->disable_irq_lock);
+ rt766->disable_irq = true;
+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK3,
+ SDW_SCP_SDCA_INTMASK_SDCA_16, 0);
+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK4,
+ SDW_SCP_SDCA_INTMASK_SDCA_24, 0);
+ mutex_unlock(&rt766->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 rt766_sdca_dev_suspend(dev);
+}
+
+static int rt766_sdca_dev_resume(struct device *dev)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev);
+ int ret;
+
+ if (!rt766->first_hw_init)
+ return 0;
+
+ if (!slave->unattach_request) {
+ mutex_lock(&rt766->disable_irq_lock);
+ if (rt766->disable_irq == true) {
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK3, SDW_SCP_SDCA_INTMASK_SDCA_16);
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK4, SDW_SCP_SDCA_INTMASK_SDCA_24);
+ rt766->disable_irq = false;
+ }
+ mutex_unlock(&rt766->disable_irq_lock);
+ goto regmap_sync;
+ }
+
+ ret = sdw_slave_wait_for_init(slave, RT766_PROBE_TIMEOUT);
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
+ return ret;
+ }
+
+regmap_sync:
+ regcache_cache_only(rt766->regmap, false);
+ ret = regcache_sync(rt766->regmap);
+ if (ret) {
+ regcache_cache_only(rt766->regmap, true);
+ regcache_mark_dirty(rt766->regmap);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops rt766_sdca_pm = {
+ SYSTEM_SLEEP_PM_OPS(rt766_sdca_dev_system_suspend, rt766_sdca_dev_resume)
+ RUNTIME_PM_OPS(rt766_sdca_dev_suspend, rt766_sdca_dev_resume, NULL)
+};
+
+static struct sdw_driver rt766_sdca_sdw_driver = {
+ .driver = {
+ .name = "rt766-sdca",
+ .pm = pm_ptr(&rt766_sdca_pm),
+ },
+ .probe = rt766_sdca_sdw_probe,
+ .remove = rt766_sdca_sdw_remove,
+ .ops = &rt766_sdca_slave_ops,
+ .id_table = rt766_sdca_id,
+};
+module_sdw_driver(rt766_sdca_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT766 SDCA SDW driver");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_SDCA");
diff --git a/sound/soc/codecs/rt766-sdca-sdw.h b/sound/soc/codecs/rt766-sdca-sdw.h
new file mode 100644
index 000000000000..3e923a1ea2f8
--- /dev/null
+++ b/sound/soc/codecs/rt766-sdca-sdw.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt766-sdca-sdw.h -- RT766 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2026 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT766_SDW_H__
+#define __RT766_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw_registers.h>
+
+static const struct reg_default rt766_sdca_defaults[] = {
+ /* 0x40400289 - 0x4040028a */
+ { RT766_MUTE_REG(UAJ, USER_FU41, 1), 0x01 },
+ { RT766_MUTE_REG(UAJ, USER_FU41, 2), 0x01 },
+ /* 0x40400291 - 0x40400292 */
+ { RT766_VOLUME_REG(UAJ, USER_FU41, 1), 0x0000 },
+ { RT766_VOLUME_REG(UAJ, USER_FU41, 2), 0x0000 },
+ /* 0x40400789 - 0x4040078a */
+ { RT766_MUTE_REG(UAJ, USER_FU36, 1), 0x01 },
+ { RT766_MUTE_REG(UAJ, USER_FU36, 2), 0x01 },
+ /* 0x40400791 - 0x40400792 */
+ { RT766_VOLUME_REG(UAJ, USER_FU36, 1), 0x0000 },
+ { RT766_VOLUME_REG(UAJ, USER_FU36, 2), 0x0000 },
+ { RT766_PDE_REQ_REG(UAJ, PDE47), 0x03 }, /* 0x40401408 */
+ { RT766_PDE_REQ_REG(UAJ, PDE34), 0x03 }, /* 0x40401488 */
+ { RT766_SDCA_CTL(UAJ, CS41, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x40480080 */
+ { RT766_SDCA_CTL(UAJ, CS36, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x40480880 */
+ /* 0x40600259 - 0x4060025a */
+ { RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1), 0xfe00 },
+ { RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2), 0xfe00 },
+ { RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_SELECTED_MODE), 0x00 }, /* 0x40600488 */
+
+ { RT766_PDE_REQ_REG(MIC, PDE11), 0x03 }, /* 0x40801508 */
+ /* 0x40801809 - 0x4080180c */
+ { RT766_MUTE_REG(MIC, USER_FU113, 1), 0x01 },
+ { RT766_MUTE_REG(MIC, USER_FU113, 2), 0x01 },
+ { RT766_MUTE_REG(MIC, USER_FU113, 3), 0x01 },
+ { RT766_MUTE_REG(MIC, USER_FU113, 4), 0x01 },
+ /* 0x40801811 - 0x40801814 */
+ { RT766_VOLUME_REG(MIC, USER_FU113, 1), 0x0000 },
+ { RT766_VOLUME_REG(MIC, USER_FU113, 2), 0x0000 },
+ { RT766_VOLUME_REG(MIC, USER_FU113, 3), 0x0000 },
+ { RT766_VOLUME_REG(MIC, USER_FU113, 4), 0x0000 },
+ { RT766_SDCA_CTL(MIC, CS113, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x40880900 */
+
+ /* 0x41000189 - 0x4100018a */
+ { RT766_MUTE_REG(AMP, USER_FU21, 1), 0x01 },
+ { RT766_MUTE_REG(AMP, USER_FU21, 2), 0x01 },
+ /* 0x41000191 - 0x41000192 */
+ { RT766_VOLUME_REG(AMP, USER_FU21, 1), 0x0000 },
+ { RT766_VOLUME_REG(AMP, USER_FU21, 2), 0x0000 },
+ { RT766_PDE_REQ_REG(AMP, PDE23), 0x03 }, /* 0x41001988 */
+ { RT766_SDCA_CTL(AMP, PPU21, SDCA_CTL_PPU_POSTURENUMBER), 0x00 }, /* 0x41080200 */
+ { RT766_SDCA_CTL(AMP, CS21, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x41081080 */
+
+};
+
+#endif /* __RT766_SDW_H__ */
diff --git a/sound/soc/codecs/rt766-sdca.c b/sound/soc/codecs/rt766-sdca.c
new file mode 100644
index 000000000000..64d763b96a06
--- /dev/null
+++ b/sound/soc/codecs/rt766-sdca.c
@@ -0,0 +1,1378 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt766-sdca.c -- rt766 SDCA ALSA SoC audio driver
+//
+// Copyright(c) 2026 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/pm_runtime.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/sdw.h>
+#include <sound/sdca.h>
+#include <sound/sdca_asoc.h>
+#include <sound/sdca_function.h>
+#include <sound/sdca_hid.h>
+#include <sound/sdca_regmap.h>
+#include <sound/sdca_interrupts.h>
+#include <linux/slab.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "rt766-sdca.h"
+#include "rt-sdw-common.h"
+
+static int rt766_sdca_btn_detect(struct sdca_interrupt *interrupt)
+{
+ struct rt766_sdca_priv *rt766 = interrupt->priv;
+ unsigned char *buf = NULL;
+ unsigned int offset, owner, length;
+ unsigned int det_mode, idx, val;
+ int ret;
+
+ ret = regmap_read(rt766->regmap,
+ RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE),
+ &det_mode);
+ if (ret < 0)
+ goto io_error;
+
+ /* get current UMP message owner */
+ ret = regmap_read(rt766->regmap,
+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER),
+ &owner);
+ if (ret < 0)
+ goto io_error;
+
+ /* if owner is device then there is no button event from device */
+ if (owner == 1)
+ return 0;
+
+ if (det_mode) {
+ /* read UMP message length */
+ ret = regmap_read(rt766->regmap,
+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH),
+ &length);
+ if (ret < 0)
+ goto _end_btn_det_;
+
+ /* read UMP message offset */
+ ret = regmap_read(rt766->regmap,
+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGEOFFSET),
+ &offset);
+ if (ret < 0)
+ goto _end_btn_det_;
+
+ buf = devm_kzalloc(&rt766->slave->dev, length, GFP_KERNEL);
+ if (!buf) {
+ dev_err(&rt766->slave->dev, "%s: alloc buf failed\n", __func__);
+ goto _end_btn_det_;
+ }
+
+ for (idx = 0; idx < length; idx++) {
+ ret = regmap_read(rt766->regmap,
+ RT766_BUF_ADDR_HID1 + offset + idx, &val);
+ if (ret < 0)
+ goto _end_btn_det_;
+ buf[idx] = val & 0xff;
+ }
+
+ if (rt766->hid)
+ hid_input_report(rt766->hid, HID_INPUT_REPORT,
+ buf, length, 1);
+ }
+
+_end_btn_det_:
+ if (buf)
+ devm_kfree(&rt766->slave->dev, buf);
+
+ /* Host is owner, so set back to device */
+ if (owner == 0) {
+ regmap_write(rt766->regmap,
+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER), 0x01);
+ }
+
+ return 0;
+
+io_error:
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+ return ret;
+}
+
+static irqreturn_t rt766_sdca_irq_btn_handler(int irq, void *data)
+{
+ struct sdca_interrupt *interrupt = data;
+ struct rt766_sdca_priv *rt766 = interrupt->priv;
+
+ if (!rt766->hs_jack)
+ return IRQ_HANDLED;
+
+ if (!rt766->component->card || !rt766->component->card->instantiated)
+ return IRQ_HANDLED;
+
+ mutex_lock(&rt766->disable_irq_lock);
+ if (!rt766->disable_irq)
+ rt766_sdca_btn_detect(interrupt);
+ mutex_unlock(&rt766->disable_irq_lock);
+ return IRQ_HANDLED;
+}
+
+static int rt766_sdca_headset_detect(struct rt766_sdca_priv *rt766)
+{
+ unsigned int det_mode;
+ int ret;
+
+ /* get detected_mode */
+ ret = regmap_read(rt766->regmap,
+ RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE),
+ &det_mode);
+ if (ret < 0)
+ goto io_error;
+
+ switch (det_mode) {
+ case 0x00:
+ rt766->jack_type = 0;
+ break;
+ case 0x03:
+ rt766->jack_type = SND_JACK_HEADPHONE;
+ break;
+ case 0x05:
+ rt766->jack_type = SND_JACK_HEADSET;
+ break;
+ }
+
+ /* write selected_mode */
+ if (det_mode) {
+ ret = regmap_write(rt766->regmap,
+ RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_SELECTED_MODE),
+ det_mode);
+ if (ret < 0)
+ goto io_error;
+ }
+
+ dev_dbg(&rt766->slave->dev,
+ "%s, detected_mode=0x%x\n", __func__, det_mode);
+
+ return 0;
+
+io_error:
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+ return ret;
+}
+
+static irqreturn_t rt766_sdca_irq_jd_handler(int irq, void *data)
+{
+ struct sdca_interrupt *interrupt = data;
+ struct rt766_sdca_priv *rt766 = interrupt->priv;
+
+ if (!rt766->hs_jack)
+ return IRQ_HANDLED;
+
+ if (!rt766->component->card || !rt766->component->card->instantiated)
+ return IRQ_HANDLED;
+
+ mutex_lock(&rt766->disable_irq_lock);
+ if (!rt766->disable_irq)
+ rt766_sdca_headset_detect(rt766);
+ mutex_unlock(&rt766->disable_irq_lock);
+
+ dev_dbg(&rt766->slave->dev,
+ "in %s, jack_type=%d\n", __func__, rt766->jack_type);
+
+ snd_soc_jack_report(rt766->hs_jack, rt766->jack_type, SND_JACK_HEADSET);
+ return IRQ_HANDLED;
+}
+
+static void rt766_sdca_destroy_hid_device(struct sdca_interrupt *interrupt)
+{
+ struct rt766_sdca_priv *rt766 = interrupt->priv;
+
+ hid_destroy_device(rt766->hid);
+}
+
+static int rt766_sdca_irq_ctl(struct rt766_sdca_priv *rt766,
+ struct sdca_function_data *function,
+ struct snd_soc_component *component,
+ struct sdca_interrupt_info *info,
+ bool enabled)
+{
+ struct device *dev = &rt766->slave->dev;
+ struct sdca_interrupt *interrupt;
+ struct sdca_control *control;
+ struct sdca_entity *entity;
+ irq_handler_t handler;
+ int i, j, irq, ret;
+
+ for (i = 0; i < function->num_entities; i++) {
+ entity = &function->entities[i];
+
+ for (j = 0; j < entity->num_controls; j++) {
+ control = &entity->controls[j];
+ irq = control->interrupt_position;
+
+ switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
+ case SDCA_CTL_TYPE_S(GE, DETECTED_MODE):
+ handler = rt766_sdca_irq_jd_handler;
+ break;
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER):
+ handler = rt766_sdca_irq_btn_handler;
+ break;
+ default:
+ continue;
+ }
+
+ interrupt = &info->irqs[irq];
+
+ if (enabled) {
+ ret = sdca_irq_data_populate(dev, rt766->regmap, component,
+ function, entity, control,
+ interrupt);
+ if (ret)
+ return ret;
+
+ if (handler == rt766_sdca_irq_btn_handler) {
+ ret = sdca_add_hid_device(interrupt);
+ if (ret)
+ return ret;
+
+ interrupt->free_priv = rt766_sdca_destroy_hid_device;
+ rt766->hid = interrupt->priv;
+ }
+
+ interrupt->priv = rt766;
+ ret = sdca_irq_request(dev, info, irq, interrupt->name,
+ handler, interrupt);
+ if (ret) {
+ dev_err(dev, "failed to request irq %s: %d\n",
+ interrupt->name, ret);
+ sdca_irq_cleanup_late(dev, function, info);
+ return ret;
+ }
+ dev_dbg(dev, "Requesting IRQ %d InterruptName=%s\n", irq, interrupt->name);
+ } else {
+ sdca_irq_cleanup_late(dev, function, info);
+ dev_dbg(dev, "Freeing IRQ %d\n", irq);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int rt766_sdca_set_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *hs_jack, void *data)
+{
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ if (!rt766->uaj_func_data) {
+ dev_err(&rt766->slave->dev, "The SDCA UAJ function is not supported.\n");
+ return -EINVAL;
+ }
+
+ rt766->hs_jack = hs_jack;
+
+ if (!rt766->first_hw_init)
+ return 0;
+
+ 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;
+ }
+
+ /* disable interrupts if hs_jack is not set */
+ if (!rt766->hs_jack) {
+ if (rt766->uaj_func_data)
+ rt766_sdca_irq_ctl(rt766, rt766->uaj_func_data,
+ rt766->component, rt766->irq_info, false);
+
+ if (rt766->hid_func_data)
+ rt766_sdca_irq_ctl(rt766, rt766->hid_func_data,
+ rt766->component, rt766->irq_info, false);
+ }
+
+ pm_runtime_put_autosuspend(component->dev);
+
+ return 0;
+}
+
+static int rt766_sdca_set_fu_ctl(struct rt766_sdca_priv *rt766, int func_num, int fu_num)
+{
+ unsigned int fu01_reg, fu02_reg;
+ unsigned int ch_01, ch_02;
+ unsigned int ch_mute;
+ unsigned int fu_reg;
+ int err, i;
+
+ switch (fu_num) {
+ case RT766_SDCA_ENT_USER_FU41:
+ ch_01 = (rt766->fu41_dapm_mute || rt766->fu41_mixer_l_mute) ? 0x01 : 0x00;
+ ch_02 = (rt766->fu41_dapm_mute || rt766->fu41_mixer_r_mute) ? 0x01 : 0x00;
+ break;
+ case RT766_SDCA_ENT_USER_FU36:
+ ch_01 = (rt766->fu36_dapm_mute || rt766->fu36_mixer_l_mute) ? 0x01 : 0x00;
+ ch_02 = (rt766->fu36_dapm_mute || rt766->fu36_mixer_r_mute) ? 0x01 : 0x00;
+ break;
+ case RT766_SDCA_ENT_USER_FU21:
+ ch_01 = (rt766->fu21_dapm_mute || rt766->fu21_mixer_l_mute) ? 0x01 : 0x00;
+ ch_02 = (rt766->fu21_dapm_mute || rt766->fu21_mixer_r_mute) ? 0x01 : 0x00;
+ break;
+ case RT766_SDCA_ENT_USER_FU113:
+ for (i = 0; i < ARRAY_SIZE(rt766->fu113_mixer_mute); i++) {
+ ch_mute = (rt766->fu113_dapm_mute || rt766->fu113_mixer_mute[i]) ? 0x01 : 0x00;
+ fu_reg = SDW_SDCA_CTL(func_num, fu_num, SDCA_CTL_FU_MUTE, 1) + i;
+ err = regmap_write(rt766->regmap, fu_reg, ch_mute);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+ }
+
+ fu01_reg = SDW_SDCA_CTL(func_num, fu_num, SDCA_CTL_FU_MUTE, 1);
+ fu02_reg = SDW_SDCA_CTL(func_num, fu_num, SDCA_CTL_FU_MUTE, 2);
+ err = regmap_write(rt766->regmap, fu01_reg, ch_01);
+ if (err < 0)
+ return err;
+ err = regmap_write(rt766->regmap, fu02_reg, ch_02);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int rt766_sdca_fu41_playback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = !rt766->fu41_mixer_l_mute;
+ ucontrol->value.integer.value[1] = !rt766->fu41_mixer_r_mute;
+ return 0;
+}
+
+static int rt766_sdca_fu41_playback_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ int err;
+
+ if (rt766->fu41_mixer_l_mute == !ucontrol->value.integer.value[0] &&
+ rt766->fu41_mixer_r_mute == !ucontrol->value.integer.value[1])
+ return 0;
+
+ rt766->fu41_mixer_l_mute = !ucontrol->value.integer.value[0];
+ rt766->fu41_mixer_r_mute = !ucontrol->value.integer.value[1];
+
+ err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU41);
+ if (err < 0)
+ return err;
+
+ return 1;
+}
+
+static int rt766_sdca_fu36_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = !rt766->fu36_mixer_l_mute;
+ ucontrol->value.integer.value[1] = !rt766->fu36_mixer_r_mute;
+ return 0;
+}
+
+static int rt766_sdca_fu36_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ int err;
+
+ if (rt766->fu36_mixer_l_mute == !ucontrol->value.integer.value[0] &&
+ rt766->fu36_mixer_r_mute == !ucontrol->value.integer.value[1])
+ return 0;
+
+ rt766->fu36_mixer_l_mute = !ucontrol->value.integer.value[0];
+ rt766->fu36_mixer_r_mute = !ucontrol->value.integer.value[1];
+ err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU36);
+ if (err < 0)
+ return err;
+
+ return 1;
+}
+
+static int rt766_sdca_fu21_playback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = !rt766->fu21_mixer_l_mute;
+ ucontrol->value.integer.value[1] = !rt766->fu21_mixer_r_mute;
+ return 0;
+}
+
+static int rt766_sdca_fu21_playback_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ int err;
+
+ if (rt766->fu21_mixer_l_mute == !ucontrol->value.integer.value[0] &&
+ rt766->fu21_mixer_r_mute == !ucontrol->value.integer.value[1])
+ return 0;
+
+ rt766->fu21_mixer_l_mute = !ucontrol->value.integer.value[0];
+ rt766->fu21_mixer_r_mute = !ucontrol->value.integer.value[1];
+
+ err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_USER_FU21);
+ if (err < 0)
+ return err;
+
+ return 1;
+}
+
+static int rt766_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 rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt766->fu113_dapm_mute = false;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_USER_FU113);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt766->fu113_dapm_mute = true;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_USER_FU113);
+ break;
+ }
+ return 0;
+}
+
+static int rt766_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 rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ struct rt_sdca_dmic_kctrl_priv *p =
+ (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ const unsigned int interval_offset = 0xc0;
+ unsigned int regvalue, ctl, i;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ regmap_read(rt766->regmap, p->reg_base + i, &regvalue);
+ ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset);
+
+ ucontrol->value.integer.value[i] = ctl;
+ }
+
+ return 0;
+}
+
+static int rt766_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 rt_sdca_dmic_kctrl_priv *p =
+ (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ const unsigned int interval_offset = 0xc0;
+ unsigned int gain_val[4];
+ unsigned int i, changed = 0;
+ unsigned int regvalue[4];
+ int err;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ regmap_read(rt766->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;
+
+ gain_val[i] = 0x1e00 - ((p->max - gain_val[i]) * interval_offset);
+ gain_val[i] &= 0xffff;
+
+ if (regvalue[i] != gain_val[i])
+ changed = 1;
+ }
+
+ if (!changed)
+ return 0;
+
+ for (i = 0; i < p->count; i++) {
+ err = regmap_write(rt766->regmap, p->reg_base + i, gain_val[i]);
+ if (err < 0)
+ dev_err(&rt766->slave->dev, "0x%08x can't be set\n", p->reg_base + i);
+ }
+
+ return changed;
+}
+
+static int rt766_sdca_dmic_fu113_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ unsigned int i;
+
+ for (i = 0; i < 4; i++)
+ ucontrol->value.integer.value[i] = !rt766->fu113_mixer_mute[i];
+ return 0;
+}
+
+static int rt766_sdca_dmic_fu113_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ int err, changed = 0, i;
+
+ for (i = 0; i < 4; i++) {
+ if (rt766->fu113_mixer_mute[i] != !ucontrol->value.integer.value[i])
+ changed = 1;
+ rt766->fu113_mixer_mute[i] = !ucontrol->value.integer.value[i];
+ }
+
+ err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_USER_FU113);
+ if (err < 0)
+ return err;
+ return changed;
+}
+
+static int rt766_sdca_fu41_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 rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt766->fu41_dapm_mute = false;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU41);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt766->fu41_dapm_mute = true;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU41);
+ break;
+ }
+ return 0;
+}
+
+static int rt766_sdca_pde_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event, int func_num, int pde_num, const char *pde_ent)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ struct sdca_function_data *func_data;
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+ const struct sdca_entity *entity;
+ unsigned int pde_req_reg;
+ int from_ps, to_ps;
+ int ret;
+
+ pde_req_reg = SDW_SDCA_CTL(func_num, pde_num, SDCA_CTL_PDE_REQUESTED_PS, 0);
+
+ switch (func_num) {
+ case RT766_FUNC_NUM_UAJ:
+ func_data = rt766->uaj_func_data;
+ break;
+ case RT766_FUNC_NUM_AMP:
+ func_data = rt766->sa_func_data;
+ break;
+ case RT766_FUNC_NUM_MIC:
+ func_data = rt766->sm_func_data;
+ break;
+ default:
+ dev_err(component->dev, "%s: unsupported func_num %d\n",
+ __func__, func_num);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt766->regmap, pde_req_reg, ps0);
+ from_ps = ps3;
+ to_ps = ps0;
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt766->regmap, pde_req_reg, ps3);
+ from_ps = ps0;
+ to_ps = ps3;
+ break;
+ }
+
+ entity = sdca_find_entity_by_label(func_data, pde_ent);
+ if (!entity) {
+ dev_err(component->dev, "%s: failed to find entity %s\n",
+ __func__, pde_ent);
+ return -EINVAL;
+ }
+
+ ret = sdca_asoc_pde_poll_actual_ps(rt766->regmap,
+ func_num,
+ pde_num,
+ from_ps, to_ps,
+ entity->pde.max_delay,
+ entity->pde.num_max_delay);
+ if (ret)
+ dev_err(component->dev, "%s: PDE transition %x -> %x failed, err=%d\n",
+ __func__, from_ps, to_ps, ret);
+
+ return ret;
+}
+
+static int rt766_sdca_pde47_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ return rt766_sdca_pde_event(w, kcontrol, event,
+ RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_PDE47, "PDE 47");
+}
+
+static int rt766_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 rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt766->fu36_dapm_mute = false;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU36);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt766->fu36_dapm_mute = true;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU36);
+ break;
+ }
+ return 0;
+}
+
+static int rt766_sdca_pde34_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ return rt766_sdca_pde_event(w, kcontrol, event,
+ RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_PDE34, "PDE 34");
+}
+
+static int rt766_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 rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt766->fu21_dapm_mute = false;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_USER_FU21);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt766->fu21_dapm_mute = true;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_USER_FU21);
+ break;
+ }
+ return 0;
+}
+
+static int rt766_sdca_pde23_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ return rt766_sdca_pde_event(w, kcontrol, event,
+ RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_PDE23, "PDE 23");
+}
+
+static int rt766_sdca_pde11_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ return rt766_sdca_pde_event(w, kcontrol, event,
+ RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_PDE11, "PDE 11");
+}
+
+static int rt766_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 const char * const rt766_rx_data_ch_select[] = {
+ "L,R",
+ "R,L",
+ "L,L",
+ "R,R",
+ "L,L+R",
+ "R,L+R",
+ "L+R,L",
+ "L+R,R",
+ "L+R,L+R",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt766_rx_data_ch_enum,
+ RT766_SDCA_CTL(AMP, PPU21, SDCA_CTL_PPU_POSTURENUMBER), 0,
+ rt766_rx_data_ch_select);
+
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -9525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(spk_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, -200, 200, 0);
+
+#define RT766_P75DB_STEP 0xC0 /* 0.75 dB in Q7.8 format */
+#define RT766_2DB_STEP 0x200 /* 2 dB in Q7.8 format */
+#define RT766_HP_VOL_MIN (-127) /* -95.25 dB / 0.75 dB step */
+#define RT766_HS_VOL_MIN (-23) /* -17.25 dB / 0.75 dB step */
+#define RT766_HS_BOOST_VOL_MIN (-1) /* -2 dB / 2 dB step */
+#define RT766_SPK_VOL_MIN (-87) /* -65.25 dB / 0.75 dB step */
+#define RT766_P_VOL_MAX 0 /* 0 dB / 0.75 dB step */
+#define RT766_HS_VOL_MAX 40 /* 30 dB / 0.75 dB step */
+#define RT766_HS_BOOST_VOL_MAX 20 /* 40 dB / 2 dB step */
+
+static const struct snd_kcontrol_new rt766_sdca_controls[] = {
+ SOC_DOUBLE_EXT("FU41 Playback Switch", SND_SOC_NOPM, 0, 1, 1, 0,
+ rt766_sdca_fu41_playback_get, rt766_sdca_fu41_playback_put),
+ SDCA_DOUBLE_Q78_TLV("FU41 Playback Volume",
+ RT766_VOLUME_REG(UAJ, USER_FU41, 1),
+ RT766_VOLUME_REG(UAJ, USER_FU41, 2),
+ RT766_HP_VOL_MIN, RT766_P_VOL_MAX, RT766_P75DB_STEP, hp_vol_tlv),
+ SOC_DOUBLE_EXT("FU36 Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0,
+ rt766_sdca_fu36_capture_get, rt766_sdca_fu36_capture_put),
+ SDCA_DOUBLE_Q78_TLV("FU36 Capture Volume",
+ RT766_VOLUME_REG(UAJ, USER_FU36, 1),
+ RT766_VOLUME_REG(UAJ, USER_FU36, 2),
+ RT766_HS_VOL_MIN, RT766_HS_VOL_MAX, RT766_P75DB_STEP, mic_vol_tlv),
+ SDCA_DOUBLE_Q78_TLV("FU33 Boost Volume",
+ RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1),
+ RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2),
+ RT766_HS_BOOST_VOL_MIN, RT766_HS_BOOST_VOL_MAX, RT766_2DB_STEP, boost_vol_tlv),
+
+ SOC_DOUBLE_EXT("FU21 Playback Switch", SND_SOC_NOPM, 0, 1, 1, 0,
+ rt766_sdca_fu21_playback_get, rt766_sdca_fu21_playback_put),
+ SDCA_DOUBLE_Q78_TLV("FU21 Playback Volume",
+ RT766_VOLUME_REG(AMP, USER_FU21, 1),
+ RT766_VOLUME_REG(AMP, USER_FU21, 2),
+ RT766_SPK_VOL_MIN, RT766_P_VOL_MAX, RT766_P75DB_STEP, spk_vol_tlv),
+ SOC_ENUM("RX Channel Select", rt766_rx_data_ch_enum),
+
+ RT_SDCA_FU_CTRL("FU113 Capture Switch",
+ RT766_MUTE_REG(MIC, USER_FU113, 1), 1, 1, 4, rt766_dmic_fu_info,
+ rt766_sdca_dmic_fu113_capture_get, rt766_sdca_dmic_fu113_capture_put),
+ RT_SDCA_EXT_TLV("FU113 Capture Volume",
+ RT766_VOLUME_REG(MIC, USER_FU113, 1),
+ rt766_sdca_dmic_set_gain_get, rt766_sdca_dmic_set_gain_put,
+ 4, 0x3f, mic_vol_tlv, rt766_dmic_fu_info),
+};
+
+static const struct snd_soc_dapm_widget rt766_sdca_dapm_widgets[] = {
+ /* UAJ */
+ SND_SOC_DAPM_OUTPUT("HP"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_SUPPLY("PDE 47", SND_SOC_NOPM, 0, 0,
+ rt766_sdca_pde47_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 34", SND_SOC_NOPM, 0, 0,
+ rt766_sdca_pde34_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("FU 41", NULL, SND_SOC_NOPM, 0, 0,
+ rt766_sdca_fu41_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("FU 36", NULL, SND_SOC_NOPM, 0, 0,
+ rt766_sdca_fu36_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP12TX", "DP12 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* AMP */
+ SND_SOC_DAPM_OUTPUT("SPOL"),
+ SND_SOC_DAPM_OUTPUT("SPOR"),
+ SND_SOC_DAPM_DAC_E("FU 21", NULL, SND_SOC_NOPM, 0, 0,
+ rt766_sdca_fu21_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0,
+ rt766_sdca_pde23_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+ /* DMIC */
+ SND_SOC_DAPM_INPUT("DMIC1"),
+ SND_SOC_DAPM_INPUT("DMIC2"),
+ SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0,
+ rt766_sdca_pde11_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("FU 113", NULL, SND_SOC_NOPM, 0, 0,
+ rt766_sdca_fu113_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_AIF_OUT("DP8TX", "DP8 Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt766_sdca_audio_map[] = {
+ { "FU 41", NULL, "DP3RX" },
+ { "DP12TX", NULL, "FU 36" },
+ { "FU 36", NULL, "PDE 34" },
+ { "FU 36", NULL, "MIC2" },
+ { "HP", NULL, "PDE 47" },
+ { "HP", NULL, "FU 41" },
+
+ { "FU 21", NULL, "DP1RX" },
+ { "FU 21", NULL, "PDE 23" },
+ { "SPOL", NULL, "FU 21" },
+ { "SPOR", NULL, "FU 21" },
+
+ {"DP8TX", NULL, "FU 113"},
+ {"FU 113", NULL, "PDE 11"},
+ {"FU 113", NULL, "DMIC1"},
+ {"FU 113", NULL, "DMIC2"},
+};
+
+static int rt766_sdca_probe(struct snd_soc_component *component)
+{
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ struct device *dev = &rt766->slave->dev;
+ int ret;
+
+ rt766->component = component;
+
+ ret = pm_runtime_resume(component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ if (rt766->uaj_func_data) {
+ dev_dbg(dev, "%s : irq %d\n", __func__, rt766->slave->irq);
+
+ rt766->irq_info = devm_sdca_irq_allocate(dev, rt766->regmap, rt766->slave->irq);
+ if (IS_ERR(rt766->irq_info))
+ return PTR_ERR(rt766->irq_info);
+
+ ret = rt766_sdca_irq_ctl(rt766, rt766->uaj_func_data,
+ component, rt766->irq_info, true);
+ if (ret < 0) {
+ dev_err(dev, "Failed to request UAJ SDCA IRQ: %d\n", ret);
+ return ret;
+ }
+
+ if (rt766->hid_func_data) {
+ ret = rt766_sdca_irq_ctl(rt766, rt766->hid_func_data,
+ component, rt766->irq_info, true);
+ if (ret < 0) {
+ dev_err(dev, "Failed to request HID SDCA IRQ: %d\n", ret);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void rt766_sdca_remove(struct snd_soc_component *component)
+{
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ sdca_irq_cleanup_late(component->dev, rt766->uaj_func_data, rt766->irq_info);
+ sdca_irq_cleanup_late(component->dev, rt766->hid_func_data, rt766->irq_info);
+}
+
+static const struct snd_soc_component_driver soc_sdca_dev_rt766 = {
+ .probe = rt766_sdca_probe,
+ .remove = rt766_sdca_remove,
+ .controls = rt766_sdca_controls,
+ .num_controls = ARRAY_SIZE(rt766_sdca_controls),
+ .dapm_widgets = rt766_sdca_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt766_sdca_dapm_widgets),
+ .dapm_routes = rt766_sdca_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rt766_sdca_audio_map),
+ .set_jack = rt766_sdca_set_jack_detect,
+ .endianness = 1,
+};
+
+static int rt766_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 rt766_sdca_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int rt766_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 rt766_sdca_priv *rt766 = 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;
+ unsigned int sampling_rate;
+ int retval, port;
+
+ dev_dbg(dai->dev, "%s %s id %d", __func__, dai->name, dai->id);
+ sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ if (!rt766->slave)
+ return -EINVAL;
+
+ /* SoundWire specific configuration */
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
+
+ /* SoundWire specific configuration */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ direction = SDW_DATA_DIR_RX;
+ if (dai->id == RT766_AIF1)
+ port = 3;
+ else if (dai->id == RT766_AIF2)
+ port = 1;
+ else
+ return -EINVAL;
+ } else {
+ direction = SDW_DATA_DIR_TX;
+ if (dai->id == RT766_AIF1)
+ port = 12;
+ else if (dai->id == RT766_AIF3)
+ port = 8;
+ else
+ return -EINVAL;
+ }
+
+ port_config.num = port;
+ retval = sdw_stream_add_slave(rt766->slave, &stream_config,
+ &port_config, 1, sdw_stream);
+ if (retval) {
+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
+ return retval;
+ }
+
+ if (params_channels(params) > 16) {
+ dev_err(component->dev, "%s: Unsupported channels %d\n",
+ __func__, params_channels(params));
+ return -EINVAL;
+ }
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 44100:
+ sampling_rate = RT766_SDCA_RATE_44100HZ;
+ break;
+ case 48000:
+ sampling_rate = RT766_SDCA_RATE_48000HZ;
+ break;
+ case 96000:
+ sampling_rate = RT766_SDCA_RATE_96000HZ;
+ break;
+ case 192000:
+ sampling_rate = RT766_SDCA_RATE_192000HZ;
+ break;
+ default:
+ dev_err(component->dev, "%s: Rate %d is not supported\n",
+ __func__, params_rate(params));
+ return -EINVAL;
+ }
+
+ /* set sampling frequency */
+ switch (dai->id) {
+ case RT766_AIF1:
+ regmap_write(rt766->regmap,
+ RT766_SDCA_CTL(UAJ, CS41, SDCA_CTL_CS_SAMPLERATEINDEX),
+ sampling_rate);
+ regmap_write(rt766->regmap,
+ RT766_SDCA_CTL(UAJ, CS36, SDCA_CTL_CS_SAMPLERATEINDEX),
+ sampling_rate);
+ break;
+ case RT766_AIF2:
+ regmap_write(rt766->regmap,
+ RT766_SDCA_CTL(AMP, CS21, SDCA_CTL_CS_SAMPLERATEINDEX),
+ sampling_rate);
+ break;
+ case RT766_AIF3:
+ regmap_write(rt766->regmap,
+ RT766_SDCA_CTL(MIC, CS113, SDCA_CTL_CS_SAMPLERATEINDEX),
+ sampling_rate);
+ break;
+ default:
+ dev_err(component->dev, "%s: Wrong DAI id\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rt766_sdca_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_runtime *sdw_stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt766->slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt766->slave, sdw_stream);
+ return 0;
+}
+
+#define RT766_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_192000)
+#define RT766_DAC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+#define RT766_ADC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops rt766_sdca_ops = {
+ .hw_params = rt766_sdca_pcm_hw_params,
+ .hw_free = rt766_sdca_pcm_hw_free,
+ .set_stream = rt766_sdca_set_sdw_stream,
+ .shutdown = rt766_sdca_shutdown,
+};
+
+static struct snd_soc_dai_driver rt766_sdca_dai[] = {
+ {
+ .name = "rt766-sdca-aif1",
+ .id = RT766_AIF1,
+ .playback = {
+ .stream_name = "DP3 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT766_STEREO_RATES,
+ .formats = RT766_DAC_FORMATS,
+ },
+ .capture = {
+ .stream_name = "DP12 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT766_STEREO_RATES,
+ .formats = RT766_ADC_FORMATS,
+ },
+ .ops = &rt766_sdca_ops,
+ .symmetric_rate = 1,
+ },
+ {
+ .name = "rt766-sdca-aif2",
+ .id = RT766_AIF2,
+ .playback = {
+ .stream_name = "DP1 Playback",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = RT766_STEREO_RATES,
+ .formats = RT766_DAC_FORMATS,
+ },
+ .ops = &rt766_sdca_ops,
+ },
+ {
+ .name = "rt766-sdca-aif3",
+ .id = RT766_AIF3,
+ .capture = {
+ .stream_name = "DP8 Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = RT766_STEREO_RATES,
+ .formats = RT766_ADC_FORMATS,
+ },
+ .ops = &rt766_sdca_ops,
+ }
+};
+
+static unsigned int rt766_find_dt_rates(struct device *dev, struct sdca_function_data *function,
+ const char *label)
+{
+ struct snd_soc_pcm_stream stream;
+ struct sdca_entity *entity;
+ int i, ret;
+
+ for (i = 0; i < function->num_entities; i++) {
+ entity = &function->entities[i];
+
+ if (strcmp(entity->label, label))
+ continue;
+
+ /* Can't check earlier as only terminals have an iot member. */
+ if (!entity->iot.is_dataport)
+ continue;
+
+ ret = sdca_asoc_populate_rate_format(dev, function, entity, &stream);
+ if (ret < 0) {
+ dev_dbg(dev, "%s: failed to parse rates for entity %s\n",
+ __func__, entity->label);
+ return 0;
+ }
+
+ dev_dbg(dev, "%s: %s supports rates 0x%08x\n", __func__, entity->label, stream.rates);
+ }
+
+ return stream.rates;
+}
+
+int rt766_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave)
+{
+ struct sdca_function_data *func_data_ptr;
+ struct snd_soc_dai_driver *dai_drv;
+ struct rt766_sdca_priv *rt766;
+ unsigned int rates;
+ int ret;
+ int i;
+
+ rt766 = devm_kzalloc(dev, sizeof(*rt766), GFP_KERNEL);
+ if (!rt766)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt766);
+ rt766->slave = slave;
+ rt766->regmap = regmap;
+
+ regcache_cache_only(rt766->regmap, true);
+
+ ret = devm_mutex_init(dev, &rt766->disable_irq_lock);
+ if (ret < 0) {
+ dev_err(dev, "Failed to initialize mutex\n");
+ return ret;
+ }
+
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt766->hw_init = false;
+ rt766->first_hw_init = false;
+ rt766->fu41_dapm_mute = true;
+ rt766->fu41_mixer_l_mute = rt766->fu41_mixer_r_mute = false;
+ rt766->fu36_dapm_mute = true;
+ rt766->fu36_mixer_l_mute = rt766->fu36_mixer_r_mute = true;
+ rt766->fu21_dapm_mute = true;
+ rt766->fu21_mixer_l_mute = rt766->fu21_mixer_r_mute = false;
+ rt766->fu113_dapm_mute = true;
+ rt766->fu113_mixer_mute[0] = rt766->fu113_mixer_mute[1] =
+ rt766->fu113_mixer_mute[2] = rt766->fu113_mixer_mute[3] = true;
+
+ dai_drv = devm_kzalloc(dev, sizeof(struct snd_soc_dai_driver) * ARRAY_SIZE(rt766_sdca_dai), GFP_KERNEL);
+ if (!dai_drv) {
+ dev_err(dev, "Failed to allocate memory for DAI driver\n");
+ ret = -ENOMEM;
+ goto _sdw_init_err_;
+ }
+ memcpy(dai_drv, rt766_sdca_dai, sizeof(struct snd_soc_dai_driver) * ARRAY_SIZE(rt766_sdca_dai));
+
+ /* get SDCA function data */
+ dev_dbg(dev, "SDCA functions found: %d", slave->sdca_data.num_functions);
+ for (i = 0; i < slave->sdca_data.num_functions; i++) {
+ func_data_ptr = devm_kzalloc(dev, sizeof(*func_data_ptr), GFP_KERNEL);
+ if (!func_data_ptr) {
+ dev_err(dev, "Failed to allocate memory for function data\n");
+ ret = -ENOMEM;
+ goto _free_dai_drv_;
+ }
+
+ func_data_ptr->desc = &slave->sdca_data.function[i];
+ ret = sdca_parse_function(dev, func_data_ptr);
+ if (ret) {
+ devm_kfree(dev, func_data_ptr);
+ goto _free_dai_drv_;
+ }
+ dev_dbg(dev, "Function type=%d, num_entities=%d",
+ slave->sdca_data.function[i].type, func_data_ptr->num_entities);
+
+ switch (slave->sdca_data.function[i].type) {
+ case SDCA_FUNCTION_TYPE_UAJ:
+ rt766->uaj_func_data = func_data_ptr;
+ /*
+ * Some machines may only support a subset of the sample rates supported by the codec.
+ * Therefore, we need to parse the supported sample rates from the DisCo table and
+ * configure them in the DAI. If the DisCo table does not provide sample rate information,
+ * we will fall back to the default supported rates defined in the codec driver.
+ */
+ rates = rt766_find_dt_rates(dev, func_data_ptr, "IT 41");
+ if (rates)
+ dai_drv[RT766_DAI_UAJ].playback.rates = rates;
+
+ rates = rt766_find_dt_rates(dev, func_data_ptr, "OT 36");
+ if (rates)
+ dai_drv[RT766_DAI_UAJ].capture.rates = rates;
+ break;
+ case SDCA_FUNCTION_TYPE_SMART_AMP:
+ rt766->sa_func_data = func_data_ptr;
+ rates = rt766_find_dt_rates(dev, func_data_ptr, "IT 21");
+ if (rates)
+ dai_drv[RT766_DAI_AMP].playback.rates = rates;
+ break;
+ case SDCA_FUNCTION_TYPE_SMART_MIC:
+ rt766->sm_func_data = func_data_ptr;
+ rates = rt766_find_dt_rates(dev, func_data_ptr, "OT 113");
+ if (rates)
+ dai_drv[RT766_DAI_MIC].capture.rates = rates;
+ break;
+ case SDCA_FUNCTION_TYPE_HID:
+ rt766->hid_func_data = func_data_ptr;
+ break;
+ default:
+ dev_dbg(dev, "Unexpected SDCA function type found: %d",
+ slave->sdca_data.function[i].type);
+ }
+ }
+
+ ret = devm_snd_soc_register_component(dev,
+ &soc_sdca_dev_rt766, dai_drv, ARRAY_SIZE(rt766_sdca_dai));
+ if (ret < 0)
+ goto _free_dai_drv_;
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+ dev_dbg(dev, "%s\n", __func__);
+ return 0;
+
+_free_dai_drv_:
+ if (dai_drv)
+ devm_kfree(dev, dai_drv);
+
+_sdw_init_err_:
+ return ret;
+}
+
+static int rt766_func_initialize(struct rt766_sdca_priv *rt766, struct sdca_function_data *func_data)
+{
+ struct device *dev = &rt766->slave->dev;
+ unsigned int func_status_reg;
+ unsigned int func_status;
+ int ret;
+
+ switch (func_data->desc->type) {
+ case SDCA_FUNCTION_TYPE_UAJ:
+ func_status_reg = RT766_FUNC_STATUS_REG(UAJ);
+ break;
+ case SDCA_FUNCTION_TYPE_SMART_AMP:
+ func_status_reg = RT766_FUNC_STATUS_REG(AMP);
+ break;
+ case SDCA_FUNCTION_TYPE_SMART_MIC:
+ func_status_reg = RT766_FUNC_STATUS_REG(MIC);
+ break;
+ case SDCA_FUNCTION_TYPE_HID:
+ func_status_reg = RT766_FUNC_STATUS_REG(HID);
+ break;
+ default:
+ dev_dbg(dev, "Unexpected SDCA function type found: %d",
+ func_data->desc->type);
+ return -EINVAL;
+ }
+
+ regmap_read(rt766->regmap, func_status_reg, &func_status);
+ dev_dbg(dev, "%s, %s func_status=0x%x\n", __func__, func_data->desc->name, func_status);
+
+ if ((func_status & SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION) || (!rt766->first_hw_init)) {
+ ret = sdca_regmap_write_init(dev, rt766->regmap, func_data);
+ if (ret) {
+ dev_err(dev, "%s initialization table update failed\n", func_data->desc->name);
+ goto _func_init_err_;
+ }
+
+ regmap_write(rt766->regmap, func_status_reg,
+ SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION);
+ }
+
+ return 0;
+
+_func_init_err_:
+ dev_err(dev, "%s: %s init writes failed, err=%d", __func__, func_data->desc->name, ret);
+ return ret;
+}
+
+int rt766_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev);
+ unsigned int val;
+
+ rt766->disable_irq = false;
+
+ if (rt766->hw_init)
+ return 0;
+
+ regcache_cache_only(rt766->regmap, false);
+ if (rt766->first_hw_init) {
+ regcache_cache_bypass(rt766->regmap, true);
+ } else {
+ /*
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
+ */
+
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+
+ regmap_read(rt766->regmap, RT766_BOND_LATCH_ID, &val);
+ dev_dbg(&slave->dev, "%s bond ID=0x%x (%s)\n", __func__, val, (val == 0x1) ? "RT767" : "RT766");
+
+ /* check function status and initialize if needed */
+ if (rt766->uaj_func_data)
+ rt766_func_initialize(rt766, rt766->uaj_func_data);
+ if (rt766->sa_func_data)
+ rt766_func_initialize(rt766, rt766->sa_func_data);
+ if (rt766->sm_func_data)
+ rt766_func_initialize(rt766, rt766->sm_func_data);
+ if (rt766->hid_func_data)
+ rt766_func_initialize(rt766, rt766->hid_func_data);
+
+ if (rt766->first_hw_init) {
+ regcache_cache_bypass(rt766->regmap, false);
+ regcache_mark_dirty(rt766->regmap);
+ } else {
+ rt766->first_hw_init = true;
+ }
+
+ /* Mark Slave initialization complete */
+ rt766->hw_init = true;
+
+ dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
+
+ pm_runtime_put_autosuspend(&slave->dev);
+
+ return 0;
+}
+
+MODULE_DESCRIPTION("ASoC RT766 SDCA SDW driver");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_SDCA");
diff --git a/sound/soc/codecs/rt766-sdca.h b/sound/soc/codecs/rt766-sdca.h
new file mode 100644
index 000000000000..de4064007eb9
--- /dev/null
+++ b/sound/soc/codecs/rt766-sdca.h
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt766-sdca.h -- RT766 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2026 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT766_H__
+#define __RT766_H__
+
+#include <linux/hid.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 rt766_sdca_priv {
+ struct regmap *regmap;
+ struct snd_soc_component *component;
+ struct sdw_slave *slave;
+ bool hw_init;
+ bool first_hw_init;
+ struct snd_soc_jack *hs_jack;
+ struct mutex disable_irq_lock; /* SDCA irq lock protection */
+ bool disable_irq;
+ int jack_type;
+ bool fu41_dapm_mute;
+ bool fu41_mixer_l_mute;
+ bool fu41_mixer_r_mute;
+ bool fu113_dapm_mute;
+ bool fu113_mixer_mute[4];
+ bool fu21_dapm_mute;
+ bool fu21_mixer_l_mute;
+ bool fu21_mixer_r_mute;
+ bool fu36_dapm_mute;
+ bool fu36_mixer_l_mute;
+ bool fu36_mixer_r_mute;
+ struct sdca_function_data *uaj_func_data;
+ struct sdca_function_data *sm_func_data;
+ struct sdca_function_data *sa_func_data;
+ struct sdca_function_data *hid_func_data;
+ struct sdca_interrupt_info *irq_info;
+ struct hid_device *hid;
+};
+
+/* vendor registers */
+#define RT766_VERSION_ID 0xc404
+#define RT766_DEV_ID1 0xc405
+#define RT766_DEV_ID0 0xc406
+#define RT766_BOND_LATCH_ID 0xc407
+
+#define RT766_HP_POWER_STATE 0x1000004
+#define RT766_HP_FSM_CTL2_1 0x100000d
+
+/* MCU Patch address */
+#define RT766_MCU_PATCH_ADDR1_START 0x10010000
+#define RT766_MCU_PATCH_ADDR1_END 0x10011fff
+#define RT766_MCU_PATCH_ADDR2_START 0x10020000
+#define RT766_MCU_PATCH_ADDR2_END 0x10023fff
+
+/* Buffer address for HID */
+#define RT766_BUF_ADDR_HID1 0x44030000
+#define RT766_BUF_ADDR_HID2 0x44030020
+
+/* SDCA (Channel) */
+#define RT766_CH_1 0x01
+#define RT766_CH_2 0x02
+#define RT766_CH_3 0x03
+#define RT766_CH_4 0x04
+
+/* RT766 SDCA Control - function number */
+#define RT766_FUNC_NUM_UAJ 0x01
+#define RT766_FUNC_NUM_MIC 0x02
+#define RT766_FUNC_NUM_HID 0x03
+#define RT766_FUNC_NUM_AMP 0x04
+
+/* RT766 SDCA entity */
+#define RT766_SDCA_ENT_0 0x00
+#define RT766_SDCA_ENT_HID101 0x01
+#define RT766_SDCA_ENT_GE49 0x49
+#define RT766_SDCA_ENT_USER_FU41 0x05
+#define RT766_SDCA_ENT_USER_FU36 0x0f
+#define RT766_SDCA_ENT_USER_FU21 0x03
+#define RT766_SDCA_ENT_USER_FU113 0x30
+#define RT766_SDCA_ENT_PDE23 0x33
+#define RT766_SDCA_ENT_PDE47 0x28
+#define RT766_SDCA_ENT_PDE11 0x2a
+#define RT766_SDCA_ENT_PDE34 0x29
+#define RT766_SDCA_ENT_CS41 0x01
+#define RT766_SDCA_ENT_CS36 0x11
+#define RT766_SDCA_ENT_CS113 0x12
+#define RT766_SDCA_ENT_CS21 0x21
+#define RT766_SDCA_ENT_PLATFORM_FU33 0x44
+#define RT766_SDCA_ENT_PPU21 0x04
+
+/* sample frequency index */
+#define RT766_SDCA_RATE_44100HZ 0x08
+#define RT766_SDCA_RATE_48000HZ 0x09
+#define RT766_SDCA_RATE_96000HZ 0x0b
+#define RT766_SDCA_RATE_192000HZ 0x0d
+
+/* SDCA Register macros */
+#define RT766_MUTE_REG(func, fu, ch) \
+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##fu, SDCA_CTL_FU_MUTE, RT766_CH_##ch)
+
+#define RT766_VOLUME_REG(func, fu, ch) \
+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##fu, SDCA_CTL_FU_CHANNEL_VOLUME, RT766_CH_##ch)
+
+#define RT766_GAIN_REG(func, fu, ch) \
+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##fu, SDCA_CTL_FU_GAIN, RT766_CH_##ch)
+
+#define RT766_PDE_REQ_REG(func, pde) \
+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##pde, SDCA_CTL_PDE_REQUESTED_PS, 0)
+
+#define RT766_PDE_ACTUAL_REG(func, pde) \
+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##pde, SDCA_CTL_PDE_ACTUAL_PS, 0)
+
+#define RT766_FUNC_STATUS_REG(func) \
+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_0, SDCA_CTL_ENTITY_0_FUNCTION_STATUS, 0)
+
+#define RT766_SDCA_CTL(func, ent, ctl) \
+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##ent, ctl, 0)
+
+enum {
+ RT766_AIF1,
+ RT766_AIF2,
+ RT766_AIF3,
+};
+
+enum {
+ RT766_DAI_UAJ,
+ RT766_DAI_AMP,
+ RT766_DAI_MIC,
+};
+
+int rt766_sdca_io_init(struct device *dev, struct sdw_slave *slave);
+int rt766_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave);
+#endif /* __RT766_H__ */
diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c
index 97f56af25577..e51cd4a31894 100644
--- a/sound/soc/codecs/rt9120.c
+++ b/sound/soc/codecs/rt9120.c
@@ -606,12 +606,19 @@ static int rt9120_runtime_suspend(struct device *dev)
static int rt9120_runtime_resume(struct device *dev)
{
struct rt9120_data *data = dev_get_drvdata(dev);
+ int ret;
if (data->pwdnn_gpio) {
gpiod_set_value(data->pwdnn_gpio, 1);
msleep(RT9120_CHIPON_WAITMS);
regcache_cache_only(data->regmap, false);
- regcache_sync(data->regmap);
+ ret = regcache_sync(data->regmap);
+ if (ret) {
+ regcache_cache_only(data->regmap, true);
+ regcache_mark_dirty(data->regmap);
+ gpiod_set_value(data->pwdnn_gpio, 0);
+ return ret;
+ }
}
return 0;
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 59642673b4cb..35df1a8c4c8c 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -56,8 +56,8 @@ static const struct reg_default sgtl5000_reg_defaults[] = {
{ SGTL5000_CHIP_PLL_CTRL, 0x5000 },
{ SGTL5000_CHIP_CLK_TOP_CTRL, 0x0000 },
{ SGTL5000_CHIP_ANA_STATUS, 0x0000 },
- { SGTL5000_CHIP_SHORT_CTRL, 0x0000 },
{ SGTL5000_CHIP_ANA_TEST2, 0x0000 },
+ { SGTL5000_CHIP_SHORT_CTRL, 0x0000 },
{ SGTL5000_DAP_CTRL, 0x0000 },
{ SGTL5000_DAP_PEQ, 0x0000 },
{ SGTL5000_DAP_BASS_ENHANCE, 0x0040 },
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c
index 2e08fde3989c..4ecbbac93258 100644
--- a/sound/soc/codecs/sigmadsp.c
+++ b/sound/soc/codecs/sigmadsp.c
@@ -5,6 +5,7 @@
* Copyright 2009-2014 Analog Devices Inc.
*/
+#include <linux/cleanup.h>
#include <linux/crc32.h>
#include <linux/firmware.h>
#include <linux/kernel.h>
@@ -135,7 +136,7 @@ static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol,
uint8_t *data;
int ret = 0;
- mutex_lock(&sigmadsp->lock);
+ guard(mutex)(&sigmadsp->lock);
data = ucontrol->value.bytes.data;
@@ -148,8 +149,6 @@ static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol,
ctrl->cached = true;
}
- mutex_unlock(&sigmadsp->lock);
-
return ret;
}
@@ -160,7 +159,7 @@ static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol,
struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol);
int ret = 0;
- mutex_lock(&sigmadsp->lock);
+ guard(mutex)(&sigmadsp->lock);
if (!ctrl->cached) {
ret = sigmadsp_read(sigmadsp, ctrl->addr, ctrl->cache,
@@ -174,8 +173,6 @@ static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol,
ctrl->num_bytes);
}
- mutex_unlock(&sigmadsp->lock);
-
return ret;
}
@@ -487,7 +484,7 @@ static void devm_sigmadsp_release(struct device *dev, void *res)
static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
{
const struct sigma_firmware_header *ssfw_head;
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
int ret;
u32 crc;
@@ -495,7 +492,7 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
ret = request_firmware(&fw, name, sigmadsp->dev);
if (ret) {
pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
- goto done;
+ return ret;
}
/* then verify the header */
@@ -509,13 +506,13 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
*/
if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) {
dev_err(sigmadsp->dev, "Failed to load firmware: Invalid size\n");
- goto done;
+ return -EINVAL;
}
ssfw_head = (void *)fw->data;
if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) {
dev_err(sigmadsp->dev, "Failed to load firmware: Invalid magic\n");
- goto done;
+ return -EINVAL;
}
crc = crc32(0, fw->data + sizeof(*ssfw_head),
@@ -524,7 +521,7 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
if (crc != le32_to_cpu(ssfw_head->crc)) {
dev_err(sigmadsp->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n",
le32_to_cpu(ssfw_head->crc), crc);
- goto done;
+ return -EINVAL;
}
switch (ssfw_head->version) {
@@ -545,9 +542,6 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
if (ret)
sigmadsp_firmware_release(sigmadsp);
-done:
- release_firmware(fw);
-
return ret;
}
@@ -677,10 +671,10 @@ static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp,
return;
changed = snd_ctl_activate_id(card, &ctrl->kcontrol->id, active);
if (active && changed > 0) {
- mutex_lock(&sigmadsp->lock);
- if (ctrl->cached)
- sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache);
- mutex_unlock(&sigmadsp->lock);
+ scoped_guard(mutex, &sigmadsp->lock) {
+ if (ctrl->cached)
+ sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache);
+ }
}
}
diff --git a/sound/soc/codecs/sma1303.c b/sound/soc/codecs/sma1303.c
index 7fce60de5e5f..15758eb13f8c 100644
--- a/sound/soc/codecs/sma1303.c
+++ b/sound/soc/codecs/sma1303.c
@@ -1777,6 +1777,8 @@ static void sma1303_i2c_remove(struct i2c_client *client)
struct sma1303_priv *sma1303 =
(struct sma1303_priv *) i2c_get_clientdata(client);
+ if (sma1303->attr_grp)
+ sysfs_remove_group(sma1303->kobj, sma1303->attr_grp);
cancel_delayed_work_sync(&sma1303->check_fault_work);
}
diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c
index c52fe95b30c6..adb369a29b9d 100644
--- a/sound/soc/codecs/sma1307.c
+++ b/sound/soc/codecs/sma1307.c
@@ -1690,7 +1690,7 @@ static void sma1307_check_fault_worker(struct work_struct *work)
static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *file)
{
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
int size, offset, num_mode;
int ret;
@@ -1703,22 +1703,18 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
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;
}
int *data __free(kfree) = kzalloc(fw->size, GFP_KERNEL);
if (!data) {
- release_firmware(fw);
sma1307->set.status = false;
return;
}
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];
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 652c6e3a9e63..d6de739212f9 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pm.h>
@@ -269,9 +270,9 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
int numcoef = kcontrol->private_value >> 16;
int index = kcontrol->private_value & 0xffff;
unsigned int cfud, val;
- int i, ret = 0;
+ int i;
- mutex_lock(&sta32x->coeff_lock);
+ guard(mutex)(&sta32x->coeff_lock);
/* preserve reserved bits in STA32X_CFUD */
regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
@@ -283,24 +284,20 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
- if (numcoef == 1) {
+ if (numcoef == 1)
regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04);
- } else if (numcoef == 5) {
+ else if (numcoef == 5)
regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08);
- } else {
- ret = -EINVAL;
- goto exit_unlock;
- }
+ else
+ return -EINVAL;
+
for (i = 0; i < 3 * numcoef; i++) {
regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val);
ucontrol->value.bytes.data[i] = val;
}
-exit_unlock:
- mutex_unlock(&sta32x->coeff_lock);
-
- return ret;
+ return 0;
}
static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
index 99c7f7ac807b..2ba35076732b 100644
--- a/sound/soc/codecs/sta350.c
+++ b/sound/soc/codecs/sta350.c
@@ -16,6 +16,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -306,9 +307,9 @@ static int sta350_coefficient_get(struct snd_kcontrol *kcontrol,
int numcoef = kcontrol->private_value >> 16;
int index = kcontrol->private_value & 0xffff;
unsigned int cfud, val;
- int i, ret = 0;
+ int i;
- mutex_lock(&sta350->coeff_lock);
+ guard(mutex)(&sta350->coeff_lock);
/* preserve reserved bits in STA350_CFUD */
regmap_read(sta350->regmap, STA350_CFUD, &cfud);
@@ -320,24 +321,19 @@ static int sta350_coefficient_get(struct snd_kcontrol *kcontrol,
regmap_write(sta350->regmap, STA350_CFUD, cfud);
regmap_write(sta350->regmap, STA350_CFADDR2, index);
- if (numcoef == 1) {
+ if (numcoef == 1)
regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x04);
- } else if (numcoef == 5) {
+ else if (numcoef == 5)
regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x08);
- } else {
- ret = -EINVAL;
- goto exit_unlock;
- }
+ else
+ return -EINVAL;
for (i = 0; i < 3 * numcoef; i++) {
regmap_read(sta350->regmap, STA350_B1CF1 + i, &val);
ucontrol->value.bytes.data[i] = val;
}
-exit_unlock:
- mutex_unlock(&sta350->coeff_lock);
-
- return ret;
+ return 0;
}
static int sta350_coefficient_put(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c
index 4ab15be69f3a..b7eaf4795d8b 100644
--- a/sound/soc/codecs/sti-sas.c
+++ b/sound/soc/codecs/sti-sas.c
@@ -44,8 +44,8 @@ enum {
};
static const struct reg_default stih407_sas_reg_defaults[] = {
- { STIH407_AUDIO_DAC_CTRL, 0x000000000 },
{ STIH407_AUDIO_GLUE_CTRL, 0x00000040 },
+ { STIH407_AUDIO_DAC_CTRL, 0x000000000 },
};
struct sti_dac_audio {
diff --git a/sound/soc/codecs/tac5xx2-sdw.c b/sound/soc/codecs/tac5xx2-sdw.c
index ace06f5ab58c..c062065a807d 100644
--- a/sound/soc/codecs/tac5xx2-sdw.c
+++ b/sound/soc/codecs/tac5xx2-sdw.c
@@ -88,6 +88,9 @@
#define TAC_FW_FILE_HDR 20
#define TAC_MAX_FW_CHUNKS 512
+#define TAC_UAJ_PREP_CONNECTED 0xff
+#define TAC_UAJ_PREP_DISCONNECTED 0xdf
+
struct tac_fw_hdr {
u32 size;
u32 version_offset;
@@ -138,6 +141,7 @@ struct tac5xx2_prv {
bool hw_init;
bool first_hw_init_done;
u32 part_id;
+ u32 rev_id;
struct snd_soc_jack *hs_jack;
int jack_type;
/* Custom fw binary. UMP File Download is not used. */
@@ -261,7 +265,6 @@ static const struct reg_default tac_reg_default[] = {
{TAC_REG_SDW(0, 0, 0x78), 0x0},
{TAC_REG_SDW(0, 0, 0x7b), 0x0},
{TAC_REG_SDW(0, 0, 0x7c), 0xd0},
- {TAC_REG_SDW(0, 0, 0x7d), 0x0},
{TAC_REG_SDW(0, 0, 0x7e), 0x0},
{TAC_REG_SDW(0, 1, 0x1), 0x0},
{TAC_REG_SDW(0, 1, 0x2), 0x0},
@@ -507,18 +510,6 @@ static const struct regmap_config tac_regmap = {
.use_single_write = true,
};
-/* Check if device has DSP algo that needs status monitoring */
-static bool tac_has_dsp_algo(struct tac5xx2_prv *tac_dev)
-{
- switch (tac_dev->part_id) {
- case 0x5682:
- case 0x2883:
- return true;
- default:
- return false;
- }
-}
-
/* Check if device has UAJ (Universal Audio Jack) support */
static bool tac_has_uaj_support(struct tac5xx2_prv *tac_dev)
{
@@ -800,7 +791,7 @@ static int tac_sdw_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- ret = sdca_asoc_pde_poll_actual_ps(tac_dev->dev, tac_dev->regmap, function_id, pde_entity,
+ ret = sdca_asoc_pde_poll_actual_ps(tac_dev->regmap, function_id, pde_entity,
SDCA_PDE_PS3, SDCA_PDE_PS0, NULL, 0);
if (ret)
dev_err(tac_dev->dev, "failed to transition func %d, pde %d from PS3 -> PS0, err=%d\n",
@@ -847,7 +838,7 @@ static int tac_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
return ret;
}
- ret = sdca_asoc_pde_poll_actual_ps(tac_dev->dev, tac_dev->regmap, function_id,
+ ret = sdca_asoc_pde_poll_actual_ps(tac_dev->regmap, function_id,
pde_entity, SDCA_PDE_PS0, SDCA_PDE_PS3,
NULL, 0);
if (ret)
@@ -942,6 +933,7 @@ end_btn_det:
static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev)
{
int val, ret;
+ u8 jack_prep;
ret = regmap_read(tac_dev->regmap,
SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_GE35,
@@ -951,6 +943,8 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev)
return ret;
}
+ jack_prep = TAC_UAJ_PREP_CONNECTED;
+
switch (val) {
case 4:
tac_dev->jack_type = SND_JACK_MICROPHONE;
@@ -964,6 +958,7 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev)
case 0:
default:
tac_dev->jack_type = 0;
+ jack_prep = TAC_UAJ_PREP_DISCONNECTED;
break;
}
@@ -973,26 +968,44 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev)
if (ret)
dev_err(tac_dev->dev, "Failed to update the jack type to device");
+ /*
+ * When uaj is uplugged and booted, we end up with the channel prepare
+ * timeout error for the uaj ports. This writes allows the channel prepare
+ * to succeed when the uaj is not plugged in.
+ */
+ if (tac_dev->rev_id >= 0x30) {
+ ret = regmap_write(tac_dev->regmap, TAC_REG_SDW(0, 3, 127), jack_prep);
+ if (ret)
+ dev_warn(tac_dev->dev, "Failed to write jack_prep register: %d\n", ret);
+ }
+
return 0;
}
static int tac5xx2_jack_init(struct tac5xx2_prv *tac_dev)
{
+ u32 jd_int_mask, hid_int_mask;
int ret = 0;
+ if (tac_dev->rev_id >= 0x30) {
+ jd_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_12;
+ hid_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_17;
+ } else {
+ jd_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_11;
+ hid_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_16;
+ }
+
if (!tac_dev->hs_jack)
goto disable_interrupts;
- ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK2,
- SDW_SCP_SDCA_INTMASK_SDCA_11);
+ ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK2, jd_int_mask);
if (ret) {
dev_err(tac_dev->dev,
"Failed to register jack detection interrupt: %d\n", ret);
goto disable_interrupts;
}
- ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK3,
- SDW_SCP_SDCA_INTMASK_SDCA_16);
+ ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK3, hid_int_mask);
if (ret) {
dev_err(tac_dev->dev,
"Failed to register for button detect interrupt: %d\n", ret);
@@ -1051,6 +1064,7 @@ static int tac_interrupt_callback(struct sdw_slave *slave,
unsigned int sdca_int2, sdca_int3, jack_report_mask = 0;
struct tac5xx2_prv *tac_dev = dev_get_drvdata(&slave->dev);
struct device *dev = &slave->dev;
+ u32 headset_detect_chk, hid_detect_chk;
int btn_type = 0;
int ret = 0;
@@ -1081,14 +1095,22 @@ static int tac_interrupt_callback(struct sdw_slave *slave,
dev_dbg(dev, "SDCA_INT2: 0x%02x, SDCA_INT3: 0x%02x\n",
sdca_int2, sdca_int3);
- if (sdca_int2 & SDW_SCP_SDCA_INT_SDCA_11) {
+ if (tac_dev->rev_id >= 0x30) {
+ headset_detect_chk = SDW_SCP_SDCA_INT_SDCA_12;
+ hid_detect_chk = SDW_SCP_SDCA_INT_SDCA_17;
+ } else {
+ headset_detect_chk = SDW_SCP_SDCA_INT_SDCA_11;
+ hid_detect_chk = SDW_SCP_SDCA_INT_SDCA_16;
+ }
+
+ if (sdca_int2 & headset_detect_chk) {
ret = tac5xx2_sdca_headset_detect(tac_dev);
if (ret < 0)
goto clear;
jack_report_mask |= SND_JACK_HEADSET;
}
- if (sdca_int3 & SDW_SCP_SDCA_INT_SDCA_16) {
+ if (sdca_int3 & hid_detect_chk) {
btn_type = tac5xx2_sdca_button_detect(tac_dev);
if (btn_type < 0)
btn_type = 0;
@@ -1695,6 +1717,15 @@ static int tac_io_init(struct device *dev, struct sdw_slave *slave, bool first)
goto io_init_err;
}
+ if (!tac_dev->rev_id) {
+ ret = regmap_read(tac_dev->regmap, TAC_REV_ID, &tac_dev->rev_id);
+ if (ret) {
+ dev_err(tac_dev->dev, "failed to rev id, err=%d\n", ret);
+ goto io_init_err;
+ }
+ dev_dbg(tac_dev->dev, "detected rev_id 0x%x", tac_dev->rev_id);
+ }
+
if (tac_dev->fw_files && tac_dev->fw_file_cnt > 0) {
ret = tac_download_fw_to_hw(tac_dev);
if (ret) {
@@ -1940,7 +1971,7 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral,
"failed to allocate %s function data",
func_name);
function_data->desc = &peripheral->sdca_data.function[i];
- ret = sdca_parse_function(dev, peripheral, function_data);
+ ret = sdca_parse_function(dev, function_data);
if (!ret)
*func_ptr = function_data;
else
@@ -1959,6 +1990,7 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral,
tac_dev->hw_init = false;
tac_dev->first_hw_init_done = false;
tac_dev->part_id = id->part_id;
+ tac_dev->rev_id = 0x0;
dev_set_drvdata(dev, tac_dev);
regmap = devm_regmap_init_sdw_mbq_cfg(&peripheral->dev, peripheral,
@@ -1972,17 +2004,13 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral,
tac_dev->jack_type = 0;
init_completion(&tac_dev->fw_caching_complete);
- if (tac_has_dsp_algo(tac_dev)) {
- tac_generate_fw_name(peripheral, tac_dev->fw_binaryname,
- sizeof(tac_dev->fw_binaryname));
+ tac_generate_fw_name(peripheral, tac_dev->fw_binaryname,
+ sizeof(tac_dev->fw_binaryname));
- ret = tac_load_and_cache_firmware_async(tac_dev);
- if (ret) {
- complete_all(&tac_dev->fw_caching_complete);
- dev_dbg(dev, "failed to load fw: %d, use rom mode\n", ret);
- }
- } else {
+ ret = tac_load_and_cache_firmware_async(tac_dev);
+ if (ret) {
complete_all(&tac_dev->fw_caching_complete);
+ dev_dbg(dev, "failed to load fw: %d, use rom mode\n", ret);
}
ret = tac_init(tac_dev);
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index 1a7650b9b2a7..be2c9a0fa529 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -31,25 +31,25 @@
static const struct reg_default tas2552_reg_defs[] = {
{TAS2552_CFG_1, 0x22},
+ {TAS2552_CFG_2, 0xef},
{TAS2552_CFG_3, 0x80},
{TAS2552_DOUT, 0x00},
- {TAS2552_OUTPUT_DATA, 0xc0},
- {TAS2552_PDM_CFG, 0x01},
- {TAS2552_PGA_GAIN, 0x00},
- {TAS2552_BOOST_APT_CTRL, 0x0f},
- {TAS2552_RESERVED_0D, 0xbe},
- {TAS2552_LIMIT_RATE_HYS, 0x08},
- {TAS2552_CFG_2, 0xef},
{TAS2552_SER_CTRL_1, 0x00},
{TAS2552_SER_CTRL_2, 0x00},
+ {TAS2552_OUTPUT_DATA, 0xc0},
{TAS2552_PLL_CTRL_1, 0x10},
{TAS2552_PLL_CTRL_2, 0x00},
{TAS2552_PLL_CTRL_3, 0x00},
{TAS2552_BTIP, 0x8f},
{TAS2552_BTS_CTRL, 0x80},
+ {TAS2552_RESERVED_0D, 0xbe},
+ {TAS2552_LIMIT_RATE_HYS, 0x08},
{TAS2552_LIMIT_RELEASE, 0x04},
{TAS2552_LIMIT_INT_COUNT, 0x00},
+ {TAS2552_PDM_CFG, 0x01},
+ {TAS2552_PGA_GAIN, 0x00},
{TAS2552_EDGE_RATE_CTRL, 0x40},
+ {TAS2552_BOOST_APT_CTRL, 0x0f},
{TAS2552_VBAT_DATA, 0x00},
};
@@ -495,13 +495,21 @@ static int tas2552_runtime_suspend(struct device *dev)
static int tas2552_runtime_resume(struct device *dev)
{
struct tas2552_data *tas2552 = dev_get_drvdata(dev);
+ int ret;
gpiod_set_value_cansleep(tas2552->enable_gpio, 1);
tas2552_sw_shutdown(tas2552, 0);
regcache_cache_only(tas2552->regmap, false);
- regcache_sync(tas2552->regmap);
+ ret = regcache_sync(tas2552->regmap);
+ if (ret) {
+ regcache_cache_only(tas2552->regmap, true);
+ regcache_mark_dirty(tas2552->regmap);
+ tas2552_sw_shutdown(tas2552, 1);
+ gpiod_set_value_cansleep(tas2552->enable_gpio, 0);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index b11b998aa32a..f9c65c9f6d0a 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -897,13 +897,13 @@ static const struct reg_default tas2764_reg_defaults[] = {
{ TAS2764_PAGE, 0x00 },
{ TAS2764_SW_RST, 0x00 },
{ TAS2764_PWR_CTRL, 0x1a },
- { TAS2764_DVC, 0x00 },
{ TAS2764_CHNL_0, 0x28 },
{ TAS2764_TDM_CFG0, 0x09 },
{ TAS2764_TDM_CFG1, 0x02 },
{ TAS2764_TDM_CFG2, 0x0a },
{ TAS2764_TDM_CFG3, 0x10 },
{ TAS2764_TDM_CFG5, 0x42 },
+ { TAS2764_DVC, 0x00 },
{ TAS2764_INT_CLK_CFG, 0x19 },
};
diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c
index 1ec1c076204f..f1fce4305fa1 100644
--- a/sound/soc/codecs/tas2780.c
+++ b/sound/soc/codecs/tas2780.c
@@ -527,13 +527,13 @@ static const struct reg_default tas2780_reg_defaults[] = {
{ TAS2780_PAGE, 0x00 },
{ TAS2780_SW_RST, 0x00 },
{ TAS2780_PWR_CTRL, 0x1a },
- { TAS2780_DVC, 0x00 },
{ TAS2780_CHNL_0, 0x00 },
{ TAS2780_TDM_CFG0, 0x09 },
{ TAS2780_TDM_CFG1, 0x02 },
{ TAS2780_TDM_CFG2, 0x0a },
{ TAS2780_TDM_CFG3, 0x10 },
{ TAS2780_TDM_CFG5, 0x42 },
+ { TAS2780_DVC, 0x00 },
};
static const struct regmap_range_cfg tas2780_regmap_ranges[] = {
diff --git a/sound/soc/codecs/tas2781-comlib-i2c.c b/sound/soc/codecs/tas2781-comlib-i2c.c
index e24d56a14cfd..79b5f5b04c74 100644
--- a/sound/soc/codecs/tas2781-comlib-i2c.c
+++ b/sound/soc/codecs/tas2781-comlib-i2c.c
@@ -6,6 +6,7 @@
//
// Author: Shenghao Ding <shenghao-ding@ti.com>
+#include <linux/cleanup.h>
#include <linux/crc8.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
@@ -342,7 +343,7 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
/* Codec Lock Hold to ensure that codec_probe and firmware parsing and
* loading do not simultaneously execute.
*/
- mutex_lock(&tas_priv->codec_lock);
+ guard(mutex)(&tas_priv->codec_lock);
if (tas_priv->name_prefix)
scnprintf(tas_priv->rca_binaryname, 64, "%s-%sRCA%d.bin",
@@ -360,8 +361,6 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
dev_err(tas_priv->dev, "request_firmware_nowait err:0x%08x\n",
ret);
- /* Codec Lock Release*/
- mutex_unlock(&tas_priv->codec_lock);
return ret;
}
EXPORT_SYMBOL_GPL(tascodec_init);
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
index dcbeb9618195..2b9efccf1a0b 100644
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -1849,16 +1849,26 @@ static int tasdev_load_blk(struct tasdevice_priv *tas_priv,
}
}
if (ret == -EAGAIN) {
- if (block->nr_retry > 0)
+ if (block->nr_retry > 0) {
+ /* Give the hardware time to stabilize before
+ * next block re-transmission attempt.
+ */
+ usleep_range(2000, 2500);
continue;
+ }
} else if (ret < 0) /*err in current device, skip it*/
break;
if (block->is_pchksum_present) {
ret = tasdev_block_chksum(tas_priv, block, chn);
if (ret == -EAGAIN) {
- if (block->nr_retry > 0)
+ if (block->nr_retry > 0) {
+ /* Give the bus time to recover after
+ * a checksum mismatch error.
+ */
+ usleep_range(2000, 2500);
continue;
+ }
} else if (ret < 0) /*err in current device, skip it*/
break;
}
@@ -2243,7 +2253,7 @@ int tas2781_load_calibration(void *context, char *file_name,
{
struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context;
struct tasdevice *tasdev = &(tas_priv->tasdevice[i]);
- const struct firmware *fw_entry = NULL;
+ const struct firmware *fw_entry __free(firmware) = NULL;
struct tasdevice_fw *tas_fmw;
struct firmware fmw;
int offset = 0;
@@ -2253,60 +2263,50 @@ int tas2781_load_calibration(void *context, char *file_name,
if (ret) {
dev_err(tas_priv->dev, "%s: Request firmware %s failed\n",
__func__, file_name);
- goto out;
+ return ret;
}
if (!fw_entry->size) {
dev_err(tas_priv->dev, "%s: file read error: size = %lu\n",
__func__, (unsigned long)fw_entry->size);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
fmw.size = fw_entry->size;
fmw.data = fw_entry->data;
tas_fmw = tasdev->cali_data_fmw = kzalloc_obj(struct tasdevice_fw);
- if (!tasdev->cali_data_fmw) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!tasdev->cali_data_fmw)
+ return -ENOMEM;
+
tas_fmw->dev = tas_priv->dev;
offset = fw_parse_header(tas_priv, tas_fmw, &fmw, offset);
if (offset == -EINVAL) {
dev_err(tas_priv->dev, "fw_parse_header EXIT!\n");
- ret = offset;
- goto out;
+ return -EINVAL;
}
offset = fw_parse_variable_hdr_cal(tas_priv, tas_fmw, &fmw, offset);
if (offset == -EINVAL) {
dev_err(tas_priv->dev,
"%s: fw_parse_variable_header_cal EXIT!\n", __func__);
- ret = offset;
- goto out;
+ return -EINVAL;
}
offset = fw_parse_program_data(tas_priv, tas_fmw, &fmw, offset);
if (offset < 0) {
dev_err(tas_priv->dev, "fw_parse_program_data EXIT!\n");
- ret = offset;
- goto out;
+ return offset;
}
offset = fw_parse_configuration_data(tas_priv, tas_fmw, &fmw, offset);
if (offset < 0) {
dev_err(tas_priv->dev, "fw_parse_configuration_data EXIT!\n");
- ret = offset;
- goto out;
+ return offset;
}
offset = fw_parse_calibration_data(tas_priv, tas_fmw, &fmw, offset);
if (offset < 0) {
dev_err(tas_priv->dev, "fw_parse_calibration_data EXIT!\n");
- ret = offset;
- goto out;
+ return offset;
}
-out:
- release_firmware(fw_entry);
-
- return ret;
+ return 0;
}
EXPORT_SYMBOL_NS_GPL(tas2781_load_calibration, "SND_SOC_TAS2781_FMWLIB");
@@ -2399,7 +2399,7 @@ static int tasdevice_dspfw_ready(const struct firmware *fmw,
int tasdevice_dsp_parser(void *context)
{
struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context;
- const struct firmware *fw_entry;
+ const struct firmware *fw_entry __free(firmware) = NULL;
int ret;
ret = request_firmware(&fw_entry, tas_priv->coef_binaryname,
@@ -2407,15 +2407,10 @@ int tasdevice_dsp_parser(void *context)
if (ret) {
dev_err(tas_priv->dev, "%s: load %s error\n", __func__,
tas_priv->coef_binaryname);
- goto out;
+ return ret;
}
- ret = tasdevice_dspfw_ready(fw_entry, tas_priv);
- release_firmware(fw_entry);
- fw_entry = NULL;
-
-out:
- return ret;
+ return tasdevice_dspfw_ready(fw_entry, tas_priv);
}
EXPORT_SYMBOL_NS_GPL(tasdevice_dsp_parser, "SND_SOC_TAS2781_FMWLIB");
@@ -2797,11 +2792,12 @@ out:
}
EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_load, "SND_SOC_TAS2781_FMWLIB");
-void tasdevice_tuning_switch(void *context, int state)
+void tasdevice_tuning_switch(void *context, int state, bool is_cap)
{
struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
struct tasdevice_fw *tas_fmw = tas_priv->fmw;
- int profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
+ int profile_cfg_id = is_cap ? tas_priv->rcabin.capture_profile_id :
+ tas_priv->rcabin.profile_cfg_id;
/*
* Only RCA-based Playback can still work with no dsp program running
@@ -2818,7 +2814,6 @@ void tasdevice_tuning_switch(void *context, int state)
if (state == 0) {
if (tas_fmw && tas_priv->cur_prog < tas_fmw->nr_programs) {
/* dsp mode or tuning mode */
- profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
tasdevice_select_tuningprm_cfg(tas_priv,
tas_priv->cur_prog, tas_priv->cur_conf,
profile_cfg_id);
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 95d875c44b91..6f349f88f194 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -13,6 +13,7 @@
// Author: Kevin Lu <kevin-lu@ti.com>
//
+#include <linux/cleanup.h>
#include <linux/crc8.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
@@ -617,6 +618,7 @@ static int tasdev_calib_stop_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp);
+ int i;
guard(mutex)(&priv->codec_lock);
if (priv->chip_id == TAS2563)
@@ -624,6 +626,14 @@ static int tasdev_calib_stop_put(struct snd_kcontrol *kcontrol,
else
tas2781_calib_stop_put(priv);
+ /*
+ * Set reloading-firmware flag after calibration, the flag will work
+ * during next playback, then set to the program id after reloading
+ * firmware.
+ */
+ for (i = 0; i < priv->ndev; i++)
+ priv->tasdevice[i].cur_prog = -1;
+
return 1;
}
@@ -843,12 +853,12 @@ static int tasdevice_digital_gain_get(
unsigned char data[4];
int ret;
- mutex_lock(&tas_dev->codec_lock);
+ guard(mutex)(&tas_dev->codec_lock);
/* Read the primary device */
ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
if (ret) {
dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
- goto out;
+ return ret;
}
target = get_unaligned_be32(&data[0]);
@@ -868,8 +878,7 @@ static int tasdevice_digital_gain_get(
/* find out the member same as or closer to the current volume */
ucontrol->value.integer.value[0] =
abs(target - ar_l) <= abs(target - ar_r) ? l : r;
-out:
- mutex_unlock(&tas_dev->codec_lock);
+
return 0;
}
@@ -882,29 +891,26 @@ static int tasdevice_digital_gain_put(
struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec);
int vol = ucontrol->value.integer.value[0];
- int status = 0, max = mc->max, rc = 1;
+ int status = 0, max = mc->max;
int i, ret;
unsigned int reg = mc->reg;
unsigned int volrd, volwr;
unsigned char data[4];
vol = clamp(vol, 0, max);
- mutex_lock(&tas_dev->codec_lock);
+ guard(mutex)(&tas_dev->codec_lock);
/* Read the primary device */
ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
if (ret) {
dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
- rc = -1;
- goto out;
+ return -1;
}
volrd = get_unaligned_be32(&data[0]);
volwr = get_unaligned_be32(tas_dev->dvc_tlv_table[vol]);
- if (volrd == volwr) {
- rc = 0;
- goto out;
- }
+ if (volrd == volwr)
+ return 0;
for (i = 0; i < tas_dev->ndev; i++) {
ret = tasdevice_dev_bulk_write(tas_dev, i, reg,
@@ -918,10 +924,9 @@ static int tasdevice_digital_gain_put(
}
if (status)
- rc = -1;
-out:
- mutex_unlock(&tas_dev->codec_lock);
- return rc;
+ return -1;
+
+ return 1;
}
static const struct snd_kcontrol_new tasdevice_cali_controls[] = {
@@ -995,6 +1000,57 @@ static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
return ret;
}
+/**
+ * tasdevice_set_capture_profile_id - Set runtime capture profile index via
+ * ALSA control
+ * @kcontrol: ALSA kcontrol handle that triggers this operation
+ * @ucontrol: User space control value carrying the new profile index
+ *
+ * This mixer control handler validates the user-provided capture profile ID
+ * against the maximum valid index parsed from the loaded DSP firmware,
+ * then updates the runtime stored capture profile ID only if the new value
+ * differs from the current active one. It will immediately return -EINVAL
+ * if the submitted profile ID falls outside the valid range, including the
+ * edge case that no valid configuration blocks are detected in firmware.
+ *
+ * No actual DSP register write is performed in this handler. The updated
+ * profile ID will be applied to the hardware when the next ALSA capture
+ * stream starts up. Caller does not need to take extra codec lock here,
+ * as the ALSA control core already guarantees serialized execution.
+ *
+ * Return: 1 if profile ID value was changed, 0 if no modification needed,
+ * -EINVAL if the input profile ID is out of valid range
+ */
+static int tasdevice_set_capture_profile_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ unsigned int user_prof_id = ucontrol->value.integer.value[0];
+ unsigned int max_valid_id;
+ int ret = 0;
+
+ /*
+ * Align valid range with the bound defined in
+ * tasdevice_info_profile()
+ */
+ max_valid_id = tas_priv->rcabin.ncfgs - 1;
+
+ /*
+ * Reject invalid input including zero total configuration edge
+ * case
+ */
+ if (tas_priv->rcabin.ncfgs == 0 || user_prof_id > max_valid_id)
+ return -EINVAL;
+
+ if (tas_priv->rcabin.capture_profile_id != user_prof_id) {
+ tas_priv->rcabin.capture_profile_id = user_prof_id;
+ ret = 1;
+ }
+
+ return ret;
+}
+
static int tasdevice_info_active_num(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -1075,6 +1131,41 @@ static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
return 0;
}
+/**
+ * tasdevice_get_capture_profile_id - Report current active capture profile
+ * ID to user space
+ * @kcontrol: ALSA kcontrol structure passed from ALSA core
+ * @ucontrol: User-space control element value buffer to write the result back
+ *
+ * This function ensures the returned profile ID is always clamped inside the
+ * valid range advertised by the info callback, preventing accidental invalid
+ * values from being exposed to applications even if internal driver state is
+ * temporarily inconsistent.
+ *
+ * Returns 0 on successful fill of the control value, no error conditions
+ * are defined for this getter callback.
+ */
+static int tasdevice_get_capture_profile_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ unsigned int max_valid_id, current_prof_id;
+
+ max_valid_id = tas_priv->rcabin.ncfgs > 0 ?
+ (tas_priv->rcabin.ncfgs - 1U) : 0;
+
+ /*
+ * Cast current profile id to unsigned to match type with max_valid_id,
+ * avoid signedness mismatch;
+ */
+ current_prof_id = (unsigned int)tas_priv->rcabin.capture_profile_id;
+ /* Prevent underflow when there are no loaded capture profiles. */
+ ucontrol->value.integer.value[0] = min(current_prof_id, max_valid_id);
+
+ return 0;
+}
+
static int tasdevice_get_chip_id(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1117,6 +1208,41 @@ static int tasdevice_create_control(struct tasdevice_priv *tas_priv)
ret = snd_soc_add_component_controls(tas_priv->codec,
prof_ctrls, nr_controls < mix_index ? nr_controls : mix_index);
+ mix_index = 0;
+ switch (tas_priv->chip_id) {
+ case TAS2563:
+ case TAS2568:
+ case TAS2570:
+ case TAS2572:
+ case TAS2573:
+ case TAS2574:
+ case TAS2781:
+ prof_ctrls = devm_kcalloc(tas_priv->dev, nr_controls,
+ sizeof(prof_ctrls[0]), GFP_KERNEL);
+ if (!prof_ctrls) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Create a mixer item for selecting the capture profile */
+ name = devm_kstrdup(tas_priv->dev, "Speaker Capture Profile Id",
+ GFP_KERNEL);
+ if (!name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ prof_ctrls[mix_index].name = name;
+ prof_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ prof_ctrls[mix_index].info = tasdevice_info_profile;
+ prof_ctrls[mix_index].get = tasdevice_get_capture_profile_id;
+ prof_ctrls[mix_index].put = tasdevice_set_capture_profile_id;
+ mix_index++;
+
+ ret = snd_soc_add_component_controls(tas_priv->codec,
+ prof_ctrls, nr_controls < mix_index ? nr_controls : mix_index);
+ break;
+ }
+
out:
return ret;
}
@@ -1330,6 +1456,43 @@ static void alpa_cali_update(struct bulk_reg_val *p,
p->val_len = 4;
}
+static int create_tas2781_cali_start_ktrl(struct tasdevice_priv
+ *priv, struct snd_kcontrol_new *cali_ctrl)
+{
+ struct soc_bytes_ext *ext_cali_start;
+ char *cali_start_name;
+
+ ext_cali_start = devm_kzalloc(priv->dev,
+ sizeof(*ext_cali_start), GFP_KERNEL);
+ if (!ext_cali_start)
+ return -ENOMEM;
+
+ cali_start_name = devm_kstrdup(priv->dev,
+ "Calibration Start", GFP_KERNEL);
+ if (!cali_start_name)
+ return -ENOMEM;
+ /*
+ * package structure for tas2781 ftc start:
+ * Pkg len (1 byte)
+ * Reg id (1 byte, constant 'r')
+ * book, page, register for pilot threshold, pilot tone
+ * and sine gain (12 bytes)
+ * for (i = 0; i < Device-Sum; i++) {
+ * Device #i index_info (1 byte)
+ * Sine gain for Device #i (8 bytes)
+ * }
+ */
+ ext_cali_start->max = 14 + priv->ndev * 9;
+ cali_ctrl->name = cali_start_name;
+ cali_ctrl->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ cali_ctrl->info = snd_soc_bytes_info_ext;
+ cali_ctrl->put = tas2781_calib_start_put;
+ cali_ctrl->get = tasdev_nop_get;
+ cali_ctrl->private_value = (unsigned long)ext_cali_start;
+
+ return 0;
+}
+
static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv)
{
struct calidata *cali_data = &priv->cali_data;
@@ -1448,37 +1611,11 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv)
*/
cali_data->data[0] = 0xff;
if (priv->chip_id == TAS2781) {
- struct soc_bytes_ext *ext_cali_start;
- char *cali_start_name;
-
- ext_cali_start = devm_kzalloc(priv->dev,
- sizeof(*ext_cali_start), GFP_KERNEL);
- if (!ext_cali_start)
- return -ENOMEM;
-
- cali_start_name = devm_kstrdup(priv->dev,
- "Calibration Start", GFP_KERNEL);
- if (!cali_start_name)
- return -ENOMEM;
- /*
- * package structure for tas2781 ftc start:
- * Pkg len (1 byte)
- * Reg id (1 byte, constant 'r')
- * book, page, register for pilot threshold, pilot tone
- * and sine gain (12 bytes)
- * for (i = 0; i < Device-Sum; i++) {
- * Device #i index_info (1 byte)
- * Sine gain for Device #i (8 bytes)
- * }
- */
- ext_cali_start->max = 14 + priv->ndev * 9;
- cali_ctrls[i].name = cali_start_name;
- cali_ctrls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- cali_ctrls[i].info = snd_soc_bytes_info_ext;
- cali_ctrls[i].put = tas2781_calib_start_put;
- cali_ctrls[i].get = tasdev_nop_get;
- cali_ctrls[i].private_value = (unsigned long)ext_cali_start;
+ rc = create_tas2781_cali_start_ktrl(priv, &cali_ctrls[i]);
+ if (rc != 0)
+ return rc;
i++;
+
}
return snd_soc_add_component_controls(priv->codec, cali_ctrls,
@@ -1765,13 +1902,25 @@ static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w,
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
int state = 0;
- /* Codec Lock Hold */
- mutex_lock(&tas_priv->codec_lock);
+ guard(mutex)(&tas_priv->codec_lock);
if (event == SND_SOC_DAPM_PRE_PMD)
state = 1;
- tasdevice_tuning_switch(tas_priv, state);
- /* Codec Lock Release*/
- mutex_unlock(&tas_priv->codec_lock);
+ tasdevice_tuning_switch(tas_priv, state, false);
+
+ return 0;
+}
+
+static int tasdevice_capture_dapm_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ int state = 0;
+
+ guard(mutex)(&tas_priv->codec_lock);
+ if (event == SND_SOC_DAPM_PRE_PMD)
+ state = 1;
+ tasdevice_tuning_switch(tas_priv, state, true);
return 0;
}
@@ -1779,7 +1928,7 @@ static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w,
static const struct snd_soc_dapm_widget tasdevice_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("ASI", "ASI Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT_E("ASI OUT", "ASI Capture", 0, SND_SOC_NOPM,
- 0, 0, tasdevice_dapm_event,
+ 0, 0, tasdevice_capture_dapm_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_SPK("SPK", tasdevice_dapm_event),
SND_SOC_DAPM_OUTPUT("OUT"),
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c
index 3d0b116544cc..caf8fe1bf4db 100644
--- a/sound/soc/codecs/tas2783-sdw.c
+++ b/sound/soc/codecs/tas2783-sdw.c
@@ -12,6 +12,7 @@
// Author: Baojun Xu <baojun.xu@ti.com>
// Author: Kevin Lu <kevin-lu@ti.com>
+#include <linux/cleanup.h>
#include <linux/unaligned.h>
#include <linux/crc32.h>
#include <linux/efi.h>
@@ -106,7 +107,6 @@ struct tas2783_prv {
static const struct reg_default tas2783_reg_default[] = {
{TAS2783_AMP_LEVEL, 0x28},
- {TASDEV_REG_SDW(0, 0, 0x03), 0x28},
{TASDEV_REG_SDW(0, 0, 0x04), 0x21},
{TASDEV_REG_SDW(0, 0, 0x05), 0x41},
{TASDEV_REG_SDW(0, 0, 0x06), 0x00},
@@ -142,6 +142,7 @@ static const struct reg_default tas2783_reg_default[] = {
{TASDEV_REG_SDW(0, 0, 0x41), 0x14},
{TASDEV_REG_SDW(0, 0, 0x5c), 0x19},
{TASDEV_REG_SDW(0, 0, 0x5d), 0x80},
+ {TASDEV_REG_SDW(0, 0, 0x60), 0x21},
{TASDEV_REG_SDW(0, 0, 0x63), 0x48},
{TASDEV_REG_SDW(0, 0, 0x65), 0x08},
{TASDEV_REG_SDW(0, 0, 0x66), 0xb2},
@@ -157,7 +158,6 @@ static const struct reg_default tas2783_reg_default[] = {
{TASDEV_REG_SDW(0, 0, 0x73), 0x08},
{TASDEV_REG_SDW(0, 0, 0x75), 0xe0},
{TASDEV_REG_SDW(0, 0, 0x7a), 0x60},
- {TASDEV_REG_SDW(0, 0, 0x60), 0x21},
{TASDEV_REG_SDW(0, 1, 0x02), 0x00},
{TASDEV_REG_SDW(0, 1, 0x17), 0xc0},
{TASDEV_REG_SDW(0, 1, 0x19), 0x60},
@@ -176,63 +176,44 @@ static const struct reg_default tas2783_reg_default[] = {
{TASDEV_REG_SDW(0, 0xfd, 0x39), 0x00},
{TASDEV_REG_SDW(0, 0xfd, 0x3e), 0x00},
{TASDEV_REG_SDW(0, 0xfd, 0x45), 0x00},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x02, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x02, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x02, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x02, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x02, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x10, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU21, 0x01, 1), 0x1},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU21, 0x02, 1), 0x9c00},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x01, 0), 0x1},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x01, 1), 0x1},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x0b, 1), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 1), 0x1},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 1), 0x1},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x0b, 1), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 0), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 1), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 2), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 1), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 2), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x01, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x06, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x07, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x09, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x0a, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x1, 0), 0x3},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x05, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x06, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x06, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x04, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x08, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x04, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x11, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x04, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x01, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x05, 0), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x12, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x01, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x05, 0), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x08, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 1), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 2), 0x0},
@@ -242,19 +223,60 @@ static const struct reg_default tas2783_reg_default[] = {
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 6), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 7), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x06, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 1), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 2), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 1), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 2), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x01, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x05, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x01, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x05, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x10, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x13, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x14, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x15, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x16, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x10, 0), 0x3},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_UDMPU23, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x10, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x13, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x13, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_TG23, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x11, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x08, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x08, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x08, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x11, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 1), 0x0},
@@ -264,6 +286,14 @@ static const struct reg_default tas2783_reg_default[] = {
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 5), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 6), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 7), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x12, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 8), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 9), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xa), 0x0},
@@ -272,36 +302,6 @@ static const struct reg_default tas2783_reg_default[] = {
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xd), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xe), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xf), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x1, 0), 0x3},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x10, 0), 0x3},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x06, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x12, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x13, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x06, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x12, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x13, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x05, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x10, 0), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x12, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_TG23, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x01, 0), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x06, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x07, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x09, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x0a, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x10, 0), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x12, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x13, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x14, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x15, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x16, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_UDMPU23, 0x10, 0), 0x0},
};
static const struct reg_sequence tas2783_init_seq[] = {
@@ -495,6 +495,56 @@ static bool tas2783_readable_register(struct device *dev, unsigned int reg)
return tas2783_sdca_mbq_size(dev, reg) > 0;
}
+static bool tas2783_writeable_register(struct device *dev, unsigned int reg)
+{
+ /*
+ * The Latency Control of every Entity, together with the Power Domain
+ * actual state and the protection status, is read-only. They are
+ * listed in tas2783_reg_default[] with a placeholder value, so without
+ * this a regcache_sync() would try to write them back and the
+ * peripheral would reject the transaction, aborting the sync.
+ */
+ switch (reg) {
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU21, 0x10, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU23, 0x10, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU26, 0x10, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x06, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x07, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS24, 0x02, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS21, 0x02, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS25, 0x02, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS26, 0x02, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS28, 0x02, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PDE23, 0x10, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_UDMPU23, 0x06, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_SAPU29, 0x05, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_SAPU29, 0x11, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PPU21, 0x06, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PPU26, 0x06, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT21, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT29, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT26, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT28, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT24, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT23, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT25, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT28, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MU26, 0x06, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT127, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU127, 0x10, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS127, 0x02, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU21, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU21, 0x04, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU26, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU26, 0x04, 0):
+ return false;
+
+ default:
+ return tas2783_sdca_mbq_size(dev, reg) > 0;
+ }
+}
+
static bool tas2783_volatile_register(struct device *dev, u32 reg)
{
switch (reg) {
@@ -516,6 +566,7 @@ static const struct regmap_config tas_regmap = {
.reg_bits = 32,
.val_bits = 8,
.readable_reg = tas2783_readable_register,
+ .writeable_reg = tas2783_writeable_register,
.volatile_reg = tas2783_volatile_register,
.reg_defaults = tas2783_reg_default,
.num_reg_defaults = ARRAY_SIZE(tas2783_reg_default),
@@ -693,12 +744,12 @@ static s32 tas2783_update_calibdata(struct tas2783_prv *tas_dev)
return 0;
}
- mutex_lock(&tas_dev->calib_lock);
- ret = tas2783_validate_calibdata(tas_dev, tas_dev->cali_data.data,
- tas_dev->cali_data.read_sz);
- if (!ret)
- tas2783_set_calib_params_to_device(tas_dev, tmp_val);
- mutex_unlock(&tas_dev->calib_lock);
+ scoped_guard(mutex, &tas_dev->calib_lock) {
+ ret = tas2783_validate_calibdata(tas_dev, tas_dev->cali_data.data,
+ tas_dev->cali_data.read_sz);
+ if (!ret)
+ tas2783_set_calib_params_to_device(tas_dev, tmp_val);
+ }
return ret;
}
@@ -927,22 +978,23 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream,
dev_err(tas_dev->dev,
"clear latch failed, err=%d", ret);
- mutex_lock(&tas_dev->pde_lock);
- /*
- * Sometimes, there is error returned during power on.
- * So added retry logic to ensure power on so that
- * port prepare succeeds
- */
- do {
- ret = regmap_write(tas_dev->regmap,
- SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23,
- TAS2783_SDCA_CTL_REQ_POW_STATE, 0),
- TAS2783_SDCA_POW_STATE_ON);
- if (!ret)
- break;
- usleep_range(2000, 2200);
- } while (retry--);
- mutex_unlock(&tas_dev->pde_lock);
+ scoped_guard(mutex, &tas_dev->pde_lock) {
+ /*
+ * Sometimes, there is error returned during power on.
+ * So added retry logic to ensure power on so that
+ * port prepare succeeds
+ */
+ do {
+ ret = regmap_write(tas_dev->regmap,
+ SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23,
+ TAS2783_SDCA_CTL_REQ_POW_STATE, 0),
+ TAS2783_SDCA_POW_STATE_ON);
+ if (!ret)
+ break;
+ usleep_range(2000, 2200);
+ } while (retry--);
+ }
+
if (ret)
return ret;
@@ -966,7 +1018,6 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream,
static s32 tas_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- s32 ret;
struct snd_soc_component *component = dai->component;
struct tas2783_prv *tas_dev =
snd_soc_component_get_drvdata(component);
@@ -975,14 +1026,11 @@ static s32 tas_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
sdw_stream_remove_slave(tas_dev->sdw_peripheral, sdw_stream);
- mutex_lock(&tas_dev->pde_lock);
- ret = regmap_write(tas_dev->regmap,
- SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23,
- TAS2783_SDCA_CTL_REQ_POW_STATE, 0),
- TAS2783_SDCA_POW_STATE_OFF);
- mutex_unlock(&tas_dev->pde_lock);
-
- return ret;
+ guard(mutex)(&tas_dev->pde_lock);
+ return regmap_write(tas_dev->regmap,
+ SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23,
+ TAS2783_SDCA_CTL_REQ_POW_STATE, 0),
+ TAS2783_SDCA_POW_STATE_OFF);
}
static const struct snd_soc_dai_ops tas_dai_ops = {
@@ -1099,7 +1147,13 @@ static s32 tas2783_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(tas_dev->regmap, false);
- regcache_sync(tas_dev->regmap);
+ ret = regcache_sync(tas_dev->regmap);
+ if (ret) {
+ regcache_cache_only(tas_dev->regmap, true);
+ regcache_mark_dirty(tas_dev->regmap);
+ return ret;
+ }
+
return 0;
}
@@ -1225,9 +1279,23 @@ static s32 tas_update_status(struct sdw_slave *slave,
if (tas_dev->hw_init || tas_dev->status != SDW_SLAVE_ATTACHED)
return 0;
- /* updated the cache data to device */
regcache_cache_only(tas_dev->regmap, false);
- regcache_sync(tas_dev->regmap);
+
+ /*
+ * The device is attaching uninitialized: either this is the first
+ * attach, or it lost power (and with it all register and DSP state)
+ * while the controller was power-gated during system suspend. The
+ * cache still holds the pre-suspend values, and tas_io_init() below
+ * resets the device via TAS2783_SW_RESET anyway, so syncing it back
+ * is both useless and harmful: later read-modify-write updates would
+ * compare against stale data and skip the hardware write.
+ *
+ * Drop the cache instead, so that subsequent accesses see the real
+ * hardware state. Syncing after the reset is not an option either:
+ * the cache accepts registers for which tas2783_sdca_mbq_size()
+ * returns 0, and writing those back fails with -EINVAL.
+ */
+ regcache_drop_region(tas_dev->regmap, 0, UINT_MAX);
/* perform I/O transfers required for Slave initialization */
return tas_io_init(&slave->dev, slave);
@@ -1330,7 +1398,7 @@ static s32 tas_sdw_probe(struct sdw_slave *peripheral,
function_data->desc = &peripheral->sdca_data.function[i];
/* Parse the function */
- ret = sdca_parse_function(dev, peripheral, function_data);
+ ret = sdca_parse_function(dev, function_data);
if (!ret)
tas_dev->sa_func_data = function_data;
else
diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c
index bcc8cab8d667..d32796a6fa75 100644
--- a/sound/soc/codecs/tas5805m.c
+++ b/sound/soc/codecs/tas5805m.c
@@ -12,6 +12,7 @@
//
// It has been simplified a little and reworked for the 5.x ALSA SoC API.
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -230,10 +231,9 @@ static int tas5805m_vol_get(struct snd_kcontrol *kcontrol,
struct tas5805m_priv *tas5805m =
snd_soc_component_get_drvdata(component);
- mutex_lock(&tas5805m->lock);
+ guard(mutex)(&tas5805m->lock);
ucontrol->value.integer.value[0] = tas5805m->vol[0];
ucontrol->value.integer.value[1] = tas5805m->vol[1];
- mutex_unlock(&tas5805m->lock);
return 0;
}
@@ -249,13 +249,12 @@ static int tas5805m_vol_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tas5805m_priv *tas5805m =
snd_soc_component_get_drvdata(component);
- int ret = 0;
if (!(volume_is_valid(ucontrol->value.integer.value[0]) &&
volume_is_valid(ucontrol->value.integer.value[1])))
return -EINVAL;
- mutex_lock(&tas5805m->lock);
+ guard(mutex)(&tas5805m->lock);
if (tas5805m->vol[0] != ucontrol->value.integer.value[0] ||
tas5805m->vol[1] != ucontrol->value.integer.value[1]) {
tas5805m->vol[0] = ucontrol->value.integer.value[0];
@@ -265,11 +264,10 @@ static int tas5805m_vol_put(struct snd_kcontrol *kcontrol,
tas5805m->is_powered);
if (tas5805m->is_powered)
tas5805m_refresh(tas5805m);
- ret = 1;
+ return 1;
}
- mutex_unlock(&tas5805m->lock);
- return ret;
+ return 0;
}
static const struct snd_kcontrol_new tas5805m_snd_controls[] = {
@@ -332,7 +330,7 @@ static void do_work(struct work_struct *work)
dev_dbg(&tas5805m->i2c->dev, "DSP startup\n");
- mutex_lock(&tas5805m->lock);
+ guard(mutex)(&tas5805m->lock);
/* We mustn't issue any I2C transactions until the I2S
* clock is stable. Furthermore, we must allow a 5ms
* delay after the first set of register writes to
@@ -345,7 +343,6 @@ static void do_work(struct work_struct *work)
tas5805m->is_powered = true;
tas5805m_refresh(tas5805m);
- mutex_unlock(&tas5805m->lock);
}
static int tas5805m_dac_event(struct snd_soc_dapm_widget *w,
@@ -362,7 +359,7 @@ static int tas5805m_dac_event(struct snd_soc_dapm_widget *w,
dev_dbg(component->dev, "DSP shutdown\n");
cancel_work_sync(&tas5805m->work);
- mutex_lock(&tas5805m->lock);
+ guard(mutex)(&tas5805m->lock);
if (tas5805m->is_powered) {
tas5805m->is_powered = false;
@@ -379,7 +376,6 @@ static int tas5805m_dac_event(struct snd_soc_dapm_widget *w,
regmap_write(rm, REG_DEVICE_CTRL_2, DCTRL2_MODE_HIZ);
}
- mutex_unlock(&tas5805m->lock);
}
return 0;
@@ -414,14 +410,13 @@ static int tas5805m_mute(struct snd_soc_dai *dai, int mute, int direction)
struct tas5805m_priv *tas5805m =
snd_soc_component_get_drvdata(component);
- mutex_lock(&tas5805m->lock);
+ guard(mutex)(&tas5805m->lock);
dev_dbg(component->dev, "set mute=%d (is_powered=%d)\n",
mute, tas5805m->is_powered);
tas5805m->is_muted = mute;
if (tas5805m->is_powered)
tas5805m_refresh(tas5805m);
- mutex_unlock(&tas5805m->lock);
return 0;
}
@@ -462,7 +457,6 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c)
struct tas5805m_priv *tas5805m;
char filename[128];
const char *config_name;
- const struct firmware *fw;
int ret;
regmap = devm_regmap_init_i2c(i2c, &tas5805m_regmap);
@@ -507,24 +501,20 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c)
snprintf(filename, sizeof(filename), "tas5805m_dsp_%s.bin",
config_name);
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, filename, dev);
if (ret)
return ret;
if ((fw->size < 2) || (fw->size & 1)) {
dev_err(dev, "firmware is invalid\n");
- release_firmware(fw);
return -EINVAL;
}
tas5805m->dsp_cfg_len = fw->size;
tas5805m->dsp_cfg_data = devm_kmemdup(dev, fw->data, fw->size, GFP_KERNEL);
- if (!tas5805m->dsp_cfg_data) {
- release_firmware(fw);
+ if (!tas5805m->dsp_cfg_data)
return -ENOMEM;
- }
-
- release_firmware(fw);
/* Do the first part of the power-on here, while we can expect
* the I2S interface to be quiet. We must raise PDN# and then
diff --git a/sound/soc/codecs/tas675x.c b/sound/soc/codecs/tas675x.c
index 82526362de7b..404706b62156 100644
--- a/sound/soc/codecs/tas675x.c
+++ b/sound/soc/codecs/tas675x.c
@@ -1924,15 +1924,6 @@ static const struct reg_default tas675x_reg_defaults[] = {
{ TAS675X_PWM_PHASE_M_CTRL_CH2_REG, 0x00 },
{ TAS675X_PWM_PHASE_M_CTRL_CH3_REG, 0x00 },
{ TAS675X_PWM_PHASE_M_CTRL_CH4_REG, 0x00 },
- { TAS675X_DC_LDG_CTRL_REG, 0x00 },
- { TAS675X_DC_LDG_LO_CTRL_REG, 0x00 },
- { TAS675X_DC_LDG_TIME_CTRL_REG, 0x00 },
- { TAS675X_DC_LDG_SL_CH1_CH2_CTRL_REG, 0x11 },
- { TAS675X_DC_LDG_SL_CH3_CH4_CTRL_REG, 0x11 },
- { TAS675X_AC_LDG_CTRL_REG, 0x10 },
- { TAS675X_TWEETER_DETECT_CTRL_REG, 0x08 },
- { TAS675X_TWEETER_DETECT_THRESH_REG, 0x00 },
- { TAS675X_AC_LDG_FREQ_CTRL_REG, 0xC8 },
{ TAS675X_REPORT_ROUTING_1_REG, 0x00 },
{ TAS675X_OTSD_RECOVERY_EN_REG, 0x00 },
{ TAS675X_REPORT_ROUTING_2_REG, 0xA2 },
@@ -1943,6 +1934,15 @@ static const struct reg_default tas675x_reg_defaults[] = {
{ TAS675X_GPIO1_OUTPUT_SEL_REG, 0x00 },
{ TAS675X_GPIO2_OUTPUT_SEL_REG, 0x00 },
{ TAS675X_GPIO_CTRL_REG, TAS675X_GPIO_CTRL_RSTVAL },
+ { TAS675X_DC_LDG_CTRL_REG, 0x00 },
+ { TAS675X_DC_LDG_LO_CTRL_REG, 0x00 },
+ { TAS675X_DC_LDG_TIME_CTRL_REG, 0x00 },
+ { TAS675X_DC_LDG_SL_CH1_CH2_CTRL_REG, 0x11 },
+ { TAS675X_DC_LDG_SL_CH3_CH4_CTRL_REG, 0x11 },
+ { TAS675X_AC_LDG_CTRL_REG, 0x10 },
+ { TAS675X_TWEETER_DETECT_CTRL_REG, 0x08 },
+ { TAS675X_TWEETER_DETECT_THRESH_REG, 0x00 },
+ { TAS675X_AC_LDG_FREQ_CTRL_REG, 0xC8 },
{ TAS675X_OTW_CTRL_CH1_CH2_REG, 0x11 },
{ TAS675X_OTW_CTRL_CH3_CH4_REG, 0x11 },
};
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index e5dfb3d752a3..84e954311c1b 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -320,8 +320,14 @@ static int aic26_probe(struct snd_soc_component *component)
return 0;
}
+static void aic26_remove(struct snd_soc_component *component)
+{
+ device_remove_file(component->dev, &dev_attr_keyclick);
+}
+
static const struct snd_soc_component_driver aic26_soc_component_dev = {
.probe = aic26_probe,
+ .remove = aic26_remove,
.controls = aic26_snd_controls,
.num_controls = ARRAY_SIZE(aic26_snd_controls),
.dapm_widgets = tlv320aic26_dapm_widgets,
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 1d2e0ea6d4fe..43bcbc5449e1 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1720,18 +1720,14 @@ static int tlv320dac3100_fw_load(struct aic31xx_priv *aic31xx,
static int tlv320dac3100_load_coeffs(struct aic31xx_priv *aic31xx,
const char *fw_name)
{
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
int ret;
ret = request_firmware(&fw, fw_name, aic31xx->dev);
if (ret)
return ret;
- ret = tlv320dac3100_fw_load(aic31xx, fw->data, fw->size);
-
- release_firmware(fw);
-
- return ret;
+ return tlv320dac3100_fw_load(aic31xx, fw->data, fw->size);
}
static int aic31xx_i2c_probe(struct i2c_client *i2c)
diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c
index 5c0a76a4a106..deed61650e09 100644
--- a/sound/soc/codecs/tlv320aic32x4-clk.c
+++ b/sound/soc/codecs/tlv320aic32x4-clk.c
@@ -1,5 +1,5 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
+// SPDX-License-Identifier: GPL-2.0
+/*
* Clock Tree for the Texas Instruments TLV320AIC32x4
*
* Copyright 2019 Annaliese McDermond
@@ -9,6 +9,7 @@
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
+#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/device.h>
@@ -57,7 +58,7 @@ static void clk_aic32x4_pll_unprepare(struct clk_hw *hw)
struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
- AIC32X4_PLLEN, 0);
+ AIC32X4_PLLEN, 0);
}
static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw)
@@ -75,7 +76,7 @@ static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw)
}
static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll,
- struct clk_aic32x4_pll_muldiv *settings)
+ struct clk_aic32x4_pll_muldiv *settings)
{
/* Change to use regmap_bulk_read? */
unsigned int val;
@@ -106,19 +107,19 @@ static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll,
}
static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll,
- struct clk_aic32x4_pll_muldiv *settings)
+ struct clk_aic32x4_pll_muldiv *settings)
{
int ret;
/* Change to use regmap_bulk_write for some if not all? */
ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
- AIC32X4_PLL_R_MASK, settings->r);
+ AIC32X4_PLL_R_MASK, settings->r);
if (ret < 0)
return ret;
ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
- AIC32X4_PLL_P_MASK,
- settings->p << AIC32X4_PLL_P_SHIFT);
+ AIC32X4_PLL_P_MASK,
+ settings->p << AIC32X4_PLL_P_SHIFT);
if (ret < 0)
return ret;
@@ -136,23 +137,21 @@ static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll,
return 0;
}
-static unsigned long clk_aic32x4_pll_calc_rate(
- struct clk_aic32x4_pll_muldiv *settings,
- unsigned long parent_rate)
+static unsigned long clk_aic32x4_pll_calc_rate(struct clk_aic32x4_pll_muldiv *settings,
+ unsigned long parent_rate)
{
u64 rate;
/*
* We scale j by 10000 to account for the decimal part of P and divide
* it back out later.
*/
- rate = (u64) parent_rate * settings->r *
- ((settings->j * 10000) + settings->d);
+ rate = (u64)parent_rate * settings->r * ((settings->j * 10000) + settings->d);
- return (unsigned long) DIV_ROUND_UP_ULL(rate, settings->p * 10000);
+ return (unsigned long)DIV_ROUND_UP_ULL(rate, settings->p * 10000);
}
static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings,
- unsigned long rate, unsigned long parent_rate)
+ unsigned long rate, unsigned long parent_rate)
{
u64 multiplier;
@@ -165,14 +164,14 @@ static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings,
* of the multiplier. This is because we can't do floating point
* math in the kernel.
*/
- multiplier = (u64) rate * settings->p * 10000;
+ multiplier = (u64)rate * settings->p * 10000;
do_div(multiplier, parent_rate);
/*
* J can't be over 64, so R can scale this.
* R can't be greater than 4.
*/
- settings->r = ((u32) multiplier / 640000) + 1;
+ settings->r = ((u32)multiplier / 640000) + 1;
if (settings->r > 4)
return -1;
do_div(multiplier, settings->r);
@@ -184,14 +183,14 @@ static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings,
return -1;
/* Figure out the integer part, J, and the fractional part, D. */
- settings->j = (u32) multiplier / 10000;
- settings->d = (u32) multiplier % 10000;
+ settings->j = (u32)multiplier / 10000;
+ settings->d = (u32)multiplier % 10000;
return 0;
}
static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
+ unsigned long parent_rate)
{
struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
struct clk_aic32x4_pll_muldiv settings;
@@ -220,8 +219,8 @@ static int clk_aic32x4_pll_determine_rate(struct clk_hw *hw,
}
static int clk_aic32x4_pll_set_rate(struct clk_hw *hw,
- unsigned long rate,
- unsigned long parent_rate)
+ unsigned long rate,
+ unsigned long parent_rate)
{
struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
struct clk_aic32x4_pll_muldiv settings;
@@ -236,7 +235,7 @@ static int clk_aic32x4_pll_set_rate(struct clk_hw *hw,
return ret;
/* 10ms is the delay to wait before the clocks are stable */
- msleep(10);
+ usleep_range(10000, 20000);
return 0;
}
@@ -261,7 +260,6 @@ static u8 clk_aic32x4_pll_get_parent(struct clk_hw *hw)
return (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT;
}
-
static const struct clk_ops aic32x4_pll_ops = {
.prepare = clk_aic32x4_pll_prepare,
.unprepare = clk_aic32x4_pll_unprepare,
@@ -311,11 +309,11 @@ static void clk_aic32x4_div_unprepare(struct clk_hw *hw)
struct clk_aic32x4 *div = to_clk_aic32x4(hw);
regmap_update_bits(div->regmap, div->reg,
- AIC32X4_DIVEN, 0);
+ AIC32X4_DIVEN, 0);
}
static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
+ unsigned long parent_rate)
{
struct clk_aic32x4 *div = to_clk_aic32x4(hw);
u8 divisor;
@@ -342,7 +340,7 @@ static int clk_aic32x4_div_determine_rate(struct clk_hw *hw,
}
static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
+ unsigned long parent_rate)
{
struct clk_aic32x4 *div = to_clk_aic32x4(hw);
unsigned int val;
@@ -399,7 +397,7 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
{
.name = "pll",
.parent_names =
- (const char* []) { "mclk", "bclk", "gpio", "din" },
+ (const char *[]) { "mclk", "bclk", "gpio", "din" },
.num_parents = 4,
.ops = &aic32x4_pll_ops,
.reg = 0,
@@ -414,28 +412,28 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
},
{
.name = "ndac",
- .parent_names = (const char * []) { "codec_clkin" },
+ .parent_names = (const char *[]) { "codec_clkin" },
.num_parents = 1,
.ops = &aic32x4_div_ops,
.reg = AIC32X4_NDAC,
},
{
.name = "mdac",
- .parent_names = (const char * []) { "ndac" },
+ .parent_names = (const char *[]) { "ndac" },
.num_parents = 1,
.ops = &aic32x4_div_ops,
.reg = AIC32X4_MDAC,
},
{
.name = "nadc",
- .parent_names = (const char * []) { "codec_clkin" },
+ .parent_names = (const char *[]) { "codec_clkin" },
.num_parents = 1,
.ops = &aic32x4_div_ops,
.reg = AIC32X4_NADC,
},
{
.name = "madc",
- .parent_names = (const char * []) { "nadc" },
+ .parent_names = (const char *[]) { "nadc" },
.num_parents = 1,
.ops = &aic32x4_div_ops,
.reg = AIC32X4_MADC,
@@ -451,7 +449,7 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
};
static struct clk *aic32x4_register_clk(struct device *dev,
- struct aic32x4_clkdesc *desc)
+ struct aic32x4_clkdesc *desc)
{
struct clk_init_data init;
struct clk_aic32x4 *priv;
@@ -464,8 +462,8 @@ static struct clk *aic32x4_register_clk(struct device *dev,
init.flags = 0;
priv = devm_kzalloc(dev, sizeof(struct clk_aic32x4), GFP_KERNEL);
- if (priv == NULL)
- return (struct clk *) -ENOMEM;
+ if (!priv)
+ return ERR_PTR(-ENOMEM);
priv->dev = dev;
priv->hw.init = &init;
diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c
index 449353d5f088..cbbb8ff3ee38 100644
--- a/sound/soc/codecs/tlv320aic32x4-i2c.c
+++ b/sound/soc/codecs/tlv320aic32x4-i2c.c
@@ -1,11 +1,10 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
+// SPDX-License-Identifier: GPL-2.0
+/*
* Copyright 2011-2019 NW Digital Radio
*
* Author: Annaliese McDermond <nh6z@nh6z.net>
*
* Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
- *
*/
#include <linux/i2c.h>
@@ -16,17 +15,23 @@
#include "tlv320aic32x4.h"
+static const struct regmap_config aic32x4_i2c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AIC32X4_REFPOWERUP,
+ .ranges = aic32x4_regmap_pages,
+ .num_ranges = 1,
+};
+
static int aic32x4_i2c_probe(struct i2c_client *i2c)
{
struct regmap *regmap;
- struct regmap_config config;
enum aic32x4_type type;
- config = aic32x4_regmap_config;
- config.reg_bits = 8;
- config.val_bits = 8;
+ regmap = devm_regmap_init_i2c(i2c, &aic32x4_i2c_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
- regmap = devm_regmap_init_i2c(i2c, &config);
type = (uintptr_t)i2c_get_match_data(i2c);
return aic32x4_probe(&i2c->dev, regmap, type);
diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c
index 92246243ff94..cb615b2e4f02 100644
--- a/sound/soc/codecs/tlv320aic32x4-spi.c
+++ b/sound/soc/codecs/tlv320aic32x4-spi.c
@@ -1,11 +1,10 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
+// SPDX-License-Identifier: GPL-2.0
+/*
* Copyright 2011-2019 NW Digital Radio
*
* Author: Annaliese McDermond <nh6z@nh6z.net>
*
* Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
- *
*/
#include <linux/spi/spi.h>
@@ -16,19 +15,25 @@
#include "tlv320aic32x4.h"
+static const struct regmap_config aic32x4_spi_regmap_config = {
+ .reg_bits = 7,
+ .pad_bits = 1,
+ .val_bits = 8,
+ .read_flag_mask = 0x01,
+ .max_register = AIC32X4_REFPOWERUP,
+ .ranges = aic32x4_regmap_pages,
+ .num_ranges = 1,
+};
+
static int aic32x4_spi_probe(struct spi_device *spi)
{
struct regmap *regmap;
- struct regmap_config config;
enum aic32x4_type type;
- config = aic32x4_regmap_config;
- config.reg_bits = 7;
- config.pad_bits = 1;
- config.val_bits = 8;
- config.read_flag_mask = 0x01;
+ regmap = devm_regmap_init_spi(spi, &aic32x4_spi_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
- regmap = devm_regmap_init_spi(spi, &config);
type = (uintptr_t)spi_get_device_match_data(spi);
return aic32x4_probe(&spi->dev, regmap, type);
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index d85094557215..9e0e4aa2b09c 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * linux/sound/soc/codecs/tlv320aic32x4.c
- *
* Copyright 2011 Vista Silicon S.L.
*
* Author: Javier Martin <javier.martin@vista-silicon.com>
@@ -28,7 +26,6 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
-#include <sound/tlv320aic32x4.h>
#include "tlv320aic32x4.h"
@@ -45,7 +42,8 @@ struct aic32x4_priv {
struct regulator *supply_dv;
struct regulator *supply_av;
- struct aic32x4_setup_data *setup;
+ unsigned int gpio_func[5];
+
struct device *dev;
enum aic32x4_type type;
@@ -75,7 +73,7 @@ static int aic32x4_reset_adc(struct snd_soc_dapm_widget *w,
};
static int mic_bias_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
@@ -83,25 +81,23 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
/* Change Mic Bias Registor */
snd_soc_component_update_bits(component, AIC32X4_MICBIAS,
- AIC32x4_MICBIAS_MASK,
- AIC32X4_MICBIAS_LDOIN |
- AIC32X4_MICBIAS_2075V);
- printk(KERN_DEBUG "%s: Mic Bias will be turned ON\n", __func__);
+ AIC32x4_MICBIAS_MASK,
+ AIC32X4_MICBIAS_LDOIN |
+ AIC32X4_MICBIAS_2075V);
+ dev_dbg(component->dev, "Mic Bias will be turned ON\n");
break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_component_update_bits(component, AIC32X4_MICBIAS,
- AIC32x4_MICBIAS_MASK, 0);
- printk(KERN_DEBUG "%s: Mic Bias will be turned OFF\n",
- __func__);
+ AIC32x4_MICBIAS_MASK, 0);
+ dev_dbg(component->dev, "Mic Bias will be turned OFF\n");
break;
}
return 0;
}
-
static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 val;
@@ -114,7 +110,7 @@ static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol,
};
static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 val;
@@ -123,8 +119,7 @@ static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol,
val = snd_soc_component_read(component, AIC32X4_DOUTCTL);
gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
- printk(KERN_ERR "%s: MFP2 is not configure as a GPIO output\n",
- __func__);
+ dev_err(component->dev, "MFP2 is not configure as a GPIO output\n");
return -EINVAL;
}
@@ -142,7 +137,7 @@ static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol,
};
static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 val;
@@ -155,7 +150,7 @@ static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol,
};
static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 val;
@@ -164,8 +159,7 @@ static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol,
val = snd_soc_component_read(component, AIC32X4_MISOCTL);
gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
- printk(KERN_ERR "%s: MFP4 is not configure as a GPIO output\n",
- __func__);
+ dev_err(component->dev, "MFP4 is not configure as a GPIO output\n");
return -EINVAL;
}
@@ -183,7 +177,7 @@ static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol,
};
static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 val;
@@ -195,7 +189,7 @@ static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol,
};
static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 val;
@@ -204,8 +198,7 @@ static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol,
val = snd_soc_component_read(component, AIC32X4_GPIOCTL);
gpio_check = (val & AIC32X4_MFP5_GPIO_OUTPUT);
if (gpio_check != AIC32X4_MFP5_GPIO_OUTPUT) {
- printk(KERN_ERR "%s: MFP5 is not configure as a GPIO output\n",
- __func__);
+ dev_err(component->dev, "MFP5 is not configure as a GPIO output\n");
return -EINVAL;
}
@@ -222,25 +215,31 @@ static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol,
return 0;
};
-static const struct snd_kcontrol_new aic32x4_mfp1[] = {
- SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL),
-};
-
-static const struct snd_kcontrol_new aic32x4_mfp2[] = {
- SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio),
-};
-
-static const struct snd_kcontrol_new aic32x4_mfp3[] = {
- SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL),
-};
-
-static const struct snd_kcontrol_new aic32x4_mfp4[] = {
- SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio),
-};
-
-static const struct snd_kcontrol_new aic32x4_mfp5[] = {
- SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio,
- aic32x4_set_mfp5_gpio),
+static const struct {
+ unsigned int reg;
+ struct snd_kcontrol_new ctrl;
+} aic32x4_mfp_cfg[] = {
+ {
+ .reg = AIC32X4_DINCTL,
+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL),
+ },
+ {
+ .reg = AIC32X4_DOUTCTL,
+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio),
+ },
+ {
+ .reg = AIC32X4_SCLKCTL,
+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL),
+ },
+ {
+ .reg = AIC32X4_MISOCTL,
+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio),
+ },
+ {
+ .reg = AIC32X4_GPIOCTL,
+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio,
+ aic32x4_set_mfp5_gpio),
+ },
};
/* 0dB min, 0.5dB steps */
@@ -270,53 +269,42 @@ static SOC_ENUM_SINGLE_DECL(r_ptm_enum, AIC32X4_RPLAYBACK, 2, ptm_text);
static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
- AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
+ AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
SOC_ENUM("DAC Left Playback PowerTune Switch", l_ptm_enum),
SOC_ENUM("DAC Right Playback PowerTune Switch", r_ptm_enum),
SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
- AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0,
- tlv_driver_gain),
+ AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0, tlv_driver_gain),
SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN,
- AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0,
- tlv_driver_gain),
+ AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0, tlv_driver_gain),
SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN,
- AIC32X4_HPRGAIN, 6, 0x01, 1),
+ AIC32X4_HPRGAIN, 6, 0x01, 1),
SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
- AIC32X4_LORGAIN, 6, 0x01, 1),
+ AIC32X4_LORGAIN, 6, 0x01, 1),
SOC_ENUM("LO Playback Common Mode Switch", lo_cm_enum),
SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL,
- AIC32X4_RMICPGAVOL, 7, 0x01, 1),
+ AIC32X4_RMICPGAVOL, 7, 0x01, 1),
SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0),
SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0),
SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL,
- AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol),
+ AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol),
SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL,
- AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
+ AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
SOC_SINGLE("AGC Left Switch", AIC32X4_LAGC1, 7, 1, 0),
SOC_SINGLE("AGC Right Switch", AIC32X4_RAGC1, 7, 1, 0),
- SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1,
- 4, 0x07, 0),
- SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1,
- 0, 0x03, 0),
- SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2,
- 6, 0x03, 0),
- SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2,
- 1, 0x1F, 0),
- SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3,
- 0, 0x7F, 0),
- SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4,
- 3, 0x1F, 0),
- SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5,
- 3, 0x1F, 0),
- SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6,
- 0, 0x1F, 0),
- SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7,
- 0, 0x0F, 0),
+ SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1, 4, 0x07, 0),
+ SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1, 0, 0x03, 0),
+ SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2, 6, 0x03, 0),
+ SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2, 1, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3, 0, 0x7F, 0),
+ SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4, 3, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5, 3, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6, 0, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7, 0, 0x0F, 0),
};
static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
@@ -354,21 +342,27 @@ static SOC_ENUM_SINGLE_DECL(in3r_lpga_n_enum, AIC32X4_LMICPGANIN, 2, resistor_te
static const struct snd_kcontrol_new in1l_to_lmixer_controls[] = {
SOC_DAPM_ENUM("IN1_L L+ Switch", in1l_lpga_p_enum),
};
+
static const struct snd_kcontrol_new in2l_to_lmixer_controls[] = {
SOC_DAPM_ENUM("IN2_L L+ Switch", in2l_lpga_p_enum),
};
+
static const struct snd_kcontrol_new in3l_to_lmixer_controls[] = {
SOC_DAPM_ENUM("IN3_L L+ Switch", in3l_lpga_p_enum),
};
+
static const struct snd_kcontrol_new in1r_to_lmixer_controls[] = {
SOC_DAPM_ENUM("IN1_R L+ Switch", in1r_lpga_p_enum),
};
+
static const struct snd_kcontrol_new cml_to_lmixer_controls[] = {
SOC_DAPM_ENUM("CM_L L- Switch", cml_lpga_n_enum),
};
+
static const struct snd_kcontrol_new in2r_to_lmixer_controls[] = {
SOC_DAPM_ENUM("IN2_R L- Switch", in2r_lpga_n_enum),
};
+
static const struct snd_kcontrol_new in3r_to_lmixer_controls[] = {
SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum),
};
@@ -385,21 +379,27 @@ static SOC_ENUM_SINGLE_DECL(in3l_rpga_n_enum, AIC32X4_RMICPGANIN, 2, resistor_te
static const struct snd_kcontrol_new in1r_to_rmixer_controls[] = {
SOC_DAPM_ENUM("IN1_R R+ Switch", in1r_rpga_p_enum),
};
+
static const struct snd_kcontrol_new in2r_to_rmixer_controls[] = {
SOC_DAPM_ENUM("IN2_R R+ Switch", in2r_rpga_p_enum),
};
+
static const struct snd_kcontrol_new in3r_to_rmixer_controls[] = {
SOC_DAPM_ENUM("IN3_R R+ Switch", in3r_rpga_p_enum),
};
+
static const struct snd_kcontrol_new in2l_to_rmixer_controls[] = {
SOC_DAPM_ENUM("IN2_L R+ Switch", in2l_rpga_p_enum),
};
+
static const struct snd_kcontrol_new cmr_to_rmixer_controls[] = {
SOC_DAPM_ENUM("CM_R R- Switch", cmr_rpga_n_enum),
};
+
static const struct snd_kcontrol_new in1l_to_rmixer_controls[] = {
SOC_DAPM_ENUM("IN1_L R- Switch", in1l_rpga_n_enum),
};
+
static const struct snd_kcontrol_new in3l_to_rmixer_controls[] = {
SOC_DAPM_ENUM("IN3_L R- Switch", in3l_rpga_n_enum),
};
@@ -428,38 +428,38 @@ static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = {
SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0),
SND_SOC_DAPM_MUX("IN1_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in1r_to_rmixer_controls),
+ in1r_to_rmixer_controls),
SND_SOC_DAPM_MUX("IN2_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in2r_to_rmixer_controls),
+ in2r_to_rmixer_controls),
SND_SOC_DAPM_MUX("IN3_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in3r_to_rmixer_controls),
+ in3r_to_rmixer_controls),
SND_SOC_DAPM_MUX("IN2_L to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in2l_to_rmixer_controls),
+ in2l_to_rmixer_controls),
SND_SOC_DAPM_MUX("CM_R to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
- cmr_to_rmixer_controls),
+ cmr_to_rmixer_controls),
SND_SOC_DAPM_MUX("IN1_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
- in1l_to_rmixer_controls),
+ in1l_to_rmixer_controls),
SND_SOC_DAPM_MUX("IN3_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
- in3l_to_rmixer_controls),
+ in3l_to_rmixer_controls),
SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0),
SND_SOC_DAPM_MUX("IN1_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in1l_to_lmixer_controls),
+ in1l_to_lmixer_controls),
SND_SOC_DAPM_MUX("IN2_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in2l_to_lmixer_controls),
+ in2l_to_lmixer_controls),
SND_SOC_DAPM_MUX("IN3_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in3l_to_lmixer_controls),
+ in3l_to_lmixer_controls),
SND_SOC_DAPM_MUX("IN1_R to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in1r_to_lmixer_controls),
+ in1r_to_lmixer_controls),
SND_SOC_DAPM_MUX("CM_L to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
- cml_to_lmixer_controls),
+ cml_to_lmixer_controls),
SND_SOC_DAPM_MUX("IN2_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
- in2r_to_lmixer_controls),
+ in2r_to_lmixer_controls),
SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
- in3r_to_lmixer_controls),
+ in3r_to_lmixer_controls),
SND_SOC_DAPM_SUPPLY("Mic Bias", AIC32X4_MICBIAS, 6, 0, mic_bias_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_POST("ADC Reset", aic32x4_reset_adc),
@@ -575,7 +575,7 @@ static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
{"IN3_R to Left Mixer Negative Resistor", "40 kOhm", "IN3_R"},
};
-static const struct regmap_range_cfg aic32x4_regmap_pages[] = {
+const struct regmap_range_cfg aic32x4_regmap_pages[] = {
{
.selector_reg = 0,
.selector_mask = 0xff,
@@ -585,13 +585,7 @@ static const struct regmap_range_cfg aic32x4_regmap_pages[] = {
.range_max = AIC32X4_REFPOWERUP,
},
};
-
-const struct regmap_config aic32x4_regmap_config = {
- .max_register = AIC32X4_REFPOWERUP,
- .ranges = aic32x4_regmap_pages,
- .num_ranges = ARRAY_SIZE(aic32x4_regmap_pages),
-};
-EXPORT_SYMBOL(aic32x4_regmap_config);
+EXPORT_SYMBOL_GPL(aic32x4_regmap_pages);
static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
@@ -624,7 +618,7 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
- printk(KERN_ERR "aic32x4: invalid clock provider\n");
+ dev_err(component->dev, "invalid clock provider\n");
return -EINVAL;
}
@@ -651,19 +645,20 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
AIC32X4_IFACE1_DATATYPE_SHIFT);
break;
default:
- printk(KERN_ERR "aic32x4: invalid DAI interface format\n");
+ dev_err(component->dev, "invalid DAI interface format\n");
return -EINVAL;
}
aic32x4->fmt = fmt;
snd_soc_component_update_bits(component, AIC32X4_IFACE1,
- AIC32X4_IFACE1_DATATYPE_MASK |
- AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
+ AIC32X4_IFACE1_DATATYPE_MASK |
+ AIC32X4_IFACE1_MASTER_MASK,
+ iface_reg_1);
snd_soc_component_update_bits(component, AIC32X4_IFACE2,
- AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
+ AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
snd_soc_component_update_bits(component, AIC32X4_IFACE3,
- AIC32X4_BCLKINV_MASK, iface_reg_3);
+ AIC32X4_BCLKINV_MASK, iface_reg_3);
return 0;
}
@@ -676,14 +671,13 @@ static int aic32x4_set_aosr(struct snd_soc_component *component, u8 aosr)
static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr)
{
snd_soc_component_write(component, AIC32X4_DOSRMSB, dosr >> 8);
- snd_soc_component_write(component, AIC32X4_DOSRLSB,
- (dosr & 0xff));
+ snd_soc_component_write(component, AIC32X4_DOSRLSB, dosr & 0xff);
return 0;
}
static int aic32x4_set_processing_blocks(struct snd_soc_component *component,
- u8 r_block, u8 p_block)
+ u8 r_block, u8 p_block)
{
struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
@@ -703,6 +697,45 @@ static int aic32x4_set_processing_blocks(struct snd_soc_component *component,
return 0;
}
+static int aic32x4_configure_rate(struct snd_soc_component *component,
+ unsigned int rate, u8 *aosr, u8 *adc_rc,
+ u8 *dac_rc, u8 *dosr_inc)
+{
+ struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
+ u8 prb_rx, prb_tx;
+
+ if (rate <= 48000) {
+ *aosr = 128;
+ *adc_rc = 6;
+ *dac_rc = 8;
+ *dosr_inc = 8;
+ prb_rx = 1;
+ prb_tx = 1;
+ } else if (rate <= 96000) {
+ *aosr = 64;
+ *adc_rc = 6;
+ *dac_rc = 8;
+ *dosr_inc = 4;
+ prb_rx = 1;
+ prb_tx = (aic32x4->type == AIC32X4_TYPE_TAS2505) ? 1 : 9;
+ } else if (rate == 192000) {
+ *aosr = 32;
+ *adc_rc = 3;
+ *dac_rc = 4;
+ *dosr_inc = 2;
+ prb_rx = 13;
+ prb_tx = (aic32x4->type == AIC32X4_TYPE_TAS2505) ? 1 : 19;
+ } else {
+ dev_err(component->dev, "Sampling rate %u not supported\n", rate);
+ return -EINVAL;
+ }
+
+ if (aic32x4->type == AIC32X4_TYPE_TAS2505)
+ prb_rx = 0;
+
+ return aic32x4_set_processing_blocks(component, prb_rx, prb_tx);
+}
+
static int aic32x4_setup_clocks(struct snd_soc_component *component,
unsigned int sample_rate, unsigned int channels,
unsigned int bit_depth)
@@ -717,7 +750,7 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
unsigned long adc_clock_rate, dac_clock_rate;
int ret;
- static struct clk_bulk_data clocks[] = {
+ struct clk_bulk_data clocks[] = {
{ .id = "pll" },
{ .id = "nadc" },
{ .id = "madc" },
@@ -729,37 +762,11 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
if (ret)
return ret;
- if (sample_rate <= 48000) {
- aosr = 128;
- adc_resource_class = 6;
- dac_resource_class = 8;
- dosr_increment = 8;
- if (aic32x4->type == AIC32X4_TYPE_TAS2505)
- aic32x4_set_processing_blocks(component, 0, 1);
- else
- aic32x4_set_processing_blocks(component, 1, 1);
- } else if (sample_rate <= 96000) {
- aosr = 64;
- adc_resource_class = 6;
- dac_resource_class = 8;
- dosr_increment = 4;
- if (aic32x4->type == AIC32X4_TYPE_TAS2505)
- aic32x4_set_processing_blocks(component, 0, 1);
- else
- aic32x4_set_processing_blocks(component, 1, 9);
- } else if (sample_rate == 192000) {
- aosr = 32;
- adc_resource_class = 3;
- dac_resource_class = 4;
- dosr_increment = 2;
- if (aic32x4->type == AIC32X4_TYPE_TAS2505)
- aic32x4_set_processing_blocks(component, 0, 1);
- else
- aic32x4_set_processing_blocks(component, 13, 19);
- } else {
- dev_err(component->dev, "Sampling rate not supported\n");
- return -EINVAL;
- }
+ ret = aic32x4_configure_rate(component, sample_rate, &aosr,
+ &adc_resource_class, &dac_resource_class,
+ &dosr_increment);
+ if (ret)
+ return ret;
/* PCM over I2S is always 2-channel */
if ((aic32x4->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
@@ -781,50 +788,39 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
(min_mdac * dosr * sample_rate);
for (mdac = min_mdac; mdac <= 128; ++mdac) {
for (ndac = max_ndac; ndac > 0; --ndac) {
- dac_clock_rate = ndac * mdac * dosr *
- sample_rate;
- if (dac_clock_rate == adc_clock_rate) {
- if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0)
- continue;
-
- clk_set_rate(clocks[0].clk,
- dac_clock_rate);
-
- clk_set_rate(clocks[1].clk,
- sample_rate * aosr *
- madc);
- clk_set_rate(clocks[2].clk,
- sample_rate * aosr);
- aic32x4_set_aosr(component,
- aosr);
-
- clk_set_rate(clocks[3].clk,
- sample_rate * dosr *
- mdac);
- clk_set_rate(clocks[4].clk,
- sample_rate * dosr);
- aic32x4_set_dosr(component,
- dosr);
-
- clk_set_rate(clocks[5].clk,
- sample_rate * channels *
- bit_depth);
-
- return 0;
- }
+ dac_clock_rate = ndac * mdac * dosr * sample_rate;
+ if (dac_clock_rate != adc_clock_rate)
+ continue;
+
+ if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0)
+ continue;
+
+ clk_set_rate(clocks[0].clk, dac_clock_rate);
+
+ clk_set_rate(clocks[1].clk, sample_rate * aosr * madc);
+ clk_set_rate(clocks[2].clk, sample_rate * aosr);
+ aic32x4_set_aosr(component, aosr);
+
+ clk_set_rate(clocks[3].clk, sample_rate * dosr * mdac);
+ clk_set_rate(clocks[4].clk, sample_rate * dosr);
+ aic32x4_set_dosr(component, dosr);
+
+ clk_set_rate(clocks[5].clk,
+ sample_rate * channels * bit_depth);
+
+ return 0;
}
}
}
}
- dev_err(component->dev,
- "Could not set clocks to support sample rate.\n");
+ dev_err(component->dev, "Could not set clocks to support sample rate.\n");
return -EINVAL;
}
static int aic32x4_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
@@ -837,24 +833,20 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
switch (params_physical_width(params)) {
case 16:
- iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
- AIC32X4_IFACE1_DATALEN_SHIFT);
+ iface1_reg |= (AIC32X4_WORD_LEN_16BITS << AIC32X4_IFACE1_DATALEN_SHIFT);
break;
case 20:
- iface1_reg |= (AIC32X4_WORD_LEN_20BITS <<
- AIC32X4_IFACE1_DATALEN_SHIFT);
+ iface1_reg |= (AIC32X4_WORD_LEN_20BITS << AIC32X4_IFACE1_DATALEN_SHIFT);
break;
case 24:
- iface1_reg |= (AIC32X4_WORD_LEN_24BITS <<
- AIC32X4_IFACE1_DATALEN_SHIFT);
+ iface1_reg |= (AIC32X4_WORD_LEN_24BITS << AIC32X4_IFACE1_DATALEN_SHIFT);
break;
case 32:
- iface1_reg |= (AIC32X4_WORD_LEN_32BITS <<
- AIC32X4_IFACE1_DATALEN_SHIFT);
+ iface1_reg |= (AIC32X4_WORD_LEN_32BITS << AIC32X4_IFACE1_DATALEN_SHIFT);
break;
}
snd_soc_component_update_bits(component, AIC32X4_IFACE1,
- AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
+ AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
if (params_channels(params) == 1) {
dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
@@ -865,7 +857,7 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
}
snd_soc_component_update_bits(component, AIC32X4_DACSETUP,
- AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
+ AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
return 0;
}
@@ -875,7 +867,7 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute, int direction)
struct snd_soc_component *component = dai->component;
snd_soc_component_update_bits(component, AIC32X4_DACMUTE,
- AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
+ AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
return 0;
}
@@ -886,7 +878,7 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component,
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
- static struct clk_bulk_data clocks[] = {
+ struct clk_bulk_data clocks[] = {
{ .id = "madc" },
{ .id = "mdac" },
{ .id = "bdiv" },
@@ -955,44 +947,14 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component)
struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
/* setup GPIO functions */
- /* MFP1 */
- if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_DINCTL,
- aic32x4->setup->gpio_func[0]);
- snd_soc_add_component_controls(component, aic32x4_mfp1,
- ARRAY_SIZE(aic32x4_mfp1));
- }
-
- /* MFP2 */
- if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_DOUTCTL,
- aic32x4->setup->gpio_func[1]);
- snd_soc_add_component_controls(component, aic32x4_mfp2,
- ARRAY_SIZE(aic32x4_mfp2));
- }
-
- /* MFP3 */
- if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_SCLKCTL,
- aic32x4->setup->gpio_func[2]);
- snd_soc_add_component_controls(component, aic32x4_mfp3,
- ARRAY_SIZE(aic32x4_mfp3));
- }
-
- /* MFP4 */
- if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_MISOCTL,
- aic32x4->setup->gpio_func[3]);
- snd_soc_add_component_controls(component, aic32x4_mfp4,
- ARRAY_SIZE(aic32x4_mfp4));
- }
-
- /* MFP5 */
- if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_GPIOCTL,
- aic32x4->setup->gpio_func[4]);
- snd_soc_add_component_controls(component, aic32x4_mfp5,
- ARRAY_SIZE(aic32x4_mfp5));
+ BUILD_BUG_ON(ARRAY_SIZE(aic32x4->gpio_func) != ARRAY_SIZE(aic32x4_mfp_cfg));
+ for (int i = 0; i < ARRAY_SIZE(aic32x4->gpio_func); i++) {
+ if (aic32x4->gpio_func[i] == AIC32X4_MFPX_DEFAULT_VALUE)
+ continue;
+
+ snd_soc_component_write(component, aic32x4_mfp_cfg[i].reg,
+ aic32x4->gpio_func[i]);
+ snd_soc_add_component_controls(component, &aic32x4_mfp_cfg[i].ctrl, 1);
}
}
@@ -1002,7 +964,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
u32 tmp_reg;
int ret;
- static struct clk_bulk_data clocks[] = {
+ struct clk_bulk_data clocks[] = {
{ .id = "codec_clkin" },
{ .id = "pll" },
{ .id = "bdiv" },
@@ -1013,8 +975,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
if (ret)
return ret;
- if (aic32x4->setup)
- aic32x4_setup_gpios(component);
+ aic32x4_setup_gpios(component);
clk_set_parent(clocks[0].clk, clocks[1].clk);
clk_set_parent(clocks[2].clk, clocks[3].clk);
@@ -1022,7 +983,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
/* Power platform configuration */
if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
snd_soc_component_write(component, AIC32X4_MICBIAS,
- AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V);
+ AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V);
}
if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
@@ -1041,16 +1002,16 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
/* Mic PGA routing */
if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K)
snd_soc_component_write(component, AIC32X4_LMICPGANIN,
- AIC32X4_LMICPGANIN_IN2R_10K);
+ AIC32X4_LMICPGANIN_IN2R_10K);
else
snd_soc_component_write(component, AIC32X4_LMICPGANIN,
- AIC32X4_LMICPGANIN_CM1L_10K);
+ AIC32X4_LMICPGANIN_CM1L_10K);
if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K)
snd_soc_component_write(component, AIC32X4_RMICPGANIN,
- AIC32X4_RMICPGANIN_IN1L_10K);
+ AIC32X4_RMICPGANIN_IN1L_10K);
else
snd_soc_component_write(component, AIC32X4_RMICPGANIN,
- AIC32X4_RMICPGANIN_CM1R_10K);
+ AIC32X4_RMICPGANIN_CM1R_10K);
/*
* Workaround: for an unknown reason, the ADC needs to be powered up
@@ -1058,8 +1019,8 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
* a HW BUG or some kind of behavior not documented in the datasheet.
*/
tmp_reg = snd_soc_component_read(component, AIC32X4_ADCSETUP);
- snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg |
- AIC32X4_LADC_EN | AIC32X4_RADC_EN);
+ snd_soc_component_write(component, AIC32X4_ADCSETUP,
+ tmp_reg | AIC32X4_LADC_EN | AIC32X4_RADC_EN);
snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg);
/*
@@ -1102,13 +1063,13 @@ static const struct snd_kcontrol_new aic32x4_tas2505_snd_controls[] = {
SOC_ENUM("DAC Playback PowerTune Switch", l_ptm_enum),
SOC_SINGLE_TLV("HP Driver Gain Volume",
- AIC32X4_HPLGAIN, 0, 0x74, 1, tlv_tas_driver_gain),
+ AIC32X4_HPLGAIN, 0, 0x74, 1, tlv_tas_driver_gain),
SOC_SINGLE("HP DAC Playback Switch", AIC32X4_HPLGAIN, 6, 1, 1),
SOC_SINGLE_TLV("Speaker Driver Playback Volume",
- TAS2505_SPKVOL1, 0, 0x74, 1, tlv_tas_driver_gain),
+ TAS2505_SPKVOL1, 0, 0x74, 1, tlv_tas_driver_gain),
SOC_SINGLE_TLV("Speaker Amplifier Playback Volume",
- TAS2505_SPKVOL2, 4, 5, 0, tlv_amp_vol),
+ TAS2505_SPKVOL2, 4, 5, 0, tlv_amp_vol),
SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
};
@@ -1144,11 +1105,12 @@ static const struct snd_soc_dapm_route aic32x4_tas2505_dapm_routes[] = {
static struct snd_soc_dai_driver aic32x4_tas2505_dai = {
.name = "tas2505-hifi",
.playback = {
- .stream_name = "Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_96000,
- .formats = AIC32X4_FORMATS,},
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = AIC32X4_FORMATS,
+ },
.ops = &aic32x4_ops,
.symmetric_rate = 1,
};
@@ -1159,7 +1121,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component)
u32 tmp_reg;
int ret;
- static struct clk_bulk_data clocks[] = {
+ struct clk_bulk_data clocks[] = {
{ .id = "codec_clkin" },
{ .id = "pll" },
{ .id = "bdiv" },
@@ -1170,8 +1132,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component)
if (ret)
return ret;
- if (aic32x4->setup)
- aic32x4_setup_gpios(component);
+ aic32x4_setup_gpios(component);
clk_set_parent(clocks[0].clk, clocks[1].clk);
clk_set_parent(clocks[2].clk, clocks[3].clk);
@@ -1192,7 +1153,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component)
snd_soc_component_write(component, AIC32X4_CMMODE, tmp_reg);
/*
- * Enable the fast charging feature and ensure the needed 40ms ellapsed
+ * Enable the fast charging feature and ensure the needed 40ms elapsed
* before using the analog circuits.
*/
snd_soc_component_write(component, TAS2505_REFPOWERUP,
@@ -1218,17 +1179,10 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 =
.endianness = 1,
};
-static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
- struct device_node *np)
+static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, struct device_node *np)
{
- struct aic32x4_setup_data *aic32x4_setup;
int ret;
- aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup),
- GFP_KERNEL);
- if (!aic32x4_setup)
- return -ENOMEM;
-
ret = of_property_match_string(np, "clock-names", "mclk");
if (ret < 0)
return -EINVAL;
@@ -1245,9 +1199,11 @@ static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
gpiod_set_consumer_name(aic32x4->rstn_gpio, "tlv320aic32x4_rstn");
}
- if (of_property_read_u32_array(np, "aic32x4-gpio-func",
- aic32x4_setup->gpio_func, 5) >= 0)
- aic32x4->setup = aic32x4_setup;
+ for (int i = 0; i < ARRAY_SIZE(aic32x4->gpio_func); i++)
+ aic32x4->gpio_func[i] = AIC32X4_MFPX_DEFAULT_VALUE;
+ of_property_read_u32_array(np, "aic32x4-gpio-func",
+ aic32x4->gpio_func, ARRAY_SIZE(aic32x4->gpio_func));
+
return 0;
}
@@ -1266,7 +1222,7 @@ static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4)
}
static int aic32x4_setup_regulators(struct device *dev,
- struct aic32x4_priv *aic32x4)
+ struct aic32x4_priv *aic32x4)
{
int ret = 0;
@@ -1356,12 +1312,8 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap,
struct device_node *np = dev->of_node;
int ret;
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv),
- GFP_KERNEL);
- if (aic32x4 == NULL)
+ aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv), GFP_KERNEL);
+ if (!aic32x4)
return -ENOMEM;
aic32x4->dev = dev;
@@ -1405,11 +1357,13 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap,
switch (aic32x4->type) {
case AIC32X4_TYPE_TAS2505:
ret = devm_snd_soc_register_component(dev,
- &soc_component_dev_aic32x4_tas2505, &aic32x4_tas2505_dai, 1);
+ &soc_component_dev_aic32x4_tas2505,
+ &aic32x4_tas2505_dai, 1);
break;
default:
ret = devm_snd_soc_register_component(dev,
- &soc_component_dev_aic32x4, &aic32x4_dai, 1);
+ &soc_component_dev_aic32x4,
+ &aic32x4_dai, 1);
}
if (ret) {
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h
index f68a846ef61d..cfab6f8ce5ac 100644
--- a/sound/soc/codecs/tlv320aic32x4.h
+++ b/sound/soc/codecs/tlv320aic32x4.h
@@ -3,7 +3,6 @@
* tlv320aic32x4.h
*/
-
#ifndef _TLV320AIC32X4_H
#define _TLV320AIC32X4_H
@@ -16,7 +15,7 @@ enum aic32x4_type {
AIC32X4_TYPE_TAS2505,
};
-extern const struct regmap_config aic32x4_regmap_config;
+extern const struct regmap_range_cfg aic32x4_regmap_pages[];
int aic32x4_probe(struct device *dev, struct regmap *regmap,
enum aic32x4_type type);
void aic32x4_remove(struct device *dev);
@@ -24,7 +23,7 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
/* tlv320aic32x4 register space (in decimal to match datasheet) */
-#define AIC32X4_REG(page, reg) ((page * 128) + reg)
+#define AIC32X4_REG(page, reg) (((page) * 128) + (reg))
#define AIC32X4_PSEL AIC32X4_REG(0, 0)
@@ -234,4 +233,31 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
#define AIC32X4_MAX_CODEC_CLKIN_FREQ 110000000
#define AIC32X4_MAX_PLL_CLKIN 20000000
+#define AIC32X4_PWR_MICBIAS_2075_LDOIN 0x00000001
+#define AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE 0x00000002
+#define AIC32X4_PWR_AIC32X4_LDO_ENABLE 0x00000004
+#define AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36 0x00000008
+#define AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED 0x00000010
+
+#define AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K 0x00000001
+#define AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K 0x00000002
+
+/* GPIO API */
+#define AIC32X4_MFPX_DEFAULT_VALUE 0xff
+
+#define AIC32X4_MFP1_DIN_DISABLED 0
+#define AIC32X4_MFP1_DIN_ENABLED 0x2
+#define AIC32X4_MFP1_GPIO_IN 0x4
+
+#define AIC32X4_MFP2_GPIO_OUT_LOW 0x0
+#define AIC32X4_MFP2_GPIO_OUT_HIGH 0x1
+
+#define AIC32X4_MFP_GPIO_ENABLED 0x4
+
+#define AIC32X4_MFP5_GPIO_DISABLED 0x0
+#define AIC32X4_MFP5_GPIO_INPUT 0x8
+#define AIC32X4_MFP5_GPIO_OUTPUT 0xc
+#define AIC32X4_MFP5_GPIO_OUT_LOW 0x0
+#define AIC32X4_MFP5_GPIO_OUT_HIGH 0x1
+
#endif /* _TLV320AIC32X4_H */
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 223c49dfc450..9bd2ddd8dacd 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -7,6 +7,7 @@
* Copyright: (C) 2009 Nokia Corporation
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -236,13 +237,10 @@ static int dac33_write_locked(struct snd_soc_component *component, unsigned int
unsigned int value)
{
struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&dac33->mutex);
- ret = dac33_write(component, reg, value);
- mutex_unlock(&dac33->mutex);
+ guard(mutex)(&dac33->mutex);
- return ret;
+ return dac33_write(component, reg, value);
}
#define DAC33_I2C_ADDR_AUTOINC 0x80
@@ -365,13 +363,13 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
int ret = 0;
- mutex_lock(&dac33->mutex);
+ guard(mutex)(&dac33->mutex);
/* Safety check */
if (unlikely(power == dac33->chip_power)) {
dev_dbg(component->dev, "Trying to set the same power state: %s\n",
power ? "ON" : "OFF");
- goto exit;
+ return ret;
}
if (power) {
@@ -380,7 +378,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
if (ret != 0) {
dev_err(component->dev,
"Failed to enable supplies: %d\n", ret);
- goto exit;
+ return ret;
}
if (dac33->reset_gpiod) {
@@ -388,7 +386,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
if (ret < 0) {
dev_err(&dac33->i2c->dev,
"Failed to set reset GPIO: %d\n", ret);
- goto exit;
+ return ret;
}
}
@@ -400,7 +398,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
if (ret < 0) {
dev_err(&dac33->i2c->dev,
"Failed to set reset GPIO: %d\n", ret);
- goto exit;
+ return ret;
}
}
@@ -409,14 +407,12 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
if (ret != 0) {
dev_err(component->dev,
"Failed to disable supplies: %d\n", ret);
- goto exit;
+ return ret;
}
dac33->chip_power = 0;
}
-exit:
- mutex_unlock(&dac33->mutex);
return ret;
}
@@ -659,7 +655,6 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
{
struct snd_soc_component *component = dac33->component;
unsigned int delay;
- unsigned long flags;
switch (dac33->fifo_mode) {
case DAC33_FIFO_MODE1:
@@ -667,10 +662,10 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
DAC33_THRREG(dac33->nsample));
/* Take the timestamps */
- spin_lock_irqsave(&dac33->lock, flags);
- dac33->t_stamp2 = ktime_to_us(ktime_get());
- dac33->t_stamp1 = dac33->t_stamp2;
- spin_unlock_irqrestore(&dac33->lock, flags);
+ scoped_guard(spinlock_irqsave, &dac33->lock) {
+ dac33->t_stamp2 = ktime_to_us(ktime_get());
+ dac33->t_stamp1 = dac33->t_stamp2;
+ }
dac33_write16(component, DAC33_PREFILL_MSB,
DAC33_THRREG(dac33->alarm_threshold));
@@ -682,11 +677,11 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
break;
case DAC33_FIFO_MODE7:
/* Take the timestamp */
- spin_lock_irqsave(&dac33->lock, flags);
- dac33->t_stamp1 = ktime_to_us(ktime_get());
- /* Move back the timestamp with drain time */
- dac33->t_stamp1 -= dac33->mode7_us_to_lthr;
- spin_unlock_irqrestore(&dac33->lock, flags);
+ scoped_guard(spinlock_irqsave, &dac33->lock) {
+ dac33->t_stamp1 = ktime_to_us(ktime_get());
+ /* Move back the timestamp with drain time */
+ dac33->t_stamp1 -= dac33->mode7_us_to_lthr;
+ }
dac33_write16(component, DAC33_PREFILL_MSB,
DAC33_THRREG(DAC33_MODE7_MARGIN));
@@ -704,14 +699,12 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
{
struct snd_soc_component *component = dac33->component;
- unsigned long flags;
switch (dac33->fifo_mode) {
case DAC33_FIFO_MODE1:
/* Take the timestamp */
- spin_lock_irqsave(&dac33->lock, flags);
- dac33->t_stamp2 = ktime_to_us(ktime_get());
- spin_unlock_irqrestore(&dac33->lock, flags);
+ scoped_guard(spinlock_irqsave, &dac33->lock)
+ dac33->t_stamp2 = ktime_to_us(ktime_get());
dac33_write16(component, DAC33_NSAMPLE_MSB,
DAC33_THRREG(dac33->nsample));
@@ -735,7 +728,7 @@ static void dac33_work(struct work_struct *work)
dac33 = container_of(work, struct tlv320dac33_priv, work);
component = dac33->component;
- mutex_lock(&dac33->mutex);
+ guard(mutex)(&dac33->mutex);
switch (dac33->state) {
case DAC33_PREFILL:
dac33->state = DAC33_PLAYBACK;
@@ -757,18 +750,15 @@ static void dac33_work(struct work_struct *work)
dac33_write(component, DAC33_FIFO_CTRL_A, reg);
break;
}
- mutex_unlock(&dac33->mutex);
}
static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
{
struct snd_soc_component *component = dev;
struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
- unsigned long flags;
- spin_lock_irqsave(&dac33->lock, flags);
- dac33->t_stamp1 = ktime_to_us(ktime_get());
- spin_unlock_irqrestore(&dac33->lock, flags);
+ scoped_guard(spinlock_irqsave, &dac33->lock)
+ dac33->t_stamp1 = ktime_to_us(ktime_get());
/* Do not schedule the workqueue in Mode7 */
if (dac33->fifo_mode != DAC33_FIFO_MODE7)
@@ -902,14 +892,13 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream,
return -EINVAL;
}
- mutex_lock(&dac33->mutex);
+ guard(mutex)(&dac33->mutex);
if (!dac33->chip_power) {
/*
* Chip is not powered yet.
* Do the init in the dac33_set_bias_level later.
*/
- mutex_unlock(&dac33->mutex);
return 0;
}
@@ -1053,8 +1042,6 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream,
break;
}
- mutex_unlock(&dac33->mutex);
-
return 0;
}
@@ -1156,21 +1143,20 @@ static snd_pcm_sframes_t dac33_dai_delay(
unsigned int time_delta, uthr;
int samples_out, samples_in, samples;
snd_pcm_sframes_t delay = 0;
- unsigned long flags;
switch (dac33->fifo_mode) {
case DAC33_FIFO_BYPASS:
break;
case DAC33_FIFO_MODE1:
- spin_lock_irqsave(&dac33->lock, flags);
- t0 = dac33->t_stamp1;
- t1 = dac33->t_stamp2;
- spin_unlock_irqrestore(&dac33->lock, flags);
+ scoped_guard(spinlock_irqsave, &dac33->lock) {
+ t0 = dac33->t_stamp1;
+ t1 = dac33->t_stamp2;
+ }
t_now = ktime_to_us(ktime_get());
/* We have not started to fill the FIFO yet, delay is 0 */
if (!t1)
- goto out;
+ return 0;
if (t0 > t1) {
/*
@@ -1230,23 +1216,22 @@ static snd_pcm_sframes_t dac33_dai_delay(
}
break;
case DAC33_FIFO_MODE7:
- spin_lock_irqsave(&dac33->lock, flags);
- t0 = dac33->t_stamp1;
- uthr = dac33->uthr;
- spin_unlock_irqrestore(&dac33->lock, flags);
+ scoped_guard(spinlock_irqsave, &dac33->lock) {
+ t0 = dac33->t_stamp1;
+ uthr = dac33->uthr;
+ }
t_now = ktime_to_us(ktime_get());
/* We have not started to fill the FIFO yet, delay is 0 */
if (!t0)
- goto out;
+ return 0;
if (t_now <= t0) {
/*
* Either the timestamps are messed or equal. Report
* maximum delay
*/
- delay = uthr;
- goto out;
+ return uthr;
}
time_delta = t_now - t0;
@@ -1287,7 +1272,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
dac33->fifo_mode);
break;
}
-out:
+
return delay;
}
diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c
index dba581857920..02082ef790b4 100644
--- a/sound/soc/codecs/tscs42xx.c
+++ b/sound/soc/codecs/tscs42xx.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <sound/tlv.h>
#include <sound/pcm_params.h>
@@ -210,25 +211,21 @@ static int power_up_audio_plls(struct snd_soc_component *component)
return ret;
}
- mutex_lock(&tscs42xx->pll_lock);
+ guard(mutex)(&tscs42xx->pll_lock);
ret = snd_soc_component_update_bits(component, R_PLLCTL1C, mask, val);
if (ret < 0) {
dev_err(component->dev, "Failed to turn PLL on (%d)\n", ret);
- goto exit;
+ return ret;
}
if (!plls_locked(component)) {
dev_err(component->dev, "Failed to lock plls\n");
ret = -ENOMSG;
- goto exit;
+ return ret;
}
- ret = 0;
-exit:
- mutex_unlock(&tscs42xx->pll_lock);
-
- return ret;
+ return 0;
}
static int power_down_audio_plls(struct snd_soc_component *component)
@@ -236,28 +233,24 @@ static int power_down_audio_plls(struct snd_soc_component *component)
struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
int ret;
- mutex_lock(&tscs42xx->pll_lock);
+ guard(mutex)(&tscs42xx->pll_lock);
ret = snd_soc_component_update_bits(component, R_PLLCTL1C,
RM_PLLCTL1C_PDB_PLL1,
RV_PLLCTL1C_PDB_PLL1_DISABLE);
if (ret < 0) {
dev_err(component->dev, "Failed to turn PLL off (%d)\n", ret);
- goto exit;
+ return ret;
}
ret = snd_soc_component_update_bits(component, R_PLLCTL1C,
RM_PLLCTL1C_PDB_PLL2,
RV_PLLCTL1C_PDB_PLL2_DISABLE);
if (ret < 0) {
dev_err(component->dev, "Failed to turn PLL off (%d)\n", ret);
- goto exit;
+ return ret;
}
- ret = 0;
-exit:
- mutex_unlock(&tscs42xx->pll_lock);
-
- return ret;
+ return 0;
}
static int coeff_ram_get(struct snd_kcontrol *kcontrol,
@@ -269,13 +262,11 @@ static int coeff_ram_get(struct snd_kcontrol *kcontrol,
(struct coeff_ram_ctl *)kcontrol->private_value;
struct soc_bytes_ext *params = &ctl->bytes_ext;
- mutex_lock(&tscs42xx->coeff_ram_lock);
+ guard(mutex)(&tscs42xx->coeff_ram_lock);
memcpy(ucontrol->value.bytes.data,
&tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE], params->max);
- mutex_unlock(&tscs42xx->coeff_ram_lock);
-
return 0;
}
@@ -290,14 +281,14 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol,
unsigned int coeff_cnt = params->max / COEFF_SIZE;
int ret;
- mutex_lock(&tscs42xx->coeff_ram_lock);
+ guard(mutex)(&tscs42xx->coeff_ram_lock);
tscs42xx->coeff_ram_synced = false;
memcpy(&tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE],
ucontrol->value.bytes.data, params->max);
- mutex_lock(&tscs42xx->pll_lock);
+ guard(mutex)(&tscs42xx->pll_lock);
if (plls_locked(component)) {
ret = write_coeff_ram(component, tscs42xx->coeff_ram,
@@ -305,18 +296,12 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol,
if (ret < 0) {
dev_err(component->dev,
"Failed to flush coeff ram cache (%d)\n", ret);
- goto exit;
+ return ret;
}
tscs42xx->coeff_ram_synced = true;
}
- ret = 0;
-exit:
- mutex_unlock(&tscs42xx->pll_lock);
-
- mutex_unlock(&tscs42xx->coeff_ram_lock);
-
- return ret;
+ return 0;
}
/* Input L Capture Route */
@@ -385,21 +370,17 @@ static int dac_event(struct snd_soc_dapm_widget *w,
struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
int ret;
- mutex_lock(&tscs42xx->coeff_ram_lock);
+ guard(mutex)(&tscs42xx->coeff_ram_lock);
if (!tscs42xx->coeff_ram_synced) {
ret = write_coeff_ram(component, tscs42xx->coeff_ram, 0x00,
COEFF_RAM_COEFF_COUNT);
if (ret < 0)
- goto exit;
+ return ret;
tscs42xx->coeff_ram_synced = true;
}
- ret = 0;
-exit:
- mutex_unlock(&tscs42xx->coeff_ram_lock);
-
- return ret;
+ return 0;
}
static const struct snd_soc_dapm_widget tscs42xx_dapm_widgets[] = {
@@ -926,12 +907,10 @@ static int setup_sample_rate(struct snd_soc_component *component,
return ret;
}
- mutex_lock(&tscs42xx->audio_params_lock);
+ guard(mutex)(&tscs42xx->audio_params_lock);
tscs42xx->samplerate = rate;
- mutex_unlock(&tscs42xx->audio_params_lock);
-
return 0;
}
@@ -1253,12 +1232,10 @@ static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai,
return ret;
}
- mutex_lock(&tscs42xx->audio_params_lock);
+ guard(mutex)(&tscs42xx->audio_params_lock);
tscs42xx->bclk_ratio = ratio;
- mutex_unlock(&tscs42xx->audio_params_lock);
-
return 0;
}
diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c
index aad394937ce6..b70c9d931e1e 100644
--- a/sound/soc/codecs/tscs454.c
+++ b/sound/soc/codecs/tscs454.c
@@ -4,6 +4,7 @@
// Author: Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
#include <linux/kernel.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/regmap.h>
@@ -329,12 +330,10 @@ static int coeff_ram_get(struct snd_kcontrol *kcontrol,
return -EINVAL;
}
- mutex_lock(coeff_ram_lock);
-
- memcpy(ucontrol->value.bytes.data,
- &coeff_ram[ctl->addr * COEFF_SIZE], params->max);
-
- mutex_unlock(coeff_ram_lock);
+ scoped_guard(mutex, coeff_ram_lock) {
+ memcpy(ucontrol->value.bytes.data,
+ &coeff_ram[ctl->addr * COEFF_SIZE], params->max);
+ }
return 0;
}
@@ -428,15 +427,15 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
}
- mutex_lock(coeff_ram_lock);
+ guard(mutex)(coeff_ram_lock);
*coeff_ram_synced = false;
memcpy(&coeff_ram[ctl->addr * COEFF_SIZE],
ucontrol->value.bytes.data, params->max);
- mutex_lock(&tscs454->pll1.lock);
- mutex_lock(&tscs454->pll2.lock);
+ guard(mutex)(&tscs454->pll1.lock);
+ guard(mutex)(&tscs454->pll2.lock);
val = snd_soc_component_read(component, R_PLLSTAT);
if (val) { /* PLLs locked */
@@ -446,18 +445,12 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol,
if (ret < 0) {
dev_err(component->dev,
"Failed to flush coeff ram cache (%d)\n", ret);
- goto exit;
+ return ret;
}
*coeff_ram_synced = true;
}
- ret = 0;
-exit:
- mutex_unlock(&tscs454->pll2.lock);
- mutex_unlock(&tscs454->pll1.lock);
- mutex_unlock(coeff_ram_lock);
-
- return ret;
+ return 0;
}
static inline int coeff_ram_sync(struct snd_soc_component *component,
@@ -465,41 +458,35 @@ static inline int coeff_ram_sync(struct snd_soc_component *component,
{
int ret;
- mutex_lock(&tscs454->dac_ram.lock);
- if (!tscs454->dac_ram.synced) {
- ret = write_coeff_ram(component, tscs454->dac_ram.cache,
- R_DACCRS, R_DACCRADD, R_DACCRWDL,
- 0x00, COEFF_RAM_COEFF_COUNT);
- if (ret < 0) {
- mutex_unlock(&tscs454->dac_ram.lock);
- return ret;
+ scoped_guard(mutex, &tscs454->dac_ram.lock) {
+ if (!tscs454->dac_ram.synced) {
+ ret = write_coeff_ram(component, tscs454->dac_ram.cache,
+ R_DACCRS, R_DACCRADD, R_DACCRWDL,
+ 0x00, COEFF_RAM_COEFF_COUNT);
+ if (ret < 0)
+ return ret;
}
}
- mutex_unlock(&tscs454->dac_ram.lock);
- mutex_lock(&tscs454->spk_ram.lock);
- if (!tscs454->spk_ram.synced) {
- ret = write_coeff_ram(component, tscs454->spk_ram.cache,
- R_SPKCRS, R_SPKCRADD, R_SPKCRWDL,
- 0x00, COEFF_RAM_COEFF_COUNT);
- if (ret < 0) {
- mutex_unlock(&tscs454->spk_ram.lock);
- return ret;
+ scoped_guard(mutex, &tscs454->spk_ram.lock) {
+ if (!tscs454->spk_ram.synced) {
+ ret = write_coeff_ram(component, tscs454->spk_ram.cache,
+ R_SPKCRS, R_SPKCRADD, R_SPKCRWDL,
+ 0x00, COEFF_RAM_COEFF_COUNT);
+ if (ret < 0)
+ return ret;
}
}
- mutex_unlock(&tscs454->spk_ram.lock);
- mutex_lock(&tscs454->sub_ram.lock);
- if (!tscs454->sub_ram.synced) {
- ret = write_coeff_ram(component, tscs454->sub_ram.cache,
- R_SUBCRS, R_SUBCRADD, R_SUBCRWDL,
- 0x00, COEFF_RAM_COEFF_COUNT);
- if (ret < 0) {
- mutex_unlock(&tscs454->sub_ram.lock);
- return ret;
+ scoped_guard(mutex, &tscs454->sub_ram.lock) {
+ if (!tscs454->sub_ram.synced) {
+ ret = write_coeff_ram(component, tscs454->sub_ram.cache,
+ R_SUBCRS, R_SUBCRADD, R_SUBCRWDL,
+ 0x00, COEFF_RAM_COEFF_COUNT);
+ if (ret < 0)
+ return ret;
}
}
- mutex_unlock(&tscs454->sub_ram.lock);
return 0;
}
@@ -658,16 +645,14 @@ static int set_sysclk(struct snd_soc_component *component)
static inline void reserve_pll(struct pll *pll)
{
- mutex_lock(&pll->lock);
+ guard(mutex)(&pll->lock);
pll->users++;
- mutex_unlock(&pll->lock);
}
static inline void free_pll(struct pll *pll)
{
- mutex_lock(&pll->lock);
+ guard(mutex)(&pll->lock);
pll->users--;
- mutex_unlock(&pll->lock);
}
static int pll_connected(struct snd_soc_dapm_widget *source,
@@ -679,15 +664,13 @@ static int pll_connected(struct snd_soc_dapm_widget *source,
int users;
if (strstr(source->name, "PLL 1")) {
- mutex_lock(&tscs454->pll1.lock);
- users = tscs454->pll1.users;
- mutex_unlock(&tscs454->pll1.lock);
+ scoped_guard(mutex, &tscs454->pll1.lock)
+ users = tscs454->pll1.users;
dev_dbg(component->dev, "%s(): PLL 1 users = %d\n", __func__,
users);
} else {
- mutex_lock(&tscs454->pll2.lock);
- users = tscs454->pll2.users;
- mutex_unlock(&tscs454->pll2.lock);
+ scoped_guard(mutex, &tscs454->pll2.lock)
+ users = tscs454->pll2.users;
dev_dbg(component->dev, "%s(): PLL 2 users = %d\n", __func__,
users);
}
@@ -806,7 +789,7 @@ static inline int aif_free(struct snd_soc_component *component,
{
struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
- mutex_lock(&tscs454->aifs_status_lock);
+ guard(mutex)(&tscs454->aifs_status_lock);
dev_dbg(component->dev, "%s(): aif %d\n", __func__, aif->id);
@@ -829,8 +812,6 @@ static inline int aif_free(struct snd_soc_component *component,
free_pll(tscs454->internal_rate.pll);
}
- mutex_unlock(&tscs454->aifs_status_lock);
-
return 0;
}
@@ -3174,7 +3155,7 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream,
unsigned int val;
int ret;
- mutex_lock(&tscs454->aifs_status_lock);
+ guard(mutex)(&tscs454->aifs_status_lock);
dev_dbg(component->dev, "%s(): aif %d fs = %u\n", __func__,
aif->id, fs);
@@ -3207,14 +3188,14 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream,
ret = set_aif_fs(component, aif->id, fs);
if (ret < 0) {
dev_err(component->dev, "Failed to set aif fs (%d)\n", ret);
- goto exit;
+ return ret;
}
ret = set_aif_sample_format(component, params_format(params), aif->id);
if (ret < 0) {
dev_err(component->dev,
"Failed to set aif sample format (%d)\n", ret);
- goto exit;
+ return ret;
}
set_aif_status_active(&tscs454->aifs_status, aif->id,
@@ -3223,11 +3204,7 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream,
dev_dbg(component->dev, "Set aif %d active. Streams status is 0x%x\n",
aif->id, tscs454->aifs_status.streams);
- ret = 0;
-exit:
- mutex_unlock(&tscs454->aifs_status_lock);
-
- return ret;
+ return 0;
}
static int tscs454_hw_free(struct snd_pcm_substream *substream,
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index e10c51092a35..650836f9615f 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
@@ -273,7 +274,7 @@ static void twl6040_hs_jack_report(struct snd_soc_component *component,
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
int status;
- mutex_lock(&priv->mutex);
+ guard(mutex)(&priv->mutex);
/* Sync status */
status = twl6040_read(component, TWL6040_REG_STATUS);
@@ -281,8 +282,6 @@ static void twl6040_hs_jack_report(struct snd_soc_component *component,
snd_soc_jack_report(jack, report, report);
else
snd_soc_jack_report(jack, 0, report);
-
- mutex_unlock(&priv->mutex);
}
void twl6040_hs_jack_detect(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/uda1342.c b/sound/soc/codecs/uda1342.c
index 12f5757f4210..4e2d6240a869 100644
--- a/sound/soc/codecs/uda1342.c
+++ b/sound/soc/codecs/uda1342.c
@@ -308,9 +308,16 @@ static int uda1342_suspend(struct device *dev)
static int uda1342_resume(struct device *dev)
{
struct uda1342_priv *uda1342 = dev_get_drvdata(dev);
+ int ret;
+ regcache_cache_only(uda1342->regmap, false);
regcache_mark_dirty(uda1342->regmap);
- regcache_sync(uda1342->regmap);
+ ret = regcache_sync(uda1342->regmap);
+ if (ret) {
+ regcache_cache_only(uda1342->regmap, true);
+ regcache_mark_dirty(uda1342->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index e3ca5ca6de3d..40de279a9750 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -5010,9 +5010,9 @@ static int wcd9335_power_on_reset(struct wcd9335_codec *wcd)
*/
usleep_range(600, 650);
- gpiod_set_value(wcd->reset_gpio, 1);
+ gpiod_set_value_cansleep(wcd->reset_gpio, 1);
msleep(20);
- gpiod_set_value(wcd->reset_gpio, 0);
+ gpiod_set_value_cansleep(wcd->reset_gpio, 0);
msleep(20);
return 0;
diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c
index bc41a1466c70..caca5cc25100 100644
--- a/sound/soc/codecs/wcd934x.c
+++ b/sound/soc/codecs/wcd934x.c
@@ -1265,13 +1265,10 @@ static int wcd934x_set_sido_input_src(struct wcd934x_codec *wcd, int sido_src)
static int wcd934x_enable_ana_bias_and_sysclk(struct wcd934x_codec *wcd)
{
- mutex_lock(&wcd->sysclk_mutex);
-
- if (++wcd->sysclk_users != 1) {
- mutex_unlock(&wcd->sysclk_mutex);
- return 0;
+ scoped_guard(mutex, &wcd->sysclk_mutex) {
+ if (++wcd->sysclk_users != 1)
+ return 0;
}
- mutex_unlock(&wcd->sysclk_mutex);
regmap_update_bits(wcd->regmap, WCD934X_ANA_BIAS,
WCD934X_ANA_BIAS_EN_MASK,
@@ -1328,12 +1325,10 @@ static int wcd934x_enable_ana_bias_and_sysclk(struct wcd934x_codec *wcd)
static int wcd934x_disable_ana_bias_and_syclk(struct wcd934x_codec *wcd)
{
- mutex_lock(&wcd->sysclk_mutex);
- if (--wcd->sysclk_users != 0) {
- mutex_unlock(&wcd->sysclk_mutex);
- return 0;
+ scoped_guard(mutex, &wcd->sysclk_mutex) {
+ if (--wcd->sysclk_users != 0)
+ return 0;
}
- mutex_unlock(&wcd->sysclk_mutex);
regmap_update_bits(wcd->regmap, WCD934X_CLK_SYS_MCLK_PRG,
WCD934X_EXT_CLK_BUF_EN_MASK |
@@ -2384,7 +2379,7 @@ static int wcd934x_micbias_control(struct snd_soc_component *component,
__func__, micb_num);
return -EINVAL;
}
- mutex_lock(&wcd934x->micb_lock);
+ guard(mutex)(&wcd934x->micb_lock);
switch (req) {
case MICB_PULLUP_ENABLE:
@@ -2446,8 +2441,6 @@ static int wcd934x_micbias_control(struct snd_soc_component *component,
break;
}
- mutex_unlock(&wcd934x->micb_lock);
-
return 0;
}
@@ -2488,7 +2481,7 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
int req_volt, int micb_num)
{
struct wcd934x_codec *wcd934x = snd_soc_component_get_drvdata(component);
- int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0;
+ int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en;
switch (micb_num) {
case MIC_BIAS_1:
@@ -2506,7 +2499,7 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
default:
return -EINVAL;
}
- mutex_lock(&wcd934x->micb_lock);
+ guard(mutex)(&wcd934x->micb_lock);
/*
* If requested micbias voltage is same as current micbias
* voltage, then just return. Otherwise, adjust voltage as
@@ -2521,15 +2514,11 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
WCD934X_MICB_VAL_MASK);
req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt);
- if (req_vout_ctl < 0) {
- ret = -EINVAL;
- goto exit;
- }
+ if (req_vout_ctl < 0)
+ return -EINVAL;
- if (cur_vout_ctl == req_vout_ctl) {
- ret = 0;
- goto exit;
- }
+ if (cur_vout_ctl == req_vout_ctl)
+ return 0;
if (micb_en == WCD934X_MICB_ENABLE)
snd_soc_component_write_field(component, micb_reg,
@@ -2550,9 +2539,8 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
*/
usleep_range(2000, 2100);
}
-exit:
- mutex_unlock(&wcd934x->micb_lock);
- return ret;
+
+ return 0;
}
static int wcd934x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component,
@@ -5899,10 +5887,8 @@ static int wcd934x_codec_probe(struct platform_device *pdev)
}
static const struct platform_device_id wcd934x_driver_id[] = {
- {
- .name = "wcd934x-codec",
- },
- {},
+ { .name = "wcd934x-codec" },
+ { }
};
MODULE_DEVICE_TABLE(platform, wcd934x_driver_id);
diff --git a/sound/soc/codecs/wcd937x-sdw.c b/sound/soc/codecs/wcd937x-sdw.c
index 7a18bed7f347..1ad75c226060 100644
--- a/sound/soc/codecs/wcd937x-sdw.c
+++ b/sound/soc/codecs/wcd937x-sdw.c
@@ -1084,10 +1084,16 @@ static int wcd937x_sdw_runtime_suspend(struct device *dev)
static int wcd937x_sdw_runtime_resume(struct device *dev)
{
struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev);
+ int ret;
if (wcd->regmap) {
regcache_cache_only(wcd->regmap, false);
- regcache_sync(wcd->regmap);
+ ret = regcache_sync(wcd->regmap);
+ if (ret) {
+ regcache_cache_only(wcd->regmap, true);
+ regcache_mark_dirty(wcd->regmap);
+ return ret;
+ }
}
return 0;
diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c
index e0169e783ee9..0dd05604f5b8 100644
--- a/sound/soc/codecs/wcd937x.c
+++ b/sound/soc/codecs/wcd937x.c
@@ -2,6 +2,7 @@
// Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
#include <linux/component.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
@@ -1056,7 +1057,7 @@ static int wcd937x_micbias_control(struct snd_soc_component *component,
return -EINVAL;
}
- mutex_lock(&wcd937x->micb_lock);
+ guard(mutex)(&wcd937x->micb_lock);
switch (req) {
case MICB_PULLUP_ENABLE:
wcd937x->pullup_ref[micb_index]++;
@@ -1136,7 +1137,6 @@ static int wcd937x_micbias_control(struct snd_soc_component *component,
}
break;
}
- mutex_unlock(&wcd937x->micb_lock);
return 0;
}
@@ -1460,7 +1460,7 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
int req_volt, int micb_num)
{
struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
- int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0;
+ int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en;
switch (micb_num) {
case MIC_BIAS_1:
@@ -1475,7 +1475,7 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
default:
return -EINVAL;
}
- mutex_lock(&wcd937x->micb_lock);
+ guard(mutex)(&wcd937x->micb_lock);
/*
* If requested micbias voltage is same as current micbias
* voltage, then just return. Otherwise, adjust voltage as
@@ -1490,15 +1490,11 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
WCD937X_MICB_VOUT_MASK);
req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt);
- if (req_vout_ctl < 0) {
- ret = -EINVAL;
- goto exit;
- }
+ if (req_vout_ctl < 0)
+ return -EINVAL;
- if (cur_vout_ctl == req_vout_ctl) {
- ret = 0;
- goto exit;
- }
+ if (cur_vout_ctl == req_vout_ctl)
+ return 0;
if (micb_en == WCD937X_MICB_ENABLE)
snd_soc_component_write_field(component, micb_reg,
@@ -1519,9 +1515,8 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
*/
usleep_range(2000, 2100);
}
-exit:
- mutex_unlock(&wcd937x->micb_lock);
- return ret;
+
+ return 0;
}
static int wcd937x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c
index 0f0cc0ac3056..e5ad368418a2 100644
--- a/sound/soc/codecs/wcd938x-sdw.c
+++ b/sound/soc/codecs/wcd938x-sdw.c
@@ -1245,10 +1245,16 @@ static int wcd938x_sdw_runtime_suspend(struct device *dev)
static int wcd938x_sdw_runtime_resume(struct device *dev)
{
struct wcd938x_sdw_priv *wcd = dev_get_drvdata(dev);
+ int ret;
if (wcd->regmap) {
regcache_cache_only(wcd->regmap, false);
- regcache_sync(wcd->regmap);
+ ret = regcache_sync(wcd->regmap);
+ if (ret) {
+ regcache_cache_only(wcd->regmap, true);
+ regcache_mark_dirty(wcd->regmap);
+ return ret;
+ }
}
pm_runtime_mark_last_busy(dev);
diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index c69e18667a85..9a9ea37ecab3 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
@@ -1976,7 +1977,7 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
int req_volt, int micb_num)
{
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
- int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0;
+ int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en;
switch (micb_num) {
case MIC_BIAS_1:
@@ -1994,7 +1995,7 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
default:
return -EINVAL;
}
- mutex_lock(&wcd938x->micb_lock);
+ guard(mutex)(&wcd938x->micb_lock);
/*
* If requested micbias voltage is same as current micbias
* voltage, then just return. Otherwise, adjust voltage as
@@ -2009,15 +2010,11 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
WCD938X_MICB_VOUT_MASK);
req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt);
- if (req_vout_ctl < 0) {
- ret = -EINVAL;
- goto exit;
- }
+ if (req_vout_ctl < 0)
+ return -EINVAL;
- if (cur_vout_ctl == req_vout_ctl) {
- ret = 0;
- goto exit;
- }
+ if (cur_vout_ctl == req_vout_ctl)
+ return 0;
if (micb_en == WCD938X_MICB_ENABLE)
snd_soc_component_write_field(component, micb_reg,
@@ -2038,9 +2035,8 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
*/
usleep_range(2000, 2100);
}
-exit:
- mutex_unlock(&wcd938x->micb_lock);
- return ret;
+
+ return 0;
}
static int wcd938x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/wcd939x-sdw.c b/sound/soc/codecs/wcd939x-sdw.c
index 95f4be287e79..69b9b08118f0 100644
--- a/sound/soc/codecs/wcd939x-sdw.c
+++ b/sound/soc/codecs/wcd939x-sdw.c
@@ -1431,10 +1431,16 @@ static int wcd939x_sdw_runtime_suspend(struct device *dev)
static int wcd939x_sdw_runtime_resume(struct device *dev)
{
struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev);
+ int ret;
if (wcd->regmap) {
regcache_cache_only(wcd->regmap, false);
- regcache_sync(wcd->regmap);
+ ret = regcache_sync(wcd->regmap);
+ if (ret) {
+ regcache_cache_only(wcd->regmap, true);
+ regcache_mark_dirty(wcd->regmap);
+ return ret;
+ }
}
return 0;
diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c
index 010d12466722..26fe0b6313cd 100644
--- a/sound/soc/codecs/wcd939x.c
+++ b/sound/soc/codecs/wcd939x.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
@@ -1923,7 +1924,6 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
unsigned int micb_reg, cur_vout_ctl, micb_en;
int req_vout_ctl;
- int ret = 0;
switch (micb_num) {
case MIC_BIAS_1:
@@ -1941,7 +1941,7 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
default:
return -EINVAL;
}
- mutex_lock(&wcd939x->micb_lock);
+ guard(mutex)(&wcd939x->micb_lock);
/*
* If requested micbias voltage is same as current micbias
@@ -1957,15 +1957,11 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
WCD939X_MICB_VOUT_CTL);
req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt);
- if (req_vout_ctl < 0) {
- ret = req_vout_ctl;
- goto exit;
- }
+ if (req_vout_ctl < 0)
+ return req_vout_ctl;
- if (cur_vout_ctl == req_vout_ctl) {
- ret = 0;
- goto exit;
- }
+ if (cur_vout_ctl == req_vout_ctl)
+ return 0;
dev_dbg(component->dev, "%s: micb_num: %d, cur_mv: %d, req_mv: %d, micb_en: %d\n",
__func__, micb_num, WCD_VOUT_CTL_TO_MICB(cur_vout_ctl),
@@ -1990,9 +1986,7 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
usleep_range(2000, 2100);
}
-exit:
- mutex_unlock(&wcd939x->micb_lock);
- return ret;
+ return 0;
}
static int wcd939x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index 2a8c61a72c17..c44abffe9b56 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -9,6 +9,7 @@
* Scott Ling <sl@opensource.wolfsonmicro.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
@@ -148,13 +149,11 @@ static const char *wm0010_state_to_str(enum wm0010_state state)
static void wm0010_halt(struct snd_soc_component *component)
{
struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
- unsigned long flags;
enum wm0010_state state;
/* Fetch the wm0010 state */
- spin_lock_irqsave(&wm0010->irq_lock, flags);
- state = wm0010->state;
- spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+ scoped_guard(spinlock_irqsave, &wm0010->irq_lock)
+ state = wm0010->state;
switch (state) {
case WM0010_POWER_OFF:
@@ -173,9 +172,8 @@ static void wm0010_halt(struct snd_soc_component *component)
break;
}
- spin_lock_irqsave(&wm0010->irq_lock, flags);
- wm0010->state = WM0010_POWER_OFF;
- spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+ scoped_guard(spinlock_irqsave, &wm0010->irq_lock)
+ wm0010->state = WM0010_POWER_OFF;
}
struct wm0010_boot_xfer {
@@ -190,11 +188,9 @@ struct wm0010_boot_xfer {
static void wm0010_mark_boot_failure(struct wm0010_priv *wm0010)
{
enum wm0010_state state;
- unsigned long flags;
- spin_lock_irqsave(&wm0010->irq_lock, flags);
- state = wm0010->state;
- spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+ scoped_guard(spinlock_irqsave, &wm0010->irq_lock)
+ state = wm0010->state;
dev_err(wm0010->dev, "Failed to transition from `%s' state to `%s' state\n",
wm0010_state_to_str(state), wm0010_state_to_str(state + 1));
@@ -337,7 +333,6 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp
struct wm0010_boot_xfer *xfer;
int ret;
DECLARE_COMPLETION_ONSTACK(done);
- const struct firmware *fw;
const struct dfw_binrec *rec;
const struct dfw_inforec *inforec;
u64 *img;
@@ -346,6 +341,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp
INIT_LIST_HEAD(&xfer_list);
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, name, component->dev);
if (ret != 0) {
dev_err(component->dev, "Failed to request application(%s): %d\n",
@@ -364,16 +360,14 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp
/* First record should be INFO */
if (rec->command != DFW_CMD_INFO) {
dev_err(component->dev, "First record not INFO\r\n");
- ret = -EINVAL;
- goto abort;
+ return -EINVAL;
}
if (inforec->info_version != INFO_VERSION) {
dev_err(component->dev,
"Unsupported version (%02d) of INFO record\r\n",
inforec->info_version);
- ret = -EINVAL;
- goto abort;
+ return -EINVAL;
}
dev_dbg(component->dev, "Version v%02d INFO record found\r\n",
@@ -382,8 +376,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp
/* Check it's a DSP file */
if (dsp != DEVICE_ID_WM0010) {
dev_err(component->dev, "Not a WM0010 firmware file.\r\n");
- ret = -EINVAL;
- goto abort;
+ return -EINVAL;
}
/* Skip the info record as we don't need to send it */
@@ -408,14 +401,14 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp
out = kzalloc(len, GFP_KERNEL | GFP_DMA);
if (!out) {
ret = -ENOMEM;
- goto abort1;
+ goto abort;
}
xfer->t.rx_buf = out;
img = kzalloc(len, GFP_KERNEL | GFP_DMA);
if (!img) {
ret = -ENOMEM;
- goto abort1;
+ goto abort;
}
xfer->t.tx_buf = img;
@@ -453,13 +446,13 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp
ret = spi_async(spi, &xfer->m);
if (ret != 0) {
dev_err(component->dev, "Write failed: %d\n", ret);
- goto abort1;
+ goto abort;
}
if (wm0010->boot_failed) {
dev_dbg(component->dev, "Boot fail!\n");
ret = -EINVAL;
- goto abort1;
+ goto abort;
}
}
@@ -467,7 +460,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp
ret = 0;
-abort1:
+abort:
while (!list_empty(&xfer_list)) {
xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer,
list);
@@ -477,8 +470,6 @@ abort1:
kfree(xfer);
}
-abort:
- release_firmware(fw);
return ret;
}
@@ -486,14 +477,12 @@ static int wm0010_stage2_load(struct snd_soc_component *component)
{
struct spi_device *spi = to_spi_device(component->dev);
struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
- const struct firmware *fw;
struct spi_message m;
struct spi_transfer t;
- u32 *img;
- u8 *out;
int i;
int ret = 0;
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, "wm0010_stage2.bin", component->dev);
if (ret != 0) {
dev_err(component->dev, "Failed to request stage2 loader: %d\n",
@@ -504,17 +493,15 @@ static int wm0010_stage2_load(struct snd_soc_component *component)
dev_dbg(component->dev, "Downloading %zu byte stage 2 loader\n", fw->size);
/* Copy to local buffer first as vmalloc causes problems for dma */
- img = kmemdup(&fw->data[0], fw->size, GFP_KERNEL | GFP_DMA);
- if (!img) {
- ret = -ENOMEM;
- goto abort2;
- }
+ u32 *img __free(kfree) =
+ kmemdup(&fw->data[0], fw->size, GFP_KERNEL | GFP_DMA);
+ if (!img)
+ return -ENOMEM;
- out = kzalloc(fw->size, GFP_KERNEL | GFP_DMA);
- if (!out) {
- ret = -ENOMEM;
- goto abort1;
- }
+ u8 *out __free(kfree) =
+ kzalloc(fw->size, GFP_KERNEL | GFP_DMA);
+ if (!out)
+ return -ENOMEM;
spi_message_init(&m);
memset(&t, 0, sizeof(t));
@@ -531,7 +518,7 @@ static int wm0010_stage2_load(struct snd_soc_component *component)
ret = spi_sync(spi, &m);
if (ret != 0) {
dev_err(component->dev, "Initial download failed: %d\n", ret);
- goto abort;
+ return ret;
}
/* Look for errors from the boot ROM */
@@ -540,18 +527,11 @@ static int wm0010_stage2_load(struct snd_soc_component *component)
dev_err(component->dev, "Boot ROM error: %x in %d\n",
out[i], i);
wm0010_mark_boot_failure(wm0010);
- ret = -EBUSY;
- goto abort;
+ return -EBUSY;
}
}
-abort:
- kfree(out);
-abort1:
- kfree(img);
-abort2:
- release_firmware(fw);
- return ret;
+ return 0;
}
static int wm0010_boot(struct snd_soc_component *component)
@@ -734,9 +714,8 @@ static int wm0010_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_PREPARE) {
- mutex_lock(&wm0010->lock);
- wm0010_halt(component);
- mutex_unlock(&wm0010->lock);
+ scoped_guard(mutex, &wm0010->lock)
+ wm0010_halt(component);
}
break;
case SND_SOC_BIAS_OFF:
@@ -832,9 +811,8 @@ static irqreturn_t wm0010_irq(int irq, void *data)
case WM0010_OUT_OF_RESET:
case WM0010_BOOTROM:
case WM0010_STAGE2:
- spin_lock(&wm0010->irq_lock);
- complete(&wm0010->boot_completion);
- spin_unlock(&wm0010->irq_lock);
+ scoped_guard(spinlock, &wm0010->irq_lock)
+ complete(&wm0010->boot_completion);
return IRQ_HANDLED;
default:
return IRQ_NONE;
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 9b68ee69324b..41c8cfb346c6 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/firmware.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pm.h>
@@ -612,20 +613,15 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
unsigned int anc_active = ucontrol->value.integer.value[0];
- int ret;
if (anc_active > 1)
return -EINVAL;
- mutex_lock(&wm2000->lock);
+ guard(mutex)(&wm2000->lock);
wm2000->anc_active = anc_active;
- ret = wm2000_anc_set_mode(wm2000);
-
- mutex_unlock(&wm2000->lock);
-
- return ret;
+ return wm2000_anc_set_mode(wm2000);
}
static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
@@ -645,20 +641,15 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
unsigned int val = ucontrol->value.integer.value[0];
- int ret;
if (val > 1)
return -EINVAL;
- mutex_lock(&wm2000->lock);
+ guard(mutex)(&wm2000->lock);
wm2000->spk_ena = val;
- ret = wm2000_anc_set_mode(wm2000);
-
- mutex_unlock(&wm2000->lock);
-
- return ret;
+ return wm2000_anc_set_mode(wm2000);
}
static const struct snd_kcontrol_new wm2000_controls[] = {
@@ -676,9 +667,8 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
- int ret;
- mutex_lock(&wm2000->lock);
+ guard(mutex)(&wm2000->lock);
if (SND_SOC_DAPM_EVENT_ON(event))
wm2000->anc_eng_ena = 1;
@@ -686,11 +676,7 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
if (SND_SOC_DAPM_EVENT_OFF(event))
wm2000->anc_eng_ena = 0;
- ret = wm2000_anc_set_mode(wm2000);
-
- mutex_unlock(&wm2000->lock);
-
- return ret;
+ return wm2000_anc_set_mode(wm2000);
}
static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = {
@@ -810,7 +796,7 @@ static int wm2000_i2c_probe(struct i2c_client *i2c)
struct wm2000_priv *wm2000;
struct wm2000_platform_data *pdata;
const char *filename;
- const struct firmware *fw = NULL;
+ const struct firmware *fw __free(firmware) = NULL;
int ret, i;
unsigned int reg;
u16 id;
@@ -828,7 +814,7 @@ static int wm2000_i2c_probe(struct i2c_client *i2c)
ret = PTR_ERR(wm2000->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
ret);
- goto out;
+ return ret;
}
for (i = 0; i < WM2000_NUM_SUPPLIES; i++)
@@ -922,9 +908,6 @@ static int wm2000_i2c_probe(struct i2c_client *i2c)
err_supplies:
regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
-
-out:
- release_firmware(fw);
return ret;
}
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index ba8ce2e6e615..bc78b553b6cb 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -2461,7 +2461,15 @@ static int wm2200_runtime_resume(struct device *dev)
}
regcache_cache_only(wm2200->regmap, false);
- regcache_sync(wm2200->regmap);
+ ret = regcache_sync(wm2200->regmap);
+ if (ret) {
+ regcache_cache_only(wm2200->regmap, true);
+ regcache_mark_dirty(wm2200->regmap);
+ gpiod_set_value_cansleep(wm2200->ldo_ena, 0);
+ regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
+ wm2200->core_supplies);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index bd94fa53c362..2fe937a93026 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -2659,7 +2659,15 @@ static int wm5100_runtime_resume(struct device *dev)
}
regcache_cache_only(wm5100->regmap, false);
- regcache_sync(wm5100->regmap);
+ ret = regcache_sync(wm5100->regmap);
+ if (ret) {
+ regcache_cache_only(wm5100->regmap, true);
+ regcache_mark_dirty(wm5100->regmap);
+ gpiod_set_value_cansleep(wm5100->ldo_ena, 0);
+ regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
+ wm5100->core_supplies);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index b4d4137c05b4..74b775b95bfd 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -7,6 +7,7 @@
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -667,10 +668,9 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
- mutex_lock(&arizona->dac_comp_lock);
+ guard(mutex)(&arizona->dac_comp_lock);
put_unaligned_be16(arizona->dac_comp_coeff,
ucontrol->value.bytes.data);
- mutex_unlock(&arizona->dac_comp_lock);
return 0;
}
@@ -681,16 +681,14 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
uint16_t dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data);
- int ret = 0;
- mutex_lock(&arizona->dac_comp_lock);
+ guard(mutex)(&arizona->dac_comp_lock);
if (arizona->dac_comp_coeff != dac_comp_coeff) {
arizona->dac_comp_coeff = dac_comp_coeff;
- ret = 1;
+ return 1;
}
- mutex_unlock(&arizona->dac_comp_lock);
- return ret;
+ return 0;
}
static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
@@ -699,9 +697,8 @@ static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
- mutex_lock(&arizona->dac_comp_lock);
+ guard(mutex)(&arizona->dac_comp_lock);
ucontrol->value.integer.value[0] = arizona->dac_comp_enabled;
- mutex_unlock(&arizona->dac_comp_lock);
return 0;
}
@@ -712,19 +709,17 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
- int ret = 0;
if (ucontrol->value.integer.value[0] > mc->max)
return -EINVAL;
- mutex_lock(&arizona->dac_comp_lock);
+ guard(mutex)(&arizona->dac_comp_lock);
if (arizona->dac_comp_enabled != ucontrol->value.integer.value[0]) {
arizona->dac_comp_enabled = ucontrol->value.integer.value[0];
- ret = 1;
+ return 1;
}
- mutex_unlock(&arizona->dac_comp_lock);
- return ret;
+ return 0;
}
static const char * const wm5102_osr_text[] = {
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index a2f0e2f5c407..ce87280d590d 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -10,6 +10,7 @@
* Based on wm8753.c by Liam Girdwood
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -110,22 +111,20 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
unsigned int deemph = ucontrol->value.integer.value[0];
- int ret = 0;
if (deemph > 1)
return -EINVAL;
- mutex_lock(&wm8731->lock);
+ guard(mutex)(&wm8731->lock);
if (wm8731->deemph != deemph) {
wm8731->deemph = deemph;
wm8731_set_deemph(component);
- ret = 1;
+ return 1;
}
- mutex_unlock(&wm8731->lock);
- return ret;
+ return 0;
}
static const DECLARE_TLV_DB_SCALE(in_tlv, -3450, 150, 0);
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 320d7737699d..156e1e24a388 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
+#include <linux/cleanup.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/gpio/driver.h>
@@ -458,22 +459,20 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
unsigned int deemph = ucontrol->value.integer.value[0];
- int ret = 0;
if (deemph > 1)
return -EINVAL;
- mutex_lock(&wm8903->lock);
+ guard(mutex)(&wm8903->lock);
if (wm8903->deemph != deemph) {
wm8903->deemph = deemph;
wm8903_set_deemph(component);
- ret = 1;
+ return 1;
}
- mutex_unlock(&wm8903->lock);
- return ret;
+ return 0;
}
/* ALSA can only do steps of .01dB */
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index e631ec072249..229252363188 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -333,7 +333,7 @@ static const struct snd_soc_dapm_route wm8940_dapm_routes[] = {
{"ADC", NULL, "Boost Mixer"},
};
-#define wm8940_reset(c) snd_soc_component_write(c, WM8940_SOFTRESET, 0);
+#define wm8940_reset(c) snd_soc_component_write(c, WM8940_SOFTRESET, 0)
static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
index 8ff0882732e7..f75a6dc9d2bb 100644
--- a/sound/soc/codecs/wm8958-dsp2.c
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -7,6 +7,7 @@
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -864,9 +865,8 @@ static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context)
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
if (fw && (wm8958_dsp2_fw(component, "ENH_EQ", fw, true) == 0)) {
- mutex_lock(&wm8994->fw_lock);
+ guard(mutex)(&wm8994->fw_lock);
wm8994->enh_eq = fw;
- mutex_unlock(&wm8994->fw_lock);
}
}
@@ -876,9 +876,8 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
if (fw && (wm8958_dsp2_fw(component, "MBC+VSS", fw, true) == 0)) {
- mutex_lock(&wm8994->fw_lock);
+ guard(mutex)(&wm8994->fw_lock);
wm8994->mbc_vss = fw;
- mutex_unlock(&wm8994->fw_lock);
}
}
@@ -888,9 +887,8 @@ static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
if (fw && (wm8958_dsp2_fw(component, "MBC", fw, true) == 0)) {
- mutex_lock(&wm8994->fw_lock);
+ guard(mutex)(&wm8994->fw_lock);
wm8994->mbc = fw;
- mutex_unlock(&wm8994->fw_lock);
}
}
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index de18b1f85a32..8a9598161b35 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pm.h>
@@ -1564,11 +1565,10 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
int old = wm8962->dsp2_ena;
- int ret = 0;
int dsp2_running = snd_soc_component_read(component, WM8962_DSP2_POWER_MANAGEMENT) &
WM8962_DSP2_ENA;
- mutex_lock(&wm8962->dsp2_ena_lock);
+ guard(mutex)(&wm8962->dsp2_ena_lock);
if (ucontrol->value.integer.value[0])
wm8962->dsp2_ena |= 1 << shift;
@@ -1576,9 +1576,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
wm8962->dsp2_ena &= ~(1 << shift);
if (wm8962->dsp2_ena == old)
- goto out;
-
- ret = 1;
+ return 0;
if (dsp2_running) {
if (wm8962->dsp2_ena)
@@ -1587,10 +1585,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
wm8962_dsp2_stop(component);
}
-out:
- mutex_unlock(&wm8962->dsp2_ena_lock);
-
- return ret;
+ return 1;
}
/* The VU bits for the headphones are in a different register to the mute
@@ -3937,7 +3932,9 @@ static int wm8962_runtime_resume(struct device *dev)
WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
0);
- regcache_sync(wm8962->regmap);
+ ret = regcache_sync(wm8962->regmap);
+ if (ret)
+ goto cache_sync_err;
regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA,
@@ -3955,6 +3952,11 @@ static int wm8962_runtime_resume(struct device *dev)
return 0;
+cache_sync_err:
+ regcache_cache_only(wm8962->regmap, true);
+ regcache_mark_dirty(wm8962->regmap);
+ regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies),
+ wm8962->supplies);
disable_clock:
clk_disable_unprepare(wm8962->pdata.mclk);
return ret;
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 1d64c7c42ed1..8bf58a6a8af7 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -7,6 +7,7 @@
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -766,7 +767,7 @@ static void active_reference(struct snd_soc_component *component)
{
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
- mutex_lock(&wm8994->accdet_lock);
+ guard(mutex)(&wm8994->accdet_lock);
wm8994->active_refcount++;
@@ -775,8 +776,6 @@ static void active_reference(struct snd_soc_component *component)
/* If we're using jack detection go into audio mode */
wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_AUDIO);
-
- mutex_unlock(&wm8994->accdet_lock);
}
static void active_dereference(struct snd_soc_component *component)
@@ -784,7 +783,7 @@ static void active_dereference(struct snd_soc_component *component)
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
u16 mode;
- mutex_lock(&wm8994->accdet_lock);
+ guard(mutex)(&wm8994->accdet_lock);
wm8994->active_refcount--;
@@ -800,8 +799,6 @@ static void active_dereference(struct snd_soc_component *component)
wm1811_jackdet_set_mode(component, mode);
}
-
- mutex_unlock(&wm8994->accdet_lock);
}
static int clk_sys_event(struct snd_soc_dapm_widget *w,
@@ -3704,7 +3701,7 @@ static void wm8958_open_circuit_work(struct work_struct *work)
open_circuit_work.work);
struct device *dev = wm8994->wm8994->dev;
- mutex_lock(&wm8994->accdet_lock);
+ guard(mutex)(&wm8994->accdet_lock);
wm1811_micd_stop(wm8994->hubs.component);
@@ -3718,8 +3715,6 @@ static void wm8958_open_circuit_work(struct work_struct *work)
snd_soc_jack_report(wm8994->micdet[0].jack, 0,
wm8994->btn_mask |
SND_JACK_HEADSET);
-
- mutex_unlock(&wm8994->accdet_lock);
}
static void wm8958_mic_id(void *data, u16 status)
@@ -3777,7 +3772,7 @@ static void wm1811_mic_work(struct work_struct *work)
struct snd_soc_component *component = wm8994->hubs.component;
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
- pm_runtime_get_sync(component->dev);
+ guard(pm_runtime_active)(component->dev);
/* If required for an external cap force MICBIAS on */
if (control->pdata.jd_ext_cap) {
@@ -3785,7 +3780,7 @@ static void wm1811_mic_work(struct work_struct *work)
snd_soc_dapm_sync(dapm);
}
- mutex_lock(&wm8994->accdet_lock);
+ guard(mutex)(&wm8994->accdet_lock);
dev_dbg(component->dev, "Starting mic detection\n");
@@ -3803,10 +3798,6 @@ static void wm1811_mic_work(struct work_struct *work)
snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1,
WM8958_MICD_ENA, WM8958_MICD_ENA);
}
-
- mutex_unlock(&wm8994->accdet_lock);
-
- pm_runtime_put(component->dev);
}
static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
@@ -4026,15 +4017,10 @@ static void wm8958_mic_work(struct work_struct *work)
mic_complete_work.work);
struct snd_soc_component *component = wm8994->hubs.component;
- pm_runtime_get_sync(component->dev);
-
- mutex_lock(&wm8994->accdet_lock);
+ guard(pm_runtime_active)(component->dev);
+ guard(mutex)(&wm8994->accdet_lock);
wm8994->mic_id_cb(wm8994->mic_id_cb_data, wm8994->mic_status);
-
- mutex_unlock(&wm8994->accdet_lock);
-
- pm_runtime_put(component->dev);
}
static irqreturn_t wm8958_mic_irq(int irq, void *data)
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 83cd42fa0c28..3105b2e0556f 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -6,6 +6,7 @@
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
*/
+#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mfd/wm97xx.h>
@@ -229,7 +230,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
shift = mc->shift & 0xff;
mask = 1 << shift;
- mutex_lock(&wm9712->lock);
+ guard(mutex)(&wm9712->lock);
old = wm9712->hp_mixer[mixer];
if (ucontrol->value.integer.value[0])
wm9712->hp_mixer[mixer] |= mask;
@@ -251,8 +252,6 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
&update);
}
- mutex_unlock(&wm9712->lock);
-
return change;
}
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index b3bbecf074ee..3ba7ca3c1770 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -11,6 +11,7 @@
* o Support for DAPM
*/
+#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mfd/wm97xx.h>
@@ -238,7 +239,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
shift = mc->shift & 0xff;
mask = (1 << shift);
- mutex_lock(&wm9713->lock);
+ guard(mutex)(&wm9713->lock);
old = wm9713->hp_mixer[mixer];
if (ucontrol->value.integer.value[0])
wm9713->hp_mixer[mixer] |= mask;
@@ -260,8 +261,6 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
&update);
}
- mutex_unlock(&wm9713->lock);
-
return change;
}
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index baa75e7ff53b..90c24c4b318e 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -348,7 +348,6 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
- int ret = 1;
if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw)
return 0;
@@ -356,16 +355,14 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW)
return -EINVAL;
- mutex_lock(&dsp[e->shift_l].cs_dsp.pwr_lock);
+ guard(mutex)(&dsp[e->shift_l].cs_dsp.pwr_lock);
if (dsp[e->shift_l].cs_dsp.booted || !list_empty(&dsp[e->shift_l].compr_list))
- ret = -EBUSY;
+ return -EBUSY;
else
dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0];
- mutex_unlock(&dsp[e->shift_l].cs_dsp.pwr_lock);
-
- return ret;
+ return 1;
}
EXPORT_SYMBOL_GPL(wm_adsp_fw_put);
@@ -450,15 +447,13 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
if (val == 0)
return 0; /* 0 means no event */
- mutex_lock(&cs_ctl->dsp->pwr_lock);
+ guard(mutex)(&cs_ctl->dsp->pwr_lock);
if (cs_ctl->enabled)
ret = cs_dsp_coeff_write_acked_control(cs_ctl, val);
else
ret = -EPERM;
- mutex_unlock(&cs_ctl->dsp->pwr_lock);
-
if (ret < 0)
return ret;
@@ -486,15 +481,13 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
int ret = 0;
- mutex_lock(&cs_ctl->dsp->pwr_lock);
+ guard(mutex)(&cs_ctl->dsp->pwr_lock);
ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, cs_ctl->cache, size);
if (!ret && copy_to_user(bytes, cs_ctl->cache, size))
ret = -EFAULT;
- mutex_unlock(&cs_ctl->dsp->pwr_lock);
-
return ret;
}
@@ -694,10 +687,9 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
struct cs_dsp_coeff_ctl *cs_ctl;
int ret;
- mutex_lock(&dsp->cs_dsp.pwr_lock);
+ guard(mutex)(&dsp->cs_dsp.pwr_lock);
cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg);
ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len);
- mutex_unlock(&dsp->cs_dsp.pwr_lock);
if (ret < 0)
return ret;
@@ -709,14 +701,10 @@ EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
unsigned int alg, void *buf, size_t len)
{
- int ret;
+ guard(mutex)(&dsp->cs_dsp.pwr_lock);
- mutex_lock(&dsp->cs_dsp.pwr_lock);
- ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg),
+ return cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg),
0, buf, len);
- mutex_unlock(&dsp->cs_dsp.pwr_lock);
-
- return ret;
}
EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
@@ -1270,38 +1258,32 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
{
struct wm_adsp_compr *compr, *tmp;
struct snd_soc_pcm_runtime *rtd = stream->private_data;
- int ret = 0;
- mutex_lock(&dsp->cs_dsp.pwr_lock);
+ guard(mutex)(&dsp->cs_dsp.pwr_lock);
if (wm_adsp_fw[dsp->fw].num_caps == 0) {
adsp_err(dsp, "%s: Firmware does not support compressed API\n",
snd_soc_rtd_to_codec(rtd, 0)->name);
- ret = -ENXIO;
- goto out;
+ return -ENXIO;
}
if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
adsp_err(dsp, "%s: Firmware does not support stream direction\n",
snd_soc_rtd_to_codec(rtd, 0)->name);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
list_for_each_entry(tmp, &dsp->compr_list, list) {
if (!strcmp(tmp->name, snd_soc_rtd_to_codec(rtd, 0)->name)) {
adsp_err(dsp, "%s: Only a single stream supported per dai\n",
snd_soc_rtd_to_codec(rtd, 0)->name);
- ret = -EBUSY;
- goto out;
+ return -EBUSY;
}
}
compr = kzalloc_obj(*compr);
- if (!compr) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!compr)
+ return -ENOMEM;
compr->dsp = dsp;
compr->stream = stream;
@@ -1311,10 +1293,7 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
stream->runtime->private_data = compr;
-out:
- mutex_unlock(&dsp->cs_dsp.pwr_lock);
-
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_open);
@@ -1324,7 +1303,7 @@ int wm_adsp_compr_free(struct snd_soc_component *component,
struct wm_adsp_compr *compr = stream->runtime->private_data;
struct wm_adsp *dsp = compr->dsp;
- mutex_lock(&dsp->cs_dsp.pwr_lock);
+ guard(mutex)(&dsp->cs_dsp.pwr_lock);
wm_adsp_compr_detach(compr);
list_del(&compr->list);
@@ -1332,8 +1311,6 @@ int wm_adsp_compr_free(struct snd_soc_component *component,
kfree(compr->raw_buf);
kfree(compr);
- mutex_unlock(&dsp->cs_dsp.pwr_lock);
-
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_free);
@@ -1741,7 +1718,7 @@ int wm_adsp_compr_trigger(struct snd_soc_component *component,
compr_dbg(compr, "Trigger: %d\n", cmd);
- mutex_lock(&dsp->cs_dsp.pwr_lock);
+ guard(mutex)(&dsp->cs_dsp.pwr_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -1777,8 +1754,6 @@ int wm_adsp_compr_trigger(struct snd_soc_component *component,
break;
}
- mutex_unlock(&dsp->cs_dsp.pwr_lock);
-
return ret;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger);
@@ -1907,21 +1882,20 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component,
compr_dbg(compr, "Pointer request\n");
- mutex_lock(&dsp->cs_dsp.pwr_lock);
+ guard(mutex)(&dsp->cs_dsp.pwr_lock);
buf = compr->buf;
if (dsp->fatal_error || !buf || buf->error) {
snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
- ret = -EIO;
- goto out;
+ return -EIO;
}
if (buf->avail < wm_adsp_compr_frag_words(compr)) {
ret = wm_adsp_buffer_update_avail(buf);
if (ret < 0) {
compr_err(compr, "Error reading avail: %d\n", ret);
- goto out;
+ return ret;
}
/*
@@ -1934,14 +1908,14 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component,
if (buf->error)
snd_compr_stop_error(stream,
SNDRV_PCM_STATE_XRUN);
- goto out;
+ return ret;
}
ret = wm_adsp_buffer_reenable_irq(buf);
if (ret < 0) {
compr_err(compr, "Failed to re-enable buffer IRQ: %d\n",
ret);
- goto out;
+ return ret;
}
}
}
@@ -1950,9 +1924,6 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component,
tstamp->copied_total += buf->avail * CS_DSP_DATA_WORD_SIZE;
tstamp->sampling_rate = compr->sample_rate;
-out:
- mutex_unlock(&dsp->cs_dsp.pwr_lock);
-
return ret;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
@@ -2063,15 +2034,13 @@ int wm_adsp_compr_copy(struct snd_soc_component *component,
struct wm_adsp *dsp = compr->dsp;
int ret;
- mutex_lock(&dsp->cs_dsp.pwr_lock);
+ guard(mutex)(&dsp->cs_dsp.pwr_lock);
if (stream->direction == SND_COMPRESS_CAPTURE)
ret = wm_adsp_compr_read(compr, buf, count);
else
ret = -ENOTSUPP;
- mutex_unlock(&dsp->cs_dsp.pwr_lock);
-
return ret;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 5174614c3e83..47ac3e4985a5 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -1178,7 +1178,13 @@ static int wsa881x_runtime_resume(struct device *dev)
}
regcache_cache_only(regmap, false);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret) {
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+ gpiod_direction_output(wsa881x->sd_n, 1);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
index 468d2b38a22a..442cf9f3eaac 100644
--- a/sound/soc/codecs/wsa883x.c
+++ b/sound/soc/codecs/wsa883x.c
@@ -4,6 +4,7 @@
*/
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/hwmon.h>
@@ -1237,9 +1238,8 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- mutex_lock(&wsa883x->sp_lock);
- wsa883x->pa_on = true;
- mutex_unlock(&wsa883x->sp_lock);
+ scoped_guard(mutex, &wsa883x->sp_lock)
+ wsa883x->pa_on = true;
switch (wsa883x->dev_mode) {
case RECEIVER:
@@ -1290,9 +1290,8 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w,
WSA883X_GLOBAL_PA_EN_MASK, 0);
snd_soc_component_write_field(component, WSA883X_PDM_WD_CTL,
WSA883X_PDM_EN_MASK, 0);
- mutex_lock(&wsa883x->sp_lock);
- wsa883x->pa_on = false;
- mutex_unlock(&wsa883x->sp_lock);
+ scoped_guard(mutex, &wsa883x->sp_lock)
+ wsa883x->pa_on = false;
break;
}
return 0;
@@ -1696,9 +1695,15 @@ static int wsa883x_runtime_suspend(struct device *dev)
static int wsa883x_runtime_resume(struct device *dev)
{
struct regmap *regmap = dev_get_regmap(dev, NULL);
+ int ret;
regcache_cache_only(regmap, false);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret) {
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c
index 6c6b497657d0..a367c94bfb4d 100644
--- a/sound/soc/codecs/wsa884x.c
+++ b/sound/soc/codecs/wsa884x.c
@@ -1701,9 +1701,8 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- mutex_lock(&wsa884x->sp_lock);
- wsa884x->pa_on = true;
- mutex_unlock(&wsa884x->sp_lock);
+ scoped_guard(mutex, &wsa884x->sp_lock)
+ wsa884x->pa_on = true;
wsa884x_spkr_post_pmu(component, wsa884x);
@@ -1717,9 +1716,8 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w,
WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK,
0x0);
- mutex_lock(&wsa884x->sp_lock);
- wsa884x->pa_on = false;
- mutex_unlock(&wsa884x->sp_lock);
+ scoped_guard(mutex, &wsa884x->sp_lock)
+ wsa884x->pa_on = false;
break;
}
@@ -2147,9 +2145,15 @@ static int wsa884x_runtime_suspend(struct device *dev)
static int wsa884x_runtime_resume(struct device *dev)
{
struct regmap *regmap = dev_get_regmap(dev, NULL);
+ int ret;
regcache_cache_only(regmap, false);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret) {
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wsa885x.c b/sound/soc/codecs/wsa885x.c
new file mode 100644
index 000000000000..1faa8541a872
--- /dev/null
+++ b/sound/soc/codecs/wsa885x.c
@@ -0,0 +1,1533 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+/* WSA885X codec driver */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+/* Control Registers - Audio Processing */
+#define WSA885X_SMP_AMP_CTRL_STEREO_STEREO_SMP_AMP_CTRL_I2S 0x0000
+#define WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK 0x0004
+#define WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX 0x0140
+#define WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID 0x0208
+#define WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX 0x0240
+#define WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER 0x0340
+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0 0x4405
+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1 0x4406
+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB 0x4409
+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB 0x6409
+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB 0x440a
+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB 0x640a
+#define WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS 0x0a04
+#define WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS 0x0a40
+#define WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE 0x0b10
+#define WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX 0x0e40
+
+/* Analog Top Registers - Power and Clock Control */
+#define WSA885X_ANA_TOP_PON_CKSK_CTL_0 0x800d
+#define WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG 0x8024
+#define WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG 0x8025
+#define WSA885X_ANA_TOP_BG_TVP_OVRD_CTL 0x8034
+
+/* Analog PLL Registers */
+#define WSA885X_ANA_PLL_DIV_CTL_0 0x8090
+#define WSA885X_ANA_PLL_DIV_CTL_1 0x8091
+#define WSA885X_ANA_TOP_PLL_VCO_CTL 0x8092
+#define WSA885X_ANA_TOP_PLL_LOOPFILT_0 0x8093
+#define WSA885X_ANA_TOP_PLL_OVRD_CTL 0x8098
+#define WSA885X_ANA_TOP_PLL_STATUS_0 0x809a
+#define WSA885X_ANA_TOP_PLL_STATUS_1 0x809b
+
+/* Analog Boost Control Registers */
+#define WSA885X_ANA_TOP_BOOST_STB_CTRL2 0x805b
+#define WSA885X_ANA_TOP_BOOST_STB_CTRL3 0x805c
+#define WSA885X_ANA_TOP_BOOST_BYP_CTRL2 0x805e
+#define WSA885X_ANA_TOP_BOOST_BYP_CTRL3 0x805f
+#define WSA885X_ANA_TOP_BOOST_MISC 0x8063
+#define WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2 0x8065
+#define WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4 0x8067
+
+/* Analog IV Sense ADC Registers */
+#define WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2 0x80ca
+#define WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3 0x80cb
+#define WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL 0x80cc
+#define WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2 0x80d0
+
+/* Analog Speaker Power Stage Registers */
+#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3 0x8108
+#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3 0x810b
+#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3 0x810e
+#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3 0x8111
+#define WSA885X_ANA_TOP_SPK_TOP_SPARE3 0x813c
+#define WSA885X_SPK_TOP_LF_CH1_CTRL11 0x811c
+#define WSA885X_SPK_TOP_LF_CH1_TUNE1 0x811d
+#define WSA885X_SPK_TOP_LF_CH2_TUNE1 0x8129
+#define WSA885X_SPK_TOP_LF_CH1_CTRL9 0x811a
+#define WSA885X_SPK_TOP_LF_CH2_CTRL9 0x8126
+#define WSA885X_SPK_TOP_LF_CH2_CTRL11 0x8128
+#define WSA885X_SPK_TOP_COMMON_CTRL2 0x8102
+#define WSA885X_SPK_TOP_COMMON_TUNE1 0x8103
+#define WSA885X_IVSENSE_VSNS_ISNS_CTL_CH1 0x80ba
+#define WSA885X_DIG_CTRL0_TOP_CLK_CFG 0x8418
+#define WSA885X_DIG_CTRL0_SDCA_COMMIT 0x8419
+#define WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE 0x841a
+#define WSA885X_DIG_CTRL0_SYS_CLK_SEL 0x841b
+#define WSA885X_DIG_CTRL0_CDC_CLK_CTL 0x841c
+#define WSA885X_DIG_CTRL0_PA_FSM_CTL 0x8420
+#define WSA885X_DIG_CTRL0_POWER_FSM_CTL0 0x8423
+#define WSA885X_DIG_CTRL0_POWER_FSM_CTL1 0x8424
+#define WSA885X_DIG_CTRL0_PA0_FSM_CTL1 0x842b
+#define WSA885X_DIG_CTRL0_PA1_FSM_CTL1 0x8435
+#define WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL 0x8458
+#define WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL 0x8470
+#define WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1 0x84b4
+#define WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1 0x84b7
+#define WSA885X_DIG_CTRL0_PCM_DATA_WD0_CTL1 0x84A0
+#define WSA885X_DIG_CTRL0_PCM_DATA_WD1_CTL1 0x84A4
+
+/* Digital Control 1 Registers - I2S/TDM Interface */
+#define WSA885X_DIG_CTRL1_I2S_CTL0 0x85A0
+#define WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX 0x85A2
+#define WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX 0x85A3
+#define WSA885X_DIG_CTRL1_I2S_TDM_CTL0 0x85A7
+#define WSA885X_DIG_CTRL1_I2S_TDM_CTL1 0x85A9
+#define WSA885X_DIG_CTRL1_I2S_TDM_CH_RX 0x85AA
+#define WSA885X_DIG_CTRL1_I2S_TDM_CH_TX 0x85AB
+#define WSA885X_DIG_CTRL1_I2S_RESET_CTL 0x85AE
+
+/* CDC RX Path Registers - Audio Data Path */
+#define WSA885X_CDC_RX0_RX_PATH_CFG0 0x8601
+#define WSA885X_CDC_RX0_RX_PATH_CFG1 0x8602
+#define WSA885X_CDC_RX0_RX_PATH_CTL 0x8606
+#define WSA885X_RX0_RX_PATH_DSMDEM_CTL 0x8613
+#define WSA885X_CDC_RX1_RX_PATH_CFG0 0x8621
+#define WSA885X_CDC_RX1_RX_PATH_CFG1 0x8622
+#define WSA885X_CDC_RX1_RX_PATH_CTL 0x8626
+#define WSA885X_RX1_RX_PATH_DSMDEM_CTL 0x8633
+
+/* CDC Compander Registers - Dynamic Range Control */
+#define WSA885X_CDC_COMPANDER0_CTL0 0x8640
+#define WSA885X_CDC_COMPANDER0_CTL7 0x8647
+#define WSA885X_CDC_COMPANDER1_CTL0 0x8660
+#define WSA885X_CDC_COMPANDER1_CTL7 0x8667
+
+/* CDC Speaker Protection Registers - IV Sense */
+#define WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL 0x86A1
+#define WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL 0x86B1
+#define WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL 0x86A9
+#define WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL 0x86B9
+
+/* CDC Class-H Registers - Headroom Control */
+#define WSA885X_CDC_CLSH_V1P8_BP_CTL1 0x86CD
+#define WSA885X_CDC_CLSH_V1P8_BP_CTL0 0x86CC
+#define WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0 0x86C7
+#define WSA885X_CDC_CLSH_CLSH_V_HD_PA 0x86C3
+#define WSA885X_CDC_CLSH_V1P8_BP_CTL2 0x86CE
+
+/* Driver Constants */
+#define WSA885X_CLK_RATE_FIXED 73728000
+#define WSA885X_NUM_REGS 0x03
+
+/* Interrupt Registers */
+#define WSA885X_INTR_STATUS0 0x8584
+#define WSA885X_INTR_MASK0 0x8581
+#define WSA885X_INTR_CLEAR0 0x8587
+
+/* Power and PA FSM Control Registers */
+#define WSA885X_PA0_FSM_CTL0 0x842A
+#define WSA885X_PA1_FSM_CTL0 0x8434
+
+/* Digital Control GPIO and Interrupt Registers */
+#define WSA885X_DIG_CTRL1_PIN_CT 0x8510
+#define WSA885X_DIG_CTRL1_SPMI_PAD_GPIO2_CTL 0x8518
+#define WSA885X_DIG_CTRL1_INTR_MODE 0x8580
+
+#define WSA885X_I2S_CTL0_PCM_RATE_MASK GENMASK(4, 1)
+#define WSA885X_I2S_CTL0_ENABLE_MASK BIT(0)
+#define WSA885X_I2S_CTL0_PCM_RATE(v) \
+ FIELD_PREP(WSA885X_I2S_CTL0_PCM_RATE_MASK, (v))
+#define WSA885X_I2S_CTL0_PCM_RATE_8KHZ 0x0
+#define WSA885X_I2S_CTL0_PCM_RATE_16KHZ 0x1
+#define WSA885X_I2S_CTL0_PCM_RATE_32KHZ 0x2
+#define WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ 0x3
+#define WSA885X_I2S_CTL0_PCM_RATE_96_OR_88KHZ 0x4
+#define WSA885X_I2S_CTL0_PCM_RATE_192_OR_176KHZ 0x5
+#define WSA885X_I2S_CTL0_PCM_RATE_384_OR_352KHZ 0x6
+#define WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK GENMASK(2, 0)
+#define WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK GENMASK(6, 4)
+#define WSA885X_I2S_CFG0_TDM_TX_SLOT0(v) \
+ FIELD_PREP_CONST(WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK, (v))
+#define WSA885X_I2S_CFG0_TDM_TX_SLOT1(v) \
+ FIELD_PREP_CONST(WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, (v))
+#define WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK GENMASK(2, 0)
+#define WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK GENMASK(6, 4)
+#define WSA885X_I2S_CFG1_TDM_TX_SLOT2(v) \
+ FIELD_PREP_CONST(WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK, (v))
+#define WSA885X_I2S_CFG1_TDM_TX_SLOT3(v) \
+ FIELD_PREP_CONST(WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK, (v))
+#define WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK BIT(0)
+#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK GENMASK(3, 2)
+#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_2 \
+ FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 0)
+#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_4 \
+ FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 1)
+#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_8 \
+ FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 3)
+#define WSA885X_I2S_TDM_CH_TX_CH0_EN BIT(0)
+#define WSA885X_I2S_TDM_CH_TX_CH1_EN BIT(1)
+#define WSA885X_I2S_TDM_CH_TX_CH2_EN BIT(2)
+#define WSA885X_I2S_TDM_CH_TX_CH3_EN BIT(3)
+#define WSA885X_I2S_TDM_CH_RX_CH0_EN BIT(0)
+#define WSA885X_I2S_TDM_CH_RX_CH3_EN BIT(3)
+#define WSA885X_I2S_RESET_CTL_RESET_MASK BIT(0)
+#define WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK BIT(2)
+#define WSA885X_POWER_FSM_CTL0_CLEAR_ERROR_MASK BIT(3)
+#define WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK BIT(2)
+
+#define WSA885X_I2S_TX_SLOT_ISENSE0 0x1
+#define WSA885X_I2S_TX_SLOT_ISENSE1 0x2
+#define WSA885X_I2S_TX_SLOT_CUR_SENSE0 0x5
+#define WSA885X_I2S_TX_SLOT_CUR_SENSE1 0x6
+
+/* RX Sample Rate Index Values - Audio Playback Path */
+#define WSA885X_RX_RATE_8000HZ 0x00
+#define WSA885X_RX_RATE_16000HZ 0x01
+#define WSA885X_RX_RATE_32000HZ 0x02
+#define WSA885X_RX_RATE_44100HZ 0x03
+#define WSA885X_RX_RATE_48000HZ 0x04
+#define WSA885X_RX_RATE_96000HZ 0x05
+#define WSA885X_RX_RATE_192000HZ 0x06
+#define WSA885X_RX_RATE_384000HZ 0x07
+
+/* VI Sample Rate Index Values - Voltage/Current Sensing Path */
+#define WSA885X_VI_RATE_8000HZ 0x00
+#define WSA885X_VI_RATE_16000HZ 0x01
+#define WSA885X_VI_RATE_44100HZ 0x02
+#define WSA885X_VI_RATE_48000HZ 0x03
+#define WSA885X_VI_RATE_96000HZ 0x04
+#define WSA885X_VI_RATE_22050HZ 0x05
+#define WSA885X_VI_RATE_24000HZ 0x06
+#define WSA885X_VI_RATE_192000HZ 0x07
+#define WSA885X_VI_RATE_384000HZ 0x08
+
+/* Channel Configuration Masks */
+#define WSA885X_CHANNEL_STEREO 0x03
+#define WSA885X_CHANNEL_MONO_LEFT 0x01
+#define WSA885X_CHANNEL_MONO_RIGHT 0x02
+
+#define WSA885X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+
+#define WSA885X_PLL_LOCK_BIT BIT(0)
+
+#define WSA885X_FU21_VOL_STEPS 124
+#define WSA885X_USAGE_MODE_MAX 8
+static const DECLARE_TLV_DB_SCALE(wsa885x_fu21_digital_gain, -8400, 100, 0);
+
+static bool wsa885x_is_valid_rx_slot_mask(u32 mask)
+{
+ return mask == WSA885X_CHANNEL_MONO_LEFT ||
+ mask == WSA885X_CHANNEL_MONO_RIGHT ||
+ mask == WSA885X_CHANNEL_STEREO;
+}
+
+static const char *const wsa885x_supply_name[] = {
+ "vdd-1p8",
+ "vdd-io",
+};
+
+enum {
+ WSA885X_BATT_1S = 1,
+ WSA885X_BATT_2S,
+};
+
+enum {
+ WSA885X_IRQ_INT_SAF2WAR = 0,
+ WSA885X_IRQ_INT_WAR2SAF,
+ WSA885X_IRQ_INT_DISABLE,
+ WSA885X_IRQ_INT_PA0_OCP,
+ WSA885X_IRQ_INT_PA1_OCP,
+ WSA885X_IRQ_INT_CLIP0,
+ WSA885X_IRQ_INT_CLIP1,
+ WSA885X_IRQ_INT_CLK_WD,
+ WSA885X_IRQ_INT_INTR_GPIO1_PIN,
+ WSA885X_IRQ_INT_INTR_GPIO2_PIN,
+ WSA885X_IRQ_INT_UVLO,
+ WSA885X_IRQ_INT_BOP,
+ WSA885X_IRQ_INT_PA0_FSM_ERR,
+ WSA885X_IRQ_INT_PA1_FSM_ERR,
+ WSA885X_IRQ_INT_MAIN_FSM_ERR,
+ WSA885X_IRQ_INT_PCM_DATA0_WD,
+ WSA885X_IRQ_INT_PCM_DATA1_WD,
+ WSA885X_IRQ_INT_PCM_DATA0_DC,
+ WSA885X_IRQ_INT_PCM_DATA1_DC,
+ WSA885X_IRQ_INT_PLL_UNLOCKED,
+ WSA885X_IRQ_INT_PROT_MODE_CHANGE,
+ WSA885X_IRQ_INT_PB_CLOCK_VALID,
+ WSA885X_IRQ_INT_SENSE_CLOCK_VALID,
+ WSA885X_IRQ_MAX,
+};
+
+struct wsa885x_priv {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct device *dev;
+ struct snd_soc_component *component;
+ struct gpio_desc *sd_n;
+ struct reset_control *sd_reset;
+ u32 usage_mode;
+ u32 rx_slot_mask;
+ u32 batt_conf;
+ int stereo_vol_db;
+ struct mutex state_lock; /* protects mutable control state */
+};
+
+struct wsa885x_reg_update {
+ unsigned int reg;
+ unsigned int mask;
+ unsigned int val;
+};
+
+static const struct regmap_range_cfg wsa885x_regmap_ranges[] = {
+ {
+ .range_min = 0,
+ .range_max = 0x88ff,
+ .selector_reg = 0x0,
+ .selector_mask = 0xFF,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 0x100,
+ },
+};
+
+static const struct reg_default wsa885x_codec_reg_defaults[] = {
+ {WSA885X_SMP_AMP_CTRL_STEREO_STEREO_SMP_AMP_CTRL_I2S, 0x00},
+ {WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX, 0x01},
+ {WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK, 0x00},
+ {WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE, 0x00},
+ {WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID, 0x00},
+ {WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX, 0x04},
+ {WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER, 0x01},
+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x01},
+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x01},
+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB, 0xac},
+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00},
+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB, 0xac},
+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00},
+ {WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x03},
+ {WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS, 0x03},
+ {WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX, 0x03},
+ {WSA885X_ANA_TOP_PON_CKSK_CTL_0, 0x00},
+ {WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG, 0x19},
+ {WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG, 0x22},
+ {WSA885X_ANA_PLL_DIV_CTL_0, 0x0c},
+ {WSA885X_ANA_PLL_DIV_CTL_1, 0x50},
+ {WSA885X_ANA_TOP_PLL_VCO_CTL, 0x00},
+ {WSA885X_ANA_TOP_PLL_LOOPFILT_0, 0xb4},
+ {WSA885X_ANA_TOP_PLL_OVRD_CTL, 0x00},
+ {WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00},
+ {WSA885X_ANA_TOP_BOOST_STB_CTRL2, 0x03},
+ {WSA885X_ANA_TOP_BOOST_STB_CTRL3, 0x3c},
+ {WSA885X_ANA_TOP_BOOST_BYP_CTRL2, 0xc5},
+ {WSA885X_ANA_TOP_BOOST_BYP_CTRL3, 0x13},
+ {WSA885X_ANA_TOP_BOOST_MISC, 0x79},
+ {WSA885X_ANA_TOP_SPK_TOP_SPARE3, 0x00},
+ {WSA885X_SPK_TOP_COMMON_CTRL2, 0x08},
+ {WSA885X_SPK_TOP_LF_CH1_CTRL11, 0x09},
+ {WSA885X_SPK_TOP_LF_CH1_TUNE1, 0x00},
+ {WSA885X_SPK_TOP_LF_CH2_TUNE1, 0x00},
+ {WSA885X_SPK_TOP_LF_CH1_CTRL9, 0x00},
+ {WSA885X_SPK_TOP_LF_CH2_CTRL9, 0x00},
+ {WSA885X_SPK_TOP_LF_CH2_CTRL11, 0x09},
+ {WSA885X_SPK_TOP_COMMON_TUNE1, 0x03},
+ {WSA885X_IVSENSE_VSNS_ISNS_CTL_CH1, 0x00},
+ {WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x0e},
+ {WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2, 0x40},
+ {WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4, 0xff},
+ {WSA885X_ANA_TOP_PLL_STATUS_0, 0x00},
+ {WSA885X_ANA_TOP_PLL_STATUS_1, 0x00},
+ {WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2, 0x84},
+ {WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x02},
+ {WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL, 0x00},
+ {WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2, 0xe0},
+ {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3, 0xa4},
+ {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3, 0xc9},
+ {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3, 0xa4},
+ {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3, 0xc9},
+ {WSA885X_DIG_CTRL0_TOP_CLK_CFG, 0x00},
+ {WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x00},
+ {WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x00},
+ {WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00},
+ {WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00},
+ {WSA885X_DIG_CTRL0_POWER_FSM_CTL0, 0x05},
+ {WSA885X_DIG_CTRL0_POWER_FSM_CTL1, 0x00},
+ {WSA885X_DIG_CTRL0_PA0_FSM_CTL1, 0x45},
+ {WSA885X_DIG_CTRL0_PA1_FSM_CTL1, 0x45},
+ {WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL, 0x7f},
+ {WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x00},
+ {WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1, 0x01},
+ {WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1, 0x01},
+ {WSA885X_DIG_CTRL1_I2S_CTL0, 0x06},
+ {WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, 0x00},
+ {WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, 0x00},
+ {WSA885X_DIG_CTRL1_I2S_TDM_CTL0, 0x00},
+ {WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x05},
+ {WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, 0x00},
+ {WSA885X_DIG_CTRL1_I2S_RESET_CTL, 0x00},
+ {WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, WSA885X_I2S_TDM_CH_RX_CH3_EN},
+ {WSA885X_CDC_RX0_RX_PATH_CFG0, 0x89},
+ {WSA885X_CDC_RX0_RX_PATH_CFG1, 0x64},
+ {WSA885X_CDC_RX0_RX_PATH_CTL, 0x24},
+ {WSA885X_RX0_RX_PATH_DSMDEM_CTL, 0x01},
+ {WSA885X_CDC_RX1_RX_PATH_CFG0, 0x89},
+ {WSA885X_CDC_RX1_RX_PATH_CFG1, 0x64},
+ {WSA885X_CDC_RX1_RX_PATH_CTL, 0x04},
+ {WSA885X_RX1_RX_PATH_DSMDEM_CTL, 0x01},
+ {WSA885X_CDC_COMPANDER0_CTL0, 0x01},
+ {WSA885X_CDC_COMPANDER0_CTL7, 0x2a},
+ {WSA885X_CDC_COMPANDER1_CTL0, 0x01},
+ {WSA885X_CDC_COMPANDER1_CTL7, 0x2a},
+ {WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL, 0x14},
+ {WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL, 0x14},
+ {WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL, 0x14},
+ {WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL, 0x14},
+ {WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x50},
+ {WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0x6c},
+ {WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0, 0x0d},
+ {WSA885X_CDC_CLSH_CLSH_V_HD_PA, 0x03},
+ {WSA885X_CDC_CLSH_V1P8_BP_CTL2, 0x05},
+};
+
+static void wsa885x_multi_update_bits(struct regmap *regmap,
+ const struct wsa885x_reg_update *updates,
+ size_t num_updates)
+{
+ size_t i;
+
+ for (i = 0; i < num_updates; i++)
+ regmap_update_bits(regmap, updates[i].reg,
+ updates[i].mask, updates[i].val);
+}
+
+static void wsa885x_toggle_irq_bit(struct wsa885x_priv *wsa885x,
+ unsigned int reg, unsigned int mask)
+{
+ regmap_update_bits(wsa885x->regmap, reg, mask, 0);
+ regmap_update_bits(wsa885x->regmap, reg, mask, mask);
+}
+
+static void wsa885x_pulse_irq_bit(struct wsa885x_priv *wsa885x,
+ unsigned int reg, unsigned int mask)
+{
+ regmap_update_bits(wsa885x->regmap, reg, mask, 0);
+ regmap_update_bits(wsa885x->regmap, reg, mask, mask);
+ regmap_update_bits(wsa885x->regmap, reg, mask, 0);
+}
+
+static int wsa885x_tdm_ctl0_slot_num_val(int slots, unsigned int *slot_num_val)
+{
+ if (!slot_num_val)
+ return -EINVAL;
+
+ switch (slots) {
+ case 2:
+ *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_2;
+ return 0;
+ case 4:
+ *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_4;
+ return 0;
+ case 8:
+ *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_8;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int wsa885x_reg_update_sequence(struct regmap *regmap, int slots)
+{
+ static const struct reg_sequence regs[] = {
+ { WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x15 },
+ { WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x11 },
+ };
+ unsigned int slot_num_val;
+ int ret;
+
+ if (!regmap)
+ return -EINVAL;
+
+ ret = wsa885x_tdm_ctl0_slot_num_val(slots, &slot_num_val);
+ if (ret)
+ return ret;
+
+ regmap_multi_reg_write(regmap, regs, ARRAY_SIZE(regs));
+
+ regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CTL0,
+ WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK,
+ slot_num_val);
+ regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CTL0,
+ WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK,
+ WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK);
+ regmap_write(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX,
+ WSA885X_I2S_TDM_CH_TX_CH0_EN);
+ regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX,
+ WSA885X_I2S_TDM_CH_TX_CH1_EN,
+ WSA885X_I2S_TDM_CH_TX_CH1_EN);
+
+ return 0;
+}
+
+static int wsa885x_wait_for_pll_lock(struct wsa885x_priv *wsa885x)
+{
+ unsigned int status = 0;
+ int cnt = 0, ret = 0;
+
+ do {
+ usleep_range(1000, 1100);
+ ret = regmap_read(wsa885x->regmap, WSA885X_ANA_TOP_PLL_STATUS_0, &status);
+ if (ret) {
+ dev_err(wsa885x->dev, "PLL status read failed: %d\n", ret);
+ return ret;
+ }
+
+ if (status & WSA885X_PLL_LOCK_BIT)
+ return 0;
+ } while (++cnt < 20);
+
+ dev_warn(wsa885x->dev, "PLL lock timeout after 20ms, status=0x%x\n", status);
+ return -ETIMEDOUT;
+}
+
+static int wsa885x_2s_conf(struct wsa885x_priv *wsa885x)
+{
+ static const struct reg_sequence regs[] = {
+ { WSA885X_SPK_TOP_COMMON_TUNE1, 0x26 },
+ { WSA885X_SPK_TOP_LF_CH1_CTRL11, 0x0d },
+ { WSA885X_SPK_TOP_LF_CH2_CTRL11, 0x0d },
+ { WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x71 },
+ { WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0xAA },
+ };
+
+ return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs));
+}
+
+static const struct reg_sequence wsa885x_reg_init[] = {
+ { WSA885X_CDC_RX0_RX_PATH_CTL, 0x24 },
+ { WSA885X_CDC_RX1_RX_PATH_CTL, 0x24 },
+ { WSA885X_RX0_RX_PATH_DSMDEM_CTL, 0x01 },
+ { WSA885X_RX1_RX_PATH_DSMDEM_CTL, 0x01 },
+ { WSA885X_CDC_COMPANDER0_CTL0, 0x01 },
+ { WSA885X_CDC_COMPANDER1_CTL0, 0x01 },
+ { WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL, 0x14 },
+ { WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL, 0x14 },
+ { WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL, 0x14 },
+ { WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL, 0x14 },
+ { WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x0f },
+ { WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x4f },
+ { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x02 },
+ { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x00 },
+ { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x01 },
+ { WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK, 0x01 },
+ { WSA885X_CDC_RX0_RX_PATH_CFG1, 0x60 },
+ { WSA885X_CDC_RX1_RX_PATH_CFG1, 0x60 },
+ { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3, 0xa5 },
+ { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3, 0xa5 },
+ { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2, 0x85 },
+ { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x0c },
+ { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x0e },
+ { WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL, 0x0c },
+ { WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1, 0x01 },
+ { WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1, 0x01 },
+ { WSA885X_CDC_RX0_RX_PATH_CFG0, 0x88 },
+ { WSA885X_CDC_RX0_RX_PATH_CFG0, 0x89 },
+ { WSA885X_CDC_RX1_RX_PATH_CFG0, 0x88 },
+ { WSA885X_CDC_RX1_RX_PATH_CFG0, 0x89 },
+ { WSA885X_ANA_TOP_BOOST_STB_CTRL2, 0x82 },
+ { WSA885X_ANA_TOP_BOOST_STB_CTRL3, 0x34 },
+ { WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2, 0x41 },
+ { WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4, 0x7f },
+ { WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x50 },
+ { WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0x6c },
+ { WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0, 0x0d },
+ { WSA885X_CDC_CLSH_CLSH_V_HD_PA, 0x03 },
+ { WSA885X_DIG_CTRL0_POWER_FSM_CTL0, 0x05 },
+ { WSA885X_ANA_TOP_PON_CKSK_CTL_0, 0x20 },
+ { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3, 0x45 },
+ { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3, 0x45 },
+ { WSA885X_CDC_CLSH_V1P8_BP_CTL2, 0x05 },
+ { WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG, 0x35 },
+ { WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG, 0x21 },
+ { WSA885X_ANA_TOP_BOOST_BYP_CTRL2, 0xc7 },
+ { WSA885X_ANA_TOP_BOOST_BYP_CTRL3, 0x11 },
+ { WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2, 0x80 },
+ { WSA885X_ANA_TOP_SPK_TOP_SPARE3, 0x08 },
+ { WSA885X_DIG_CTRL0_PA0_FSM_CTL1, 0x47 },
+ { WSA885X_DIG_CTRL0_PA1_FSM_CTL1, 0x47 },
+ { WSA885X_CDC_COMPANDER0_CTL7, 0x34 },
+ { WSA885X_CDC_COMPANDER1_CTL7, 0x34 },
+ { WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL, 0x79 },
+};
+
+static int wsa885x_hw_init(struct wsa885x_priv *wsa885x)
+{
+ static const struct reg_sequence regs[] = {
+ { WSA885X_DIG_CTRL1_SPMI_PAD_GPIO2_CTL, 0x2e },
+ { WSA885X_DIG_CTRL1_INTR_MODE, 0x01 },
+ { WSA885X_DIG_CTRL1_PIN_CT, 0x04 },
+ };
+ int ret;
+
+ ret = regmap_multi_reg_write(wsa885x->regmap, wsa885x_reg_init,
+ ARRAY_SIZE(wsa885x_reg_init));
+ if (ret)
+ return ret;
+
+ if (wsa885x->batt_conf == WSA885X_BATT_2S) {
+ ret = wsa885x_2s_conf(wsa885x);
+ if (ret)
+ return ret;
+ }
+
+ return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs));
+}
+
+static int wsa885x_unmask_interrupts(struct wsa885x_priv *wsa885x)
+{
+ static const struct reg_sequence regs[] = {
+ { WSA885X_INTR_MASK0, 0x00 },
+ { WSA885X_INTR_MASK0 + 1, 0x00 },
+ { WSA885X_INTR_MASK0 + 2, 0xf8 },
+ };
+
+ return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs));
+}
+
+static int wsa885x_wait_for_pde_state(struct wsa885x_priv *wsa885x, int ps)
+{
+ unsigned int act_ps = 0, clock_valid = 0;
+ int rc = 0, cnt = 0;
+
+ if (ps < 0 || ps > 3)
+ return -EINVAL;
+
+ do {
+ usleep_range(1000, 1500);
+ rc = regmap_read(wsa885x->regmap,
+ WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS,
+ &act_ps);
+ if (rc) {
+ dev_err(wsa885x->dev, "PDE state read failed: %d\n", rc);
+ return rc;
+ }
+ if (act_ps == ps)
+ return 0;
+ } while (++cnt < 5);
+
+ if (regmap_read(wsa885x->regmap,
+ WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID,
+ &clock_valid))
+ dev_err(wsa885x->dev,
+ "PDE power state %d request failed, actual_ps %d, clock_valid read failed\n",
+ ps, act_ps);
+ else
+ dev_err(wsa885x->dev,
+ "PDE power state %d request failed, actual_ps %d, clock_valid:%d\n",
+ ps, act_ps, clock_valid);
+
+ return -ETIMEDOUT;
+}
+
+static void wsa885x_program_stereo_volume(struct wsa885x_priv *wsa885x,
+ int stereo_vol_db, bool commit)
+{
+ regmap_write(wsa885x->regmap,
+ WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB,
+ (u8)(s8)stereo_vol_db);
+ regmap_write(wsa885x->regmap,
+ WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00);
+ regmap_write(wsa885x->regmap,
+ WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB,
+ (u8)(s8)stereo_vol_db);
+ regmap_write(wsa885x->regmap,
+ WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00);
+
+ if (commit)
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01);
+}
+
+static int wsa885x_codec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct wsa885x_priv *wsa885x;
+ u8 pcm_rate, cs21_sample_rate_idx, cs24_sample_rate_idx;
+
+ wsa885x = snd_soc_component_get_drvdata(dai->component);
+
+ switch (params_rate(params)) {
+ case 8000:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_8KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_8000HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_8000HZ;
+ break;
+ case 16000:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_16KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_16000HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_16000HZ;
+ break;
+ case 32000:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_32KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_32000HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_48000HZ;
+ break;
+ case 44100:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_44100HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_44100HZ;
+ break;
+ case 48000:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_48000HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_48000HZ;
+ break;
+ case 88200:
+ case 96000:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_96_OR_88KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_96000HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_96000HZ;
+ break;
+ case 176400:
+ case 192000:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_192_OR_176KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_192000HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_192000HZ;
+ break;
+ case 352800:
+ case 384000:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_384_OR_352KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_384000HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_384000HZ;
+ break;
+ default:
+ dev_err(wsa885x->dev, "sampling rate %d is not supported\n", params_rate(params));
+ return -EINVAL;
+ }
+
+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_CTL0,
+ WSA885X_I2S_CTL0_PCM_RATE_MASK |
+ WSA885X_I2S_CTL0_ENABLE_MASK,
+ WSA885X_I2S_CTL0_PCM_RATE(pcm_rate) |
+ WSA885X_I2S_CTL0_ENABLE_MASK);
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL, 0x00);
+ regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX,
+ cs21_sample_rate_idx);
+ regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX,
+ cs24_sample_rate_idx);
+
+ mutex_lock(&wsa885x->state_lock);
+ wsa885x_program_stereo_volume(wsa885x, wsa885x->stereo_vol_db, false);
+ mutex_unlock(&wsa885x->state_lock);
+
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01);
+
+ return 0;
+}
+
+static int wsa885x_codec_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_slot_mask,
+ unsigned int rx_slot_mask, int slots,
+ int slot_width)
+{
+ static const struct wsa885x_reg_update stereo_updates[] = {
+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK,
+ WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE0) },
+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK,
+ WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_ISENSE1) },
+ { WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK,
+ WSA885X_I2S_CFG1_TDM_TX_SLOT2(WSA885X_I2S_TX_SLOT_CUR_SENSE0) },
+ { WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK,
+ WSA885X_I2S_CFG1_TDM_TX_SLOT3(WSA885X_I2S_TX_SLOT_CUR_SENSE1) },
+ };
+ static const struct wsa885x_reg_update mono_left_updates[] = {
+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK,
+ WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE0) },
+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK,
+ WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_CUR_SENSE0) },
+ };
+ static const struct wsa885x_reg_update mono_right_updates[] = {
+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK,
+ WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE1) },
+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK,
+ WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_CUR_SENSE1) },
+ };
+ struct wsa885x_priv *wsa885x;
+ unsigned int slot_num_val;
+ u32 mask;
+ int ret;
+
+ wsa885x = snd_soc_component_get_drvdata(dai->component);
+
+ ret = wsa885x_tdm_ctl0_slot_num_val(slots, &slot_num_val);
+ if (ret) {
+ dev_err(wsa885x->dev, "%s: unsupported slot count %d\n",
+ __func__, slots);
+ return ret;
+ }
+
+ if (rx_slot_mask && !wsa885x_is_valid_rx_slot_mask(rx_slot_mask)) {
+ dev_err(wsa885x->dev,
+ "%s: unsupported rx_slot_mask 0x%x\n",
+ __func__, rx_slot_mask);
+ return -EINVAL;
+ }
+
+ mutex_lock(&wsa885x->state_lock);
+ if (rx_slot_mask)
+ wsa885x->rx_slot_mask = rx_slot_mask;
+ else if (!wsa885x_is_valid_rx_slot_mask(wsa885x->rx_slot_mask))
+ wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO;
+ mask = wsa885x->rx_slot_mask;
+
+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL,
+ WSA885X_I2S_RESET_CTL_RESET_MASK,
+ WSA885X_I2S_RESET_CTL_RESET_MASK);
+
+ if (mask == WSA885X_CHANNEL_STEREO) {
+ wsa885x_multi_update_bits(wsa885x->regmap, stereo_updates,
+ ARRAY_SIZE(stereo_updates));
+ ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots);
+ if (ret)
+ goto exit_unlock;
+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX,
+ WSA885X_I2S_TDM_CH_TX_CH2_EN,
+ WSA885X_I2S_TDM_CH_TX_CH2_EN);
+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX,
+ WSA885X_I2S_TDM_CH_TX_CH3_EN,
+ WSA885X_I2S_TDM_CH_TX_CH3_EN);
+ } else if (mask == WSA885X_CHANNEL_MONO_LEFT) {
+ wsa885x_multi_update_bits(wsa885x->regmap, mono_left_updates,
+ ARRAY_SIZE(mono_left_updates));
+ ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots);
+ if (ret)
+ goto exit_unlock;
+ } else if (mask == WSA885X_CHANNEL_MONO_RIGHT) {
+ wsa885x_multi_update_bits(wsa885x->regmap, mono_right_updates,
+ ARRAY_SIZE(mono_right_updates));
+ ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots);
+ if (ret)
+ goto exit_unlock;
+ }
+
+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_CTL0,
+ WSA885X_I2S_CTL0_ENABLE_MASK,
+ WSA885X_I2S_CTL0_ENABLE_MASK);
+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL,
+ WSA885X_I2S_RESET_CTL_RESET_MASK, 0);
+
+ ret = 0;
+
+exit_unlock:
+ mutex_unlock(&wsa885x->state_lock);
+
+ return ret;
+}
+
+static int wsa885x_codec_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ static const struct reg_sequence pll_prep[] = {
+ { WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x03 },
+ { WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x04 },
+ { WSA885X_ANA_TOP_PLL_LOOPFILT_0, 0xB4 },
+ { WSA885X_ANA_TOP_PLL_VCO_CTL, 0x00 },
+ { WSA885X_ANA_TOP_PLL_OVRD_CTL, 0x00 },
+ };
+ static const struct reg_sequence pll_cleanup[] = {
+ { WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x00 },
+ { WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00 },
+ { WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00 },
+ };
+ struct wsa885x_priv *wsa885x;
+ u32 pll_div;
+ int ret = 0;
+
+ wsa885x = snd_soc_component_get_drvdata(dai->component);
+
+ if (!freq)
+ return -EINVAL;
+ if (WSA885X_CLK_RATE_FIXED % freq)
+ return -EINVAL;
+ pll_div = WSA885X_CLK_RATE_FIXED / freq;
+ if (pll_div > 0xff)
+ return -EINVAL;
+
+ regmap_multi_reg_write(wsa885x->regmap, pll_prep, ARRAY_SIZE(pll_prep));
+ regmap_write(wsa885x->regmap, WSA885X_ANA_PLL_DIV_CTL_0, pll_div);
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x02);
+
+ ret = wsa885x_wait_for_pll_lock(wsa885x);
+ if (ret) {
+ dev_err(wsa885x->dev, "PLL lock failed, aborting sysclk configuration\n");
+ regmap_multi_reg_write(wsa885x->regmap, pll_cleanup,
+ ARRAY_SIZE(pll_cleanup));
+ return ret;
+ }
+
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00);
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_POWER_FSM_CTL1, 0x01);
+ regmap_write(wsa885x->regmap, WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00);
+
+ return 0;
+}
+
+static int wsa885x_codec_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+ static const struct reg_sequence mute_regs[] = {
+ { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 },
+ { WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x03 },
+ };
+ static const struct reg_sequence mute_commit_regs[] = {
+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x01 },
+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x01 },
+ { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 },
+ };
+ static const struct reg_sequence unmute_prep_head_regs[] = {
+ { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 },
+ };
+ static const struct reg_sequence unmute_prep_tail_regs[] = {
+ { WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX, 0x01 },
+ { WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER, 0x01 },
+ };
+ static const struct reg_sequence unmute_volume_regs[] = {
+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00 },
+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00 },
+ };
+ static const struct reg_sequence unmute_commit_regs[] = {
+ { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 },
+ { WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x00 },
+ };
+ static const struct reg_sequence unmute_finish_regs[] = {
+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x00 },
+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x00 },
+ { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 },
+ };
+ struct wsa885x_priv *wsa885x;
+ int ret = 0, ps0 = 0, ps3 = 3;
+
+ wsa885x = snd_soc_component_get_drvdata(dai->component);
+
+ if (stream != SNDRV_PCM_STREAM_PLAYBACK)
+ return 0;
+
+ mutex_lock(&wsa885x->state_lock);
+
+ if (wsa885x->usage_mode > WSA885X_USAGE_MODE_MAX) {
+ ret = -EINVAL;
+ goto exit_unlock;
+ }
+
+ if (!wsa885x_is_valid_rx_slot_mask(wsa885x->rx_slot_mask))
+ wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO;
+
+ if (mute) {
+ regmap_multi_reg_write(wsa885x->regmap, mute_regs,
+ ARRAY_SIZE(mute_regs));
+ ret = wsa885x_wait_for_pde_state(wsa885x, ps3);
+ if (ret) {
+ dev_err(wsa885x->dev,
+ "PS3 transition failed: %d\n", ret);
+ } else {
+ regmap_multi_reg_write(wsa885x->regmap, mute_commit_regs,
+ ARRAY_SIZE(mute_commit_regs));
+ }
+ } else {
+ regmap_multi_reg_write(wsa885x->regmap, unmute_prep_head_regs,
+ ARRAY_SIZE(unmute_prep_head_regs));
+ regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE,
+ wsa885x->usage_mode);
+ regmap_multi_reg_write(wsa885x->regmap, unmute_prep_tail_regs,
+ ARRAY_SIZE(unmute_prep_tail_regs));
+ wsa885x_program_stereo_volume(wsa885x, wsa885x->stereo_vol_db, false);
+ regmap_multi_reg_write(wsa885x->regmap, unmute_volume_regs,
+ ARRAY_SIZE(unmute_volume_regs));
+ regmap_multi_reg_write(wsa885x->regmap, unmute_commit_regs,
+ ARRAY_SIZE(unmute_commit_regs));
+ ret = wsa885x_wait_for_pde_state(wsa885x, ps0);
+ if (ret)
+ goto exit_unlock;
+
+ if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_STEREO) {
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX,
+ WSA885X_I2S_TDM_CH_RX_CH0_EN |
+ WSA885X_I2S_TDM_CH_RX_CH3_EN);
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x03);
+ } else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_LEFT) {
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX,
+ WSA885X_I2S_TDM_CH_RX_CH3_EN);
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x01);
+ } else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_RIGHT) {
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX,
+ WSA885X_I2S_TDM_CH_RX_CH0_EN);
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x02);
+ }
+
+ regmap_multi_reg_write(wsa885x->regmap, unmute_finish_regs,
+ ARRAY_SIZE(unmute_finish_regs));
+ }
+
+exit_unlock:
+ mutex_unlock(&wsa885x->state_lock);
+
+ return ret;
+}
+
+static int wsa885x_codec_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ static const struct reg_sequence regs[] = {
+ { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 },
+ };
+ struct wsa885x_priv *wsa885x;
+
+ wsa885x = snd_soc_component_get_drvdata(dai->component);
+
+ if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+ return 0;
+
+ mutex_lock(&wsa885x->state_lock);
+ regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs));
+ mutex_unlock(&wsa885x->state_lock);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops wsa885x_dai_ops = {
+ .hw_params = wsa885x_codec_hw_params,
+ .set_tdm_slot = wsa885x_codec_set_tdm_slot,
+ .set_sysclk = wsa885x_codec_set_sysclk,
+ .mute_stream = wsa885x_codec_mute_stream,
+ .hw_free = wsa885x_codec_hw_free,
+};
+
+static struct snd_soc_dai_driver wsa885x_dai[] = {
+ {
+ .name = "wsa885x_dai_drv",
+ .playback = {
+ .stream_name = "WSA885X TDM Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WSA885X_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &wsa885x_dai_ops,
+ },
+};
+
+static void wsa885x_reset_assert(void *data)
+{
+ struct wsa885x_priv *wsa885x = data;
+
+ if (wsa885x->sd_reset)
+ reset_control_assert(wsa885x->sd_reset);
+ else
+ gpiod_direction_output(wsa885x->sd_n, 1);
+}
+
+static void wsa885x_reset_deassert(struct wsa885x_priv *wsa885x)
+{
+ if (wsa885x->sd_reset)
+ reset_control_deassert(wsa885x->sd_reset);
+ else
+ gpiod_direction_output(wsa885x->sd_n, 0);
+}
+
+static int wsa885x_get_reset(struct device *dev, struct wsa885x_priv *wsa885x)
+{
+ wsa885x->sd_reset = devm_reset_control_get_optional_shared(dev, NULL);
+ if (IS_ERR(wsa885x->sd_reset))
+ return dev_err_probe(dev, PTR_ERR(wsa885x->sd_reset),
+ "Failed to get reset\n");
+ else if (wsa885x->sd_reset)
+ return 0;
+
+ wsa885x->sd_n = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH);
+ if (IS_ERR(wsa885x->sd_n))
+ return dev_err_probe(dev, PTR_ERR(wsa885x->sd_n),
+ "Shutdown Control GPIO not found\n");
+
+ return 0;
+}
+
+static bool wsa885x_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WSA885X_ANA_TOP_PLL_STATUS_0:
+ case WSA885X_ANA_TOP_PLL_STATUS_1:
+ case WSA885X_DIG_CTRL0_SDCA_COMMIT:
+ case WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS:
+ case WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID:
+ case WSA885X_INTR_STATUS0:
+ case WSA885X_INTR_STATUS0 + 1:
+ case WSA885X_INTR_STATUS0 + 2:
+ case WSA885X_INTR_CLEAR0:
+ case WSA885X_INTR_CLEAR0 + 1:
+ case WSA885X_INTR_CLEAR0 + 2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool wsa885x_readable_register(struct device *dev, unsigned int reg)
+{
+ if (reg == WSA885X_INTR_CLEAR0 ||
+ reg == WSA885X_INTR_CLEAR0 + 1 ||
+ reg == WSA885X_INTR_CLEAR0 + 2)
+ return false;
+ return reg <= 0x88ff;
+}
+
+static bool wsa885x_writeable_register(struct device *dev, unsigned int reg)
+{
+ if (reg > 0x88ff)
+ return false;
+
+ switch (reg) {
+ case WSA885X_ANA_TOP_PLL_STATUS_0:
+ case WSA885X_ANA_TOP_PLL_STATUS_1:
+ case WSA885X_INTR_STATUS0:
+ case WSA885X_INTR_STATUS0 + 1:
+ case WSA885X_INTR_STATUS0 + 2:
+ case WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS:
+ case WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static const struct regmap_config wsa885x_regmap_cfg = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x88FF,
+ .ranges = wsa885x_regmap_ranges,
+ .num_ranges = ARRAY_SIZE(wsa885x_regmap_ranges),
+ .reg_defaults = wsa885x_codec_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wsa885x_codec_reg_defaults),
+ .volatile_reg = wsa885x_volatile_register,
+ .writeable_reg = wsa885x_writeable_register,
+ .readable_reg = wsa885x_readable_register,
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int wsa885x_component_probe(struct snd_soc_component *component)
+{
+ struct wsa885x_priv *wsa885x =
+ snd_soc_component_get_drvdata(component);
+ int ret;
+
+ wsa885x->component = component;
+ snd_soc_component_init_regmap(component, wsa885x->regmap);
+
+ ret = wsa885x_hw_init(wsa885x);
+ if (ret)
+ return ret;
+
+ return wsa885x_unmask_interrupts(wsa885x);
+}
+
+static int wsa885x_stereo_gain_offset_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component);
+ int val;
+
+ mutex_lock(&wsa885x->state_lock);
+ val = wsa885x->stereo_vol_db + 84;
+ mutex_unlock(&wsa885x->state_lock);
+ if (val < 0 || val > WSA885X_FU21_VOL_STEPS)
+ return -ERANGE;
+
+ ucontrol->value.integer.value[0] = val;
+ return 0;
+}
+
+static int wsa885x_stereo_gain_offset_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component);
+ long val;
+ int stereo_vol_db;
+
+ val = ucontrol->value.integer.value[0];
+
+ if (val < 0 || val > WSA885X_FU21_VOL_STEPS) {
+ dev_err(component->dev, "%s: Invalid range, Val: %ld\n", __func__, val);
+ return -EINVAL;
+ }
+
+ stereo_vol_db = (int)val - 84;
+
+ mutex_lock(&wsa885x->state_lock);
+ if (wsa885x->stereo_vol_db == stereo_vol_db) {
+ mutex_unlock(&wsa885x->state_lock);
+ return 0;
+ }
+
+ wsa885x_program_stereo_volume(wsa885x, stereo_vol_db, true);
+ wsa885x->stereo_vol_db = stereo_vol_db;
+ mutex_unlock(&wsa885x->state_lock);
+
+ return 1;
+}
+
+static int wsa885x_usage_modes_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&wsa885x->state_lock);
+ if (wsa885x->usage_mode > WSA885X_USAGE_MODE_MAX) {
+ mutex_unlock(&wsa885x->state_lock);
+ return -ERANGE;
+ }
+
+ ucontrol->value.integer.value[0] = wsa885x->usage_mode;
+ mutex_unlock(&wsa885x->state_lock);
+
+ return 0;
+}
+
+static int wsa885x_usage_modes_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component);
+ u32 val = ucontrol->value.integer.value[0];
+
+ if (val > WSA885X_USAGE_MODE_MAX)
+ return -EINVAL;
+
+ mutex_lock(&wsa885x->state_lock);
+ if (wsa885x->usage_mode == val) {
+ mutex_unlock(&wsa885x->state_lock);
+ return 0;
+ }
+
+ wsa885x->usage_mode = val;
+ mutex_unlock(&wsa885x->state_lock);
+
+ return 1;
+}
+
+static int wsa885x_rx_slot_mask_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component);
+ u32 mask;
+
+ mutex_lock(&wsa885x->state_lock);
+ mask = wsa885x->rx_slot_mask;
+ mutex_unlock(&wsa885x->state_lock);
+ if (!wsa885x_is_valid_rx_slot_mask(mask))
+ return -ERANGE;
+
+ ucontrol->value.integer.value[0] = mask;
+
+ return 0;
+}
+
+static int wsa885x_rx_slot_mask_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component);
+ u32 mask = ucontrol->value.integer.value[0];
+
+ if (!wsa885x_is_valid_rx_slot_mask(mask))
+ return -EINVAL;
+
+ mutex_lock(&wsa885x->state_lock);
+ if (wsa885x->rx_slot_mask == mask) {
+ mutex_unlock(&wsa885x->state_lock);
+ return 0;
+ }
+
+ wsa885x->rx_slot_mask = mask;
+ mutex_unlock(&wsa885x->state_lock);
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new wsa885x_snd_controls[] = {
+ SOC_SINGLE_EXT("Usage Mode", SND_SOC_NOPM, 0, WSA885X_USAGE_MODE_MAX, 0,
+ wsa885x_usage_modes_get,
+ wsa885x_usage_modes_put),
+
+ SOC_SINGLE_EXT_TLV("Speaker Volume", SND_SOC_NOPM,
+ 0, WSA885X_FU21_VOL_STEPS, 0,
+ wsa885x_stereo_gain_offset_get,
+ wsa885x_stereo_gain_offset_put,
+ wsa885x_fu21_digital_gain),
+
+ SOC_SINGLE_EXT("Rx Slot Mask", SND_SOC_NOPM, 0, 3, 0,
+ wsa885x_rx_slot_mask_get,
+ wsa885x_rx_slot_mask_put),
+};
+
+static const struct snd_soc_component_driver wsa885x_component = {
+ .name = "wsa885x",
+ .probe = wsa885x_component_probe,
+ .controls = wsa885x_snd_controls,
+ .num_controls = ARRAY_SIZE(wsa885x_snd_controls),
+};
+
+static irqreturn_t wsa885x_handle_irq(int irq_idx, void *data)
+{
+ struct wsa885x_priv *wsa885x = data;
+
+ if (irq_idx < 0 || irq_idx >= WSA885X_IRQ_MAX)
+ return IRQ_NONE;
+
+ switch (irq_idx) {
+ case WSA885X_IRQ_INT_SAF2WAR:
+ case WSA885X_IRQ_INT_WAR2SAF:
+ case WSA885X_IRQ_INT_DISABLE:
+ case WSA885X_IRQ_INT_INTR_GPIO1_PIN:
+ case WSA885X_IRQ_INT_INTR_GPIO2_PIN:
+ case WSA885X_IRQ_INT_PA0_OCP:
+ case WSA885X_IRQ_INT_PA1_OCP:
+ case WSA885X_IRQ_INT_CLIP0:
+ case WSA885X_IRQ_INT_CLIP1:
+ case WSA885X_IRQ_INT_CLK_WD:
+ case WSA885X_IRQ_INT_BOP:
+ case WSA885X_IRQ_INT_UVLO:
+ case WSA885X_IRQ_INT_PCM_DATA0_DC:
+ case WSA885X_IRQ_INT_PCM_DATA1_DC:
+ case WSA885X_IRQ_INT_PLL_UNLOCKED:
+ case WSA885X_IRQ_INT_PROT_MODE_CHANGE:
+ case WSA885X_IRQ_INT_PB_CLOCK_VALID:
+ case WSA885X_IRQ_INT_SENSE_CLOCK_VALID:
+ break;
+ case WSA885X_IRQ_INT_PCM_DATA0_WD:
+ case WSA885X_IRQ_INT_PCM_DATA1_WD:
+ if (irq_idx == WSA885X_IRQ_INT_PCM_DATA0_WD)
+ wsa885x_toggle_irq_bit(wsa885x, WSA885X_DIG_CTRL0_PCM_DATA_WD0_CTL1,
+ WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK);
+ else
+ wsa885x_toggle_irq_bit(wsa885x, WSA885X_DIG_CTRL0_PCM_DATA_WD1_CTL1,
+ WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK);
+ break;
+ case WSA885X_IRQ_INT_PA0_FSM_ERR:
+ case WSA885X_IRQ_INT_PA1_FSM_ERR:
+ case WSA885X_IRQ_INT_MAIN_FSM_ERR:
+ if (irq_idx == WSA885X_IRQ_INT_MAIN_FSM_ERR) {
+ wsa885x_pulse_irq_bit(wsa885x, WSA885X_DIG_CTRL0_POWER_FSM_CTL0,
+ WSA885X_POWER_FSM_CTL0_CLEAR_ERROR_MASK);
+ } else if (irq_idx == WSA885X_IRQ_INT_PA0_FSM_ERR) {
+ wsa885x_pulse_irq_bit(wsa885x, WSA885X_PA0_FSM_CTL0,
+ WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK);
+ } else if (irq_idx == WSA885X_IRQ_INT_PA1_FSM_ERR) {
+ wsa885x_pulse_irq_bit(wsa885x, WSA885X_PA1_FSM_CTL0,
+ WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wsa885x_interrupt_handler(int irq, void *data)
+{
+ static const unsigned int status_reg[WSA885X_NUM_REGS] = {
+ WSA885X_INTR_STATUS0,
+ WSA885X_INTR_STATUS0 + 1,
+ WSA885X_INTR_STATUS0 + 2,
+ };
+ static const unsigned int clear_reg[WSA885X_NUM_REGS] = {
+ WSA885X_INTR_CLEAR0,
+ WSA885X_INTR_CLEAR0 + 1,
+ WSA885X_INTR_CLEAR0 + 2,
+ };
+ unsigned int status[WSA885X_NUM_REGS] = { 0 };
+ struct wsa885x_priv *wsa885x = data;
+ irqreturn_t handled = IRQ_NONE;
+ irqreturn_t irq_ret;
+ int i, bit, ret, irq_num;
+
+ for (i = 0; i < WSA885X_NUM_REGS; i++) {
+ ret = regmap_read(wsa885x->regmap, status_reg[i], &status[i]);
+ if (ret) {
+ dev_err(wsa885x->dev,
+ "Failed to read status_reg[%d] (0x%x): %d\n",
+ i, status_reg[i], ret);
+ status[i] = 0;
+ continue;
+ }
+ }
+
+ for (i = 0; i < WSA885X_NUM_REGS; i++) {
+ for (bit = 0; bit < 8; bit++) {
+ if (status[i] & BIT(bit)) {
+ irq_num = i * 8 + bit;
+ regmap_write(wsa885x->regmap, clear_reg[i], BIT(bit));
+ regmap_write(wsa885x->regmap, clear_reg[i], 0);
+ if (irq_num >= WSA885X_IRQ_MAX) {
+ dev_warn_ratelimited(wsa885x->dev,
+ "Unexpected IRQ bit %d (reg %d)\n",
+ bit, i);
+ handled = IRQ_HANDLED;
+ continue;
+ }
+ irq_ret = wsa885x_handle_irq(irq_num, wsa885x);
+ if (irq_ret == IRQ_HANDLED)
+ handled = IRQ_HANDLED;
+ }
+ }
+ }
+ return handled;
+}
+
+static int wsa885x_register_irq(struct wsa885x_priv *wsa885x)
+{
+ if (!wsa885x->client->irq)
+ return dev_err_probe(wsa885x->dev, -EINVAL,
+ "IRQ is not configured\n");
+
+ return devm_request_threaded_irq(wsa885x->dev, wsa885x->client->irq, NULL,
+ wsa885x_interrupt_handler,
+ IRQF_ONESHOT,
+ dev_name(wsa885x->dev), wsa885x);
+}
+
+static int wsa885x_probe(struct i2c_client *client)
+{
+ struct wsa885x_priv *wsa885x;
+ const struct snd_soc_component_driver *component_driver = &wsa885x_component;
+ const char *battery_config;
+ unsigned int i;
+ int ret;
+ struct device *dev = &client->dev;
+
+ wsa885x = devm_kzalloc(dev, sizeof(*wsa885x), GFP_KERNEL);
+ if (!wsa885x)
+ return -ENOMEM;
+
+ wsa885x->client = client;
+ wsa885x->dev = dev;
+ wsa885x->stereo_vol_db = -84;
+ wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO;
+ mutex_init(&wsa885x->state_lock);
+ wsa885x->regmap = devm_regmap_init_i2c(client, &wsa885x_regmap_cfg);
+
+ if (IS_ERR(wsa885x->regmap))
+ return PTR_ERR(wsa885x->regmap);
+
+ ret = device_property_read_string(dev, "qcom,battery-config",
+ &battery_config);
+ if (ret) {
+ wsa885x->batt_conf = WSA885X_BATT_1S;
+ } else if (!strcmp(battery_config, "1s")) {
+ wsa885x->batt_conf = WSA885X_BATT_1S;
+ } else if (!strcmp(battery_config, "2s")) {
+ wsa885x->batt_conf = WSA885X_BATT_2S;
+ } else {
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid battery config %s (expected 1s or 2s)\n",
+ battery_config);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wsa885x_supply_name); i++) {
+ ret = devm_regulator_get_enable(dev, wsa885x_supply_name[i]);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable regulator %s\n",
+ wsa885x_supply_name[i]);
+ }
+
+ ret = wsa885x_get_reset(dev, wsa885x);
+ if (ret)
+ return ret;
+
+ wsa885x_reset_deassert(wsa885x);
+ usleep_range(5000, 5500);
+
+ ret = devm_add_action_or_reset(dev, wsa885x_reset_assert, wsa885x);
+ if (ret)
+ return dev_err_probe(dev, ret, "devm_add_action_or_reset failed\n");
+
+ i2c_set_clientdata(client, wsa885x);
+
+ ret = wsa885x_register_irq(wsa885x);
+ if (ret)
+ return dev_err_probe(dev, ret, "wsa885x irq registration failed\n");
+
+ ret = devm_snd_soc_register_component(dev, component_driver,
+ wsa885x_dai,
+ ARRAY_SIZE(wsa885x_dai));
+ if (ret)
+ return dev_err_probe(dev, ret, "Codec component registration failed\n");
+
+ return 0;
+}
+
+static const struct of_device_id wsa885x_dt_match[] = {
+ {
+ .compatible = "qcom,wsa8855",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, wsa885x_dt_match);
+
+static const struct i2c_device_id wsa885x_id[] = {
+ {
+ .name = "wsa885x",
+ .driver_data = 0,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, wsa885x_id);
+
+static struct i2c_driver wsa885x_driver = {
+ .driver = {
+ .name = "wsa885x",
+ .of_match_table = wsa885x_dt_match,
+ },
+ .probe = wsa885x_probe,
+ .id_table = wsa885x_id,
+};
+
+module_i2c_driver(wsa885x_driver);
+
+MODULE_DESCRIPTION("ASoC WSA885X Stereo Smart PA Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/zl38060.c b/sound/soc/codecs/zl38060.c
index 7de4014e626d..894b8eb42e39 100644
--- a/sound/soc/codecs/zl38060.c
+++ b/sound/soc/codecs/zl38060.c
@@ -162,7 +162,7 @@ static int zl38_fw_send_xaddr(struct regmap *regmap, const void *data)
static int zl38_load_firmware(struct device *dev, struct regmap *regmap)
{
const struct ihex_binrec *rec;
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
u32 addr;
u16 len;
int err;
@@ -180,7 +180,7 @@ static int zl38_load_firmware(struct device *dev, struct regmap *regmap)
return err;
err = zl38_fw_enter_boot_mode(regmap);
if (err)
- goto out;
+ return err;
rec = (const struct ihex_binrec *)fw->data;
while (rec) {
addr = be32_to_cpu(rec->addr);
@@ -195,15 +195,12 @@ static int zl38_load_firmware(struct device *dev, struct regmap *regmap)
err = -EINVAL;
}
if (err)
- goto out;
+ return err;
/* next ! */
rec = ihex_next_binrec(rec);
}
- err = zl38_fw_go(regmap);
-out:
- release_firmware(fw);
- return err;
+ return zl38_fw_go(regmap);
}