summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-08-03 13:18:29 +0100
committerMark Brown <broonie@kernel.org>2026-08-03 13:18:29 +0100
commitd58fe9eabc01543b79decfccfedd50d4c49351ff (patch)
tree0ea477298e1838a42a46b527cb9e744c486cade0
parentee145d35e44fd5d72eca19221bb65a26b9097c09 (diff)
parent69ddd29d8f078f440256534dcafce463ab1c2d24 (diff)
Merge remote-tracking branch 'asoc/for-7.3' into asoc-next
-rw-r--r--Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml240
-rw-r--r--Documentation/devicetree/bindings/sound/cs35l36.txt168
-rw-r--r--Documentation/devicetree/bindings/sound/dmic-codec.yaml4
-rw-r--r--Documentation/devicetree/bindings/sound/eukrea,asoc-tlv320.yaml61
-rw-r--r--Documentation/devicetree/bindings/sound/eukrea-tlv320.txt26
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,micfil.yaml4
-rw-r--r--Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml53
-rw-r--r--Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml22
-rw-r--r--Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml59
-rw-r--r--Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt24
-rw-r--r--Documentation/devicetree/bindings/sound/omap-dmic.txt20
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml8
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml11
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml50
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml4
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,sm8250.yaml4
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml93
-rw-r--r--Documentation/devicetree/bindings/sound/realtek,rt1015.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml64
-rw-r--r--Documentation/devicetree/bindings/sound/st,sta32x.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/ti,omap4-dmic.yaml58
-rw-r--r--Documentation/devicetree/bindings/sound/wlf,wm8524.yaml4
-rw-r--r--include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h7
-rw-r--r--include/linux/platform_data/omap-twl4030.h42
-rw-r--r--include/sound/aw88399.h621
-rw-r--r--include/sound/hda-mlink.h23
-rw-r--r--include/sound/sdca_asoc.h7
-rw-r--r--include/sound/sdca_fdl.h4
-rw-r--r--include/sound/sdca_function.h2
-rw-r--r--include/sound/simple_card_utils.h37
-rw-r--r--include/sound/soc_sdw_utils.h31
-rw-r--r--include/sound/sof/dai-amd.h1
-rw-r--r--include/sound/sof/dai.h3
-rw-r--r--include/sound/sof/header.h4
-rw-r--r--include/sound/sof/ipc4/header.h133
-rw-r--r--include/sound/tlv320aic32x4.h43
-rw-r--r--include/uapi/sound/sof/tokens.h5
-rw-r--r--sound/soc/amd/acp-config.c12
-rw-r--r--sound/soc/amd/acp/acp-i2s.c6
-rw-r--r--sound/soc/amd/acp/acp-mach-common.c11
-rw-r--r--sound/soc/amd/acp/acp-pci.c26
-rw-r--r--sound/soc/amd/acp/acp-sdw-legacy-mach.c20
-rw-r--r--sound/soc/amd/acp/acp-sdw-sof-mach.c16
-rw-r--r--sound/soc/amd/acp/acp-sof-mach.c14
-rw-r--r--sound/soc/amd/mach-config.h1
-rw-r--r--sound/soc/amd/raven/acp3x-i2s.c6
-rw-r--r--sound/soc/amd/vangogh/acp5x-i2s.c6
-rw-r--r--sound/soc/amd/yc/acp6x-mach.c12
-rw-r--r--sound/soc/apple/mca.c315
-rw-r--r--sound/soc/atmel/atmel-i2s.c4
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c7
-rw-r--r--sound/soc/atmel/atmel_wm8904.c13
-rw-r--r--sound/soc/atmel/mchp-i2s-mcc.c9
-rw-r--r--sound/soc/atmel/mchp-pdmc.c4
-rw-r--r--sound/soc/au1x/db1200.c2
-rw-r--r--sound/soc/au1x/i2sc.c11
-rw-r--r--sound/soc/au1x/psc-ac97.c4
-rw-r--r--sound/soc/au1x/psc-i2s.c11
-rw-r--r--sound/soc/bcm/bcm2835-i2s.c13
-rw-r--r--sound/soc/bcm/cygnus-ssp.c7
-rw-r--r--sound/soc/cirrus/ep93xx-i2s.c11
-rw-r--r--sound/soc/codecs/Kconfig50
-rw-r--r--sound/soc/codecs/Makefile4
-rw-r--r--sound/soc/codecs/ab8500-codec.c12
-rw-r--r--sound/soc/codecs/adau7118-hw.c2
-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.c10
-rw-r--r--sound/soc/codecs/aw88081.c18
-rw-r--r--sound/soc/codecs/aw88166.c24
-rw-r--r--sound/soc/codecs/aw88261.c27
-rw-r--r--sound/soc/codecs/aw88261.h6
-rw-r--r--sound/soc/codecs/aw88395/aw88395.c24
-rw-r--r--sound/soc/codecs/aw88395/aw88395_device.c40
-rw-r--r--sound/soc/codecs/aw88399-lib.c1411
-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/cros_ec_codec.c18
-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-sdw.c2
-rw-r--r--sound/soc/codecs/cs35l56-shared.c34
-rw-r--r--sound/soc/codecs/cs35l56.c1
-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.c5
-rw-r--r--sound/soc/codecs/da7213.c37
-rw-r--r--sound/soc/codecs/da7219.c62
-rw-r--r--sound/soc/codecs/es8316.c31
-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/fs210x.c89
-rw-r--r--sound/soc/codecs/hdac_hda.c4
-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/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.c39
-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.c8
-rw-r--r--sound/soc/codecs/max98396.c24
-rw-r--r--sound/soc/codecs/max98927.c8
-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/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.c28
-rw-r--r--sound/soc/codecs/pcm6240.c25
-rw-r--r--sound/soc/codecs/peb2466.c16
-rw-r--r--sound/soc/codecs/pm4125-sdw.c8
-rw-r--r--sound/soc/codecs/pm4125.c3
-rw-r--r--sound/soc/codecs/rt1017-sdca-sdw.c7
-rw-r--r--sound/soc/codecs/rt1316-sdw.c7
-rw-r--r--sound/soc/codecs/rt1318-sdw.c7
-rw-r--r--sound/soc/codecs/rt1320-sdw.c869
-rw-r--r--sound/soc/codecs/rt1320-sdw.h19
-rw-r--r--sound/soc/codecs/rt5514-spi.c21
-rw-r--r--sound/soc/codecs/rt5514.c16
-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.c92
-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/rt711-sdca-sdw.c29
-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.c50
-rw-r--r--sound/soc/codecs/rt712-sdca-dmic.c17
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.c45
-rw-r--r--sound/soc/codecs/rt712-sdca.c5
-rw-r--r--sound/soc/codecs/rt721-sdca-sdw.c44
-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.c7
-rw-r--r--sound/soc/codecs/rt9120.c9
-rw-r--r--sound/soc/codecs/sigmadsp.c17
-rw-r--r--sound/soc/codecs/sma1303.c2
-rw-r--r--sound/soc/codecs/sta32x.c21
-rw-r--r--sound/soc/codecs/sta350.c20
-rw-r--r--sound/soc/codecs/tas2552.c10
-rw-r--r--sound/soc/codecs/tas2781-comlib-i2c.c5
-rw-r--r--sound/soc/codecs/tas2781-i2c.c42
-rw-r--r--sound/soc/codecs/tas2783-sdw.c86
-rw-r--r--sound/soc/codecs/tas5805m.c21
-rw-r--r--sound/soc/codecs/tlv320aic26.c6
-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.c28
-rw-r--r--sound/soc/codecs/wm2000.c28
-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/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/fsl/fsl_asrc.c10
-rw-r--r--sound/soc/fsl/fsl_audmix.c35
-rw-r--r--sound/soc/fsl/fsl_dma.c68
-rw-r--r--sound/soc/fsl/fsl_easrc.c38
-rw-r--r--sound/soc/fsl/fsl_esai.c16
-rw-r--r--sound/soc/fsl/fsl_spdif.c8
-rw-r--r--sound/soc/fsl/fsl_ssi.c13
-rw-r--r--sound/soc/fsl/fsl_xcvr.c29
-rw-r--r--sound/soc/fsl/imx-audio-rpmsg.c25
-rw-r--r--sound/soc/fsl/imx-pcm-rpmsg.c75
-rw-r--r--sound/soc/fsl/mpc5200_dma.c114
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c38
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.c4
-rw-r--r--sound/soc/fsl/p1022_ds.c14
-rw-r--r--sound/soc/fsl/p1022_rdk.c14
-rw-r--r--sound/soc/generic/audio-graph-card.c16
-rw-r--r--sound/soc/generic/audio-graph-card2.c35
-rw-r--r--sound/soc/generic/simple-card-utils.c82
-rw-r--r--sound/soc/generic/simple-card.c127
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.c67
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c66
-rw-r--r--sound/soc/intel/atom/sst/sst_ipc.c5
-rw-r--r--sound/soc/intel/atom/sst/sst_pci.c4
-rw-r--r--sound/soc/intel/atom/sst/sst_pvt.c9
-rw-r--r--sound/soc/intel/avs/apl.c8
-rw-r--r--sound/soc/intel/avs/boards/da7219.c7
-rw-r--r--sound/soc/intel/avs/boards/dmic.c6
-rw-r--r--sound/soc/intel/avs/boards/es8336.c6
-rw-r--r--sound/soc/intel/avs/boards/hdaudio.c6
-rw-r--r--sound/soc/intel/avs/boards/i2s_test.c6
-rw-r--r--sound/soc/intel/avs/boards/max98357a.c6
-rw-r--r--sound/soc/intel/avs/boards/max98373.c6
-rw-r--r--sound/soc/intel/avs/boards/max98927.c6
-rw-r--r--sound/soc/intel/avs/boards/nau8825.c6
-rw-r--r--sound/soc/intel/avs/boards/pcm3168a.c6
-rw-r--r--sound/soc/intel/avs/boards/probe.c2
-rw-r--r--sound/soc/intel/avs/boards/rt274.c2
-rw-r--r--sound/soc/intel/avs/boards/rt286.c2
-rw-r--r--sound/soc/intel/avs/boards/rt298.c2
-rw-r--r--sound/soc/intel/avs/boards/rt5514.c2
-rw-r--r--sound/soc/intel/avs/boards/rt5640.c2
-rw-r--r--sound/soc/intel/avs/boards/rt5663.c2
-rw-r--r--sound/soc/intel/avs/boards/rt5682.c2
-rw-r--r--sound/soc/intel/avs/boards/ssm4567.c2
-rw-r--r--sound/soc/intel/avs/control.c7
-rw-r--r--sound/soc/intel/avs/core.c4
-rw-r--r--sound/soc/intel/avs/debug.h10
-rw-r--r--sound/soc/intel/avs/debugfs.c19
-rw-r--r--sound/soc/intel/avs/ipc.c59
-rw-r--r--sound/soc/intel/avs/loader.c15
-rw-r--r--sound/soc/intel/avs/path.c30
-rw-r--r--sound/soc/intel/avs/utils.c45
-rw-r--r--sound/soc/intel/boards/sof_sdw.c16
-rw-r--r--sound/soc/intel/catpt/core.h4
-rw-r--r--sound/soc/intel/catpt/device.c33
-rw-r--r--sound/soc/intel/catpt/loader.c131
-rw-r--r--sound/soc/intel/catpt/pcm.c45
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-arl-match.c3
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-lnl-match.c15
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-mtl-match.c18
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-ptl-match.c6
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c8
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h1
-rw-r--r--sound/soc/loongson/loongson_card.c171
-rw-r--r--sound/soc/loongson/loongson_i2s_plat.c42
-rw-r--r--sound/soc/mediatek/Kconfig2
-rw-r--r--sound/soc/mediatek/common/mtk-dsp-sof-common.c7
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650.c2
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-dai-adda.c2
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c12
-rw-r--r--sound/soc/mediatek/mt8196/mt8196-nau8825.c2
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-mt6357.c10
-rw-r--r--sound/soc/meson/Makefile2
-rw-r--r--sound/soc/meson/aiu-encoder-i2s.c365
-rw-r--r--sound/soc/meson/aiu-formatter-i2s.c103
-rw-r--r--sound/soc/meson/aiu.c33
-rw-r--r--sound/soc/meson/aiu.h4
-rw-r--r--sound/soc/meson/axg-card.c25
-rw-r--r--sound/soc/meson/g12a-toacodec.c2
-rw-r--r--sound/soc/meson/g12a-tohdmitx.c2
-rw-r--r--sound/soc/meson/gx-card.c6
-rw-r--r--sound/soc/meson/gx-formatter.c282
-rw-r--r--sound/soc/meson/gx-formatter.h56
-rw-r--r--sound/soc/meson/gx-interface.h42
-rw-r--r--sound/soc/meson/meson-card-utils.c39
-rw-r--r--sound/soc/meson/t9015.c12
-rw-r--r--sound/soc/qcom/common.c9
-rw-r--r--sound/soc/qcom/common.h2
-rw-r--r--sound/soc/qcom/qdsp6/audioreach.c47
-rw-r--r--sound/soc/qcom/qdsp6/q6afe-dai.c48
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.c56
-rw-r--r--sound/soc/qcom/qdsp6/q6apm-lpass-dais.c168
-rw-r--r--sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c2
-rw-r--r--sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c5
-rw-r--r--sound/soc/qcom/qdsp6/q6prm-clocks.c7
-rw-r--r--sound/soc/qcom/qdsp6/q6prm.c16
-rw-r--r--sound/soc/qcom/qdsp6/q6prm.h15
-rw-r--r--sound/soc/qcom/qdsp6/q6routing.c78
-rw-r--r--sound/soc/qcom/sc8280xp.c369
-rw-r--r--sound/soc/qcom/sdm845.c2
-rw-r--r--sound/soc/qcom/sm8250.c17
-rw-r--r--sound/soc/qcom/storm.c12
-rw-r--r--sound/soc/renesas/fsi.c13
-rw-r--r--sound/soc/renesas/rcar/adg.c8
-rw-r--r--sound/soc/samsung/aries_wm8994.c1
-rw-r--r--sound/soc/samsung/i2s.c35
-rw-r--r--sound/soc/samsung/smdk_spdif.c8
-rw-r--r--sound/soc/samsung/spdif.c8
-rw-r--r--sound/soc/sdca/sdca_asoc.c5
-rw-r--r--sound/soc/sdca/sdca_functions.c7
-rw-r--r--sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c4
-rw-r--r--sound/soc/sdw_utils/soc_sdw_utils.c36
-rw-r--r--sound/soc/soc-dapm.c6
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c28
-rw-r--r--sound/soc/sof/amd/Kconfig11
-rw-r--r--sound/soc/sof/amd/Makefile2
-rw-r--r--sound/soc/sof/amd/acp-dsp-offset.h17
-rw-r--r--sound/soc/sof/amd/acp-ipc.c15
-rw-r--r--sound/soc/sof/amd/acp-loader.c37
-rw-r--r--sound/soc/sof/amd/acp.c267
-rw-r--r--sound/soc/sof/amd/acp.h20
-rw-r--r--sound/soc/sof/amd/acp7x.c185
-rw-r--r--sound/soc/sof/amd/pci-acp7x.c116
-rw-r--r--sound/soc/sof/intel/hda-ctrl.c19
-rw-r--r--sound/soc/sof/intel/hda-dai-ops.c76
-rw-r--r--sound/soc/sof/intel/hda-dai.c2
-rw-r--r--sound/soc/sof/intel/hda-dsp.c6
-rw-r--r--sound/soc/sof/intel/hda-loader.c11
-rw-r--r--sound/soc/sof/intel/hda-mlink.c35
-rw-r--r--sound/soc/sof/intel/hda-sdw-bpt.c2
-rw-r--r--sound/soc/sof/intel/hda-stream.c18
-rw-r--r--sound/soc/sof/intel/hda.c18
-rw-r--r--sound/soc/sof/intel/hda.h31
-rw-r--r--sound/soc/sof/intel/icl.c10
-rw-r--r--sound/soc/sof/intel/mtl.c23
-rw-r--r--sound/soc/sof/ipc3-pcm.c6
-rw-r--r--sound/soc/sof/ipc3-topology.c39
-rw-r--r--sound/soc/sof/ipc4-topology.c181
-rw-r--r--sound/soc/sof/ipc4-topology.h9
-rw-r--r--sound/soc/sof/ipc4.c84
-rw-r--r--sound/soc/sof/nocodec.c16
-rw-r--r--sound/soc/sof/pcm.c2
-rw-r--r--sound/soc/sof/sof-audio.h8
-rw-r--r--sound/soc/sof/topology.c15
-rw-r--r--sound/soc/spacemit/k1_i2s.c23
-rw-r--r--sound/soc/spear/spdif_in.c12
-rw-r--r--sound/soc/spear/spdif_out.c2
-rw-r--r--sound/soc/sprd/sprd-mcdt.c4
-rw-r--r--sound/soc/sprd/sprd-pcm-dma.c2
-rw-r--r--sound/soc/starfive/jh7110_pwmdac.c15
-rw-r--r--sound/soc/starfive/jh7110_tdm.c27
-rw-r--r--sound/soc/stm/stm32_adfsdm.c5
-rw-r--r--sound/soc/stm/stm32_i2s.c6
-rw-r--r--sound/soc/stm/stm32_sai_sub.c8
-rw-r--r--sound/soc/stm/stm32_spdifrx.c6
-rw-r--r--sound/soc/sunxi/sun4i-codec.c93
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c28
-rw-r--r--sound/soc/sunxi/sun4i-spdif.c23
-rw-r--r--sound/soc/sunxi/sun50i-codec-analog.c11
-rw-r--r--sound/soc/sunxi/sun8i-codec-analog.c11
-rw-r--r--sound/soc/tegra/tegra20_das.c7
-rw-r--r--sound/soc/tegra/tegra210_adx.c12
-rw-r--r--sound/soc/tegra/tegra210_amx.c12
-rw-r--r--sound/soc/tegra/tegra210_i2s.c10
-rw-r--r--sound/soc/ti/ams-delta.c8
-rw-r--r--sound/soc/ti/davinci-evm.c3
-rw-r--r--sound/soc/ti/j721e-evm.c11
-rw-r--r--sound/soc/ti/omap-abe-twl6040.c15
-rw-r--r--sound/soc/ti/omap-dmic.c7
-rw-r--r--sound/soc/ti/omap-hdmi.c9
-rw-r--r--sound/soc/ti/omap-twl4030.c166
-rw-r--r--sound/soc/ti/rx51.c53
-rw-r--r--sound/soc/uniphier/aio-cpu.c8
-rw-r--r--sound/soc/ux500/mop500.c12
-rw-r--r--sound/soc/ux500/mop500_ab8500.c2
-rw-r--r--sound/soc/xilinx/xlnx_i2s.c18
-rw-r--r--sound/soc/xilinx/xlnx_spdif.c31
-rw-r--r--sound/soc/xtensa/xtfpga-i2s.c60
397 files changed, 12361 insertions, 6710 deletions
diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml
index 4f13e8ab50b2..177db900d4a0 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml
+++ b/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml
@@ -30,7 +30,7 @@ properties:
minItems: 1
maxItems: 3
description:
- Base PLL clocks of audio susbsytem, used to configure base clock
+ Base PLL clocks of audio subsystem, used to configure base clock
frequencies for different audio use-cases.
patternProperties:
diff --git a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
index 413b47778181..6fdf605ad59c 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
+++ b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
@@ -31,7 +31,7 @@ properties:
minItems: 1
maxItems: 3
description:
- Base PLL clocks of audio susbsytem, used to configure base clock
+ Base PLL clocks of audio subsystem, used to configure base clock
frequencies for different audio use-cases.
patternProperties:
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
new file mode 100644
index 000000000000..2a142b32acf5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
@@ -0,0 +1,240 @@
+# SPDX-License-Identifier: GPL-2.0-only
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/cirrus,cs35l36.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cirrus Logic CS35L36 Speaker Amplifier
+
+maintainers:
+ - David Rhodes <drhodes@opensource.cirrus.com>
+ - patches@opensource.cirrus.com
+
+description:
+ CS35L36 is a boosted mono Class D amplifier
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ enum:
+ - cirrus,cs35l36
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ VA-supply:
+ description: Voltage regulator of analog internal section
+
+ VP-supply:
+ description: Voltage regulator of boost converter
+
+ reset-gpios:
+ maxItems: 1
+
+ cirrus,boost-ctl-millivolt:
+ description: Boost converter output voltage (step 50)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 2550
+ maximum: 12000
+
+ cirrus,boost-peak-milliamp:
+ description: Boost-converter peak current limit (step 50)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 4500
+ minimum: 1600
+ maximum: 4500
+
+ cirrus,boost-ind-nanohenry:
+ description: Initial inductor estimation reference value (1000=1μH, 1200=1.2μH)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 1000
+
+ cirrus,multi-amp-mode:
+ description: Hi-Z ASP port when more than one amplifier in system
+ type: boolean
+
+ cirrus,boost-ctl-select:
+ description: Boost converter control source selection
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 1
+ enum:
+ - 0 # Control Port
+ - 1 # Class
+ - 2 # Sync
+
+ cirrus,amp-pcm-inv:
+ description: Invert incoming PCM data when true
+ type: boolean
+
+ cirrus,imon-pol-inv:
+ description: Invert polarity of outbound IMON feedback when true
+ type: boolean
+
+ cirrus,vmon-pol-inv:
+ description: Invert polarity of outbound VMON feedback when true
+ type: boolean
+
+ cirrus,dcm-mode-enable:
+ description: Enable boost converter automatic Discontinuous Conduction Mode
+ type: boolean
+
+ cirrus,weak-fet-disable:
+ description: Reduce output driver strength in Weak-FET Drive Mode when true
+ type: boolean
+
+ cirrus,classh-wk-fet-delay-ms:
+ description: Weak-FET entry delay
+ default: 100
+ enum: [0, 5, 10, 50, 100, 200, 500, 1000]
+
+ cirrus,classh-weak-fet-thld-millivolt:
+ description: Weak-FET drive threshold
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700]
+
+ cirrus,temp-warn-threshold:
+ description: Overtemperature warning threshold
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 2
+ enum:
+ - 0 # 105°C
+ - 1 # 115°C
+ - 2 # 125°C
+ - 3 # 135°C
+
+ cirrus,irq-drive-select:
+ description: Interrupt output driver type
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 1
+ enum:
+ - 0 # open-drain
+ - 1 # push-pull
+
+ cirrus,irq-gpio-select:
+ description: Programmable IRQ pin selection
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum:
+ - 0 # PDM_DATA/SWIRE_SD/INT
+ - 1 # GPIO
+
+ cirrus,vpbr-config:
+ $ref: "#/$defs/vpbr-config"
+
+$defs:
+ vpbr-config:
+ description: Brownout prevention configuration sub-node
+ type: object
+ additionalProperties: false
+
+ properties:
+ cirrus,vpbr-en:
+ description: VBST brownout prevention enable
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 0
+ enum:
+ - 0 # disabled
+ - 1 # enabled
+
+ cirrus,vpbr-thld:
+ description: Initial VPBR threshold voltage
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 2
+ maximum: 31
+
+ cirrus,vpbr-atk-rate:
+ description: Attenuation attack step rate
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 7
+
+ cirrus,vpbr-atk-vol:
+ description: VP brownout prevention step size
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 7
+
+ cirrus,vpbr-max-attn:
+ description: Maximum attenuation during VP brownout prevention (dB)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 15
+
+ cirrus,vpbr-wait:
+ description: Delay between brownout clearance and attenuation release (ms)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 1
+ enum:
+ - 0 # 10
+ - 1 # 100
+ - 2 # 250
+ - 3 # 500
+
+ cirrus,vpbr-rel-rate:
+ description: Attenuation release step rate
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 7
+
+ cirrus,vpbr-mute-en:
+ description: Mute audio if maximum attenuation reached
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - VA-supply
+ - cirrus,boost-ctl-millivolt
+ - cirrus,boost-peak-milliamp
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ codec@40 {
+ compatible = "cirrus,cs35l36";
+ reg = <0x40>;
+ VA-supply = <&dummy_vreg>;
+ VP-supply = <&dummy_vreg>;
+ reset-gpios = <&gpio0 54 GPIO_ACTIVE_HIGH>;
+ interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+ cirrus,boost-ind-nanohenry = <1000>;
+ cirrus,boost-ctl-millivolt = <10000>;
+ cirrus,boost-peak-milliamp = <4500>;
+ cirrus,boost-ctl-select = <0>;
+ cirrus,classh-wk-fet-delay-ms = <100>;
+ cirrus,classh-weak-fet-thld-millivolt = <100>;
+ cirrus,temp-warn-threshold = <1>;
+ cirrus,multi-amp-mode;
+ cirrus,irq-drive-select = <1>;
+ cirrus,irq-gpio-select = <1>;
+
+ cirrus,vpbr-config {
+ cirrus,vpbr-en = <0>;
+ cirrus,vpbr-thld = <5>;
+ cirrus,vpbr-atk-rate = <2>;
+ cirrus,vpbr-atk-vol = <1>;
+ cirrus,vpbr-max-attn = <9>;
+ cirrus,vpbr-wait = <1>;
+ cirrus,vpbr-rel-rate = <5>;
+ cirrus,vpbr-mute-en = <0>;
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/cs35l36.txt b/Documentation/devicetree/bindings/sound/cs35l36.txt
deleted file mode 100644
index d34117b8558e..000000000000
--- a/Documentation/devicetree/bindings/sound/cs35l36.txt
+++ /dev/null
@@ -1,168 +0,0 @@
-CS35L36 Speaker Amplifier
-
-Required properties:
-
- - compatible : "cirrus,cs35l36"
-
- - reg : the I2C address of the device for I2C
-
- - VA-supply, VP-supply : power supplies for the device,
- as covered in
- Documentation/devicetree/bindings/regulator/regulator.txt.
-
- - cirrus,boost-ctl-millivolt : Boost Voltage Value. Configures the boost
- converter's output voltage in mV. The range is from 2550mV to 12000mV with
- increments of 50mV.
- (Default) VP
-
- - cirrus,boost-peak-milliamp : Boost-converter peak current limit in mA.
- Configures the peak current by monitoring the current through the boost FET.
- Range starts at 1600mA and goes to a maximum of 4500mA with increments of
- 50mA.
- (Default) 4.50 Amps
-
- - cirrus,boost-ind-nanohenry : Inductor estimation LBST reference value.
- Seeds the digital boost converter's inductor estimation block with the initial
- inductance value to reference.
-
- 1000 = 1uH (Default)
- 1200 = 1.2uH
-
-Optional properties:
- - cirrus,multi-amp-mode : Boolean to determine if there are more than
- one amplifier in the system. If more than one it is best to Hi-Z the ASP
- port to prevent bus contention on the output signal
-
- - cirrus,boost-ctl-select : Boost converter control source selection.
- Selects the source of the BST_CTL target VBST voltage for the boost
- converter to generate.
- 0x00 - Control Port Value
- 0x01 - Class H Tracking (Default)
- 0x10 - MultiDevice Sync Value
-
- - cirrus,amp-pcm-inv : Boolean to determine Amplifier will invert incoming
- PCM data
-
- - cirrus,imon-pol-inv : Boolean to determine Amplifier will invert the
- polarity of outbound IMON feedback data
-
- - cirrus,vmon-pol-inv : Boolean to determine Amplifier will invert the
- polarity of outbound VMON feedback data
-
- - cirrus,dcm-mode-enable : Boost converter automatic DCM Mode enable.
- This enables the digital boost converter to operate in a low power
- (Discontinuous Conduction) mode during low loading conditions.
-
- - cirrus,weak-fet-disable : Boolean : The strength of the output drivers is
- reduced when operating in a Weak-FET Drive Mode and must not be used to drive
- a large load.
-
- - cirrus,classh-wk-fet-delay : Weak-FET entry delay. Controls the delay
- (in ms) before the Class H algorithm switches to the weak-FET voltage
- (after the audio falls and remains below the value specified in WKFET_AMP_THLD).
-
- 0 = 0ms
- 1 = 5ms
- 2 = 10ms
- 3 = 50ms
- 4 = 100ms (Default)
- 5 = 200ms
- 6 = 500ms
- 7 = 1000ms
-
- - cirrus,classh-weak-fet-thld-millivolt : Weak-FET amplifier drive threshold.
- Configures the signal threshold at which the PWM output stage enters
- weak-FET operation. The range is 50mV to 700mV in 50mV increments.
-
- - cirrus,temp-warn-threshold : Amplifier overtemperature warning threshold.
- Configures the threshold at which the overtemperature warning condition occurs.
- When the threshold is met, the overtemperature warning attenuation is applied
- and the TEMP_WARN_EINT interrupt status bit is set.
- If TEMP_WARN_MASK = 0, INTb is asserted.
-
- 0 = 105C
- 1 = 115C
- 2 = 125C (Default)
- 3 = 135C
-
- - cirrus,irq-drive-select : Selects the driver type of the selected interrupt
- output.
-
- 0 = Open-drain
- 1 = Push-pull (Default)
-
- - cirrus,irq-gpio-select : Selects the pin to serve as the programmable
- interrupt output.
-
- 0 = PDM_DATA / SWIRE_SD / INT (Default)
- 1 = GPIO
-
-Optional properties for the "cirrus,vpbr-config" Sub-node
-
- - cirrus,vpbr-en : VBST brownout prevention enable. Configures whether the
- VBST brownout prevention algorithm is enabled or disabled.
-
- 0 = VBST brownout prevention disabled (default)
- 1 = VBST brownout prevention enabled
-
- See Section 7.31.1 VPBR Config for configuration options & further details
-
- - cirrus,vpbr-thld : Initial VPBR threshold. Configures the VP brownout
- threshold voltage
-
- - cirrus,cirrus,vpbr-atk-rate : Attenuation attack step rate. Configures the
- amount delay between consecutive volume attenuation steps when a brownout
- condition is present and the VP brownout condition is in an attacking state.
-
- - cirrus,vpbr-atk-vol : VP brownout prevention step size. Configures the VP
- brownout prevention attacking attenuation step size when operating in either
- digital volume or analog gain modes.
-
- - cirrus,vpbr-max-attn : Maximum attenuation that the VP brownout prevention
- can apply to the audio signal.
-
- - cirrus,vpbr-wait : Configures the delay time between a brownout condition
- no longer being present and the VP brownout prevention entering an attenuation
- release state.
-
- - cirrus,vpbr-rel-rate : Attenuation release step rate. Configures the delay
- between consecutive volume attenuation release steps when a brownout condition
- is not longer present and the VP brownout is in an attenuation release state.
-
- - cirrus,vpbr-mute-en : During the attack state, if the vpbr-max-attn value
- is reached, the error condition still remains, and this bit is set, the audio
- is muted.
-
-Example:
-
-cs35l36: cs35l36@40 {
- compatible = "cirrus,cs35l36";
- reg = <0x40>;
- VA-supply = <&dummy_vreg>;
- VP-supply = <&dummy_vreg>;
- reset-gpios = <&gpio0 54 0>;
- interrupt-parent = <&gpio8>;
- interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
-
- cirrus,boost-ind-nanohenry = <1000>;
- cirrus,boost-ctl-millivolt = <10000>;
- cirrus,boost-peak-milliamp = <4500>;
- cirrus,boost-ctl-select = <0x00>;
- cirrus,weak-fet-delay = <0x04>;
- cirrus,weak-fet-thld = <0x01>;
- cirrus,temp-warn-threshold = <0x01>;
- cirrus,multi-amp-mode;
- cirrus,irq-drive-select = <0x01>;
- cirrus,irq-gpio-select = <0x01>;
-
- cirrus,vpbr-config {
- cirrus,vpbr-en = <0x00>;
- cirrus,vpbr-thld = <0x05>;
- cirrus,vpbr-atk-rate = <0x02>;
- cirrus,vpbr-atk-vol = <0x01>;
- cirrus,vpbr-max-attn = <0x09>;
- cirrus,vpbr-wait = <0x01>;
- cirrus,vpbr-rel-rate = <0x05>;
- cirrus,vpbr-mute-en = <0x00>;
- };
-};
diff --git a/Documentation/devicetree/bindings/sound/dmic-codec.yaml b/Documentation/devicetree/bindings/sound/dmic-codec.yaml
index cc3c84dd4c26..83c23e029ea4 100644
--- a/Documentation/devicetree/bindings/sound/dmic-codec.yaml
+++ b/Documentation/devicetree/bindings/sound/dmic-codec.yaml
@@ -39,6 +39,10 @@ properties:
wakeup-delay-ms:
description: Delay (in ms) after enabling the DMIC
+ port:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+
required:
- compatible
diff --git a/Documentation/devicetree/bindings/sound/eukrea,asoc-tlv320.yaml b/Documentation/devicetree/bindings/sound/eukrea,asoc-tlv320.yaml
new file mode 100644
index 000000000000..24b793feb02d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/eukrea,asoc-tlv320.yaml
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/eukrea,asoc-tlv320.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Audio complex for Eukrea boards with tlv320aic23 codec.
+
+maintainers:
+ - Frank Li <Frank.Li@nxp.com>
+
+properties:
+ compatible:
+ const: eukrea,asoc-tlv320
+
+ eukrea,model:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ The user-visible name of this sound complex.
+
+ ssi-controller:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ The phandle of the SSI controller.
+
+ fsl,mux-int-port:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: |
+ The internal port of the i.MX audio muxer (AUDMUX).
+ Note: The AUDMUX port numbering should start at 1, which is consistent with
+ hardware manual.
+ minimum: 1
+ maximum: 8
+
+ fsl,mux-ext-port:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: |
+ The external port of the i.MX audio muxer.
+ Note: The AUDMUX port numbering should start at 1, which is consistent with
+ hardware manual.
+ minimum: 1
+ maximum: 8
+
+required:
+ - compatible
+ - eukrea,model
+ - ssi-controller
+ - fsl,mux-int-port
+ - fsl,mux-ext-port
+
+additionalProperties: false
+
+examples:
+ - |
+ sound {
+ compatible = "eukrea,asoc-tlv320";
+ eukrea,model = "imx51-eukrea-tlv320aic23";
+ ssi-controller = <&ssi2>;
+ fsl,mux-int-port = <2>;
+ fsl,mux-ext-port = <3>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt
deleted file mode 100644
index 6dfa88c4dc1e..000000000000
--- a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-Audio complex for Eukrea boards with tlv320aic23 codec.
-
-Required properties:
-
- - compatible : "eukrea,asoc-tlv320"
-
- - eukrea,model : The user-visible name of this sound complex.
-
- - ssi-controller : The phandle of the SSI controller.
-
- - fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX).
-
- - fsl,mux-ext-port : The external port of the i.MX audio muxer.
-
-Note: The AUDMUX port numbering should start at 1, which is consistent with
-hardware manual.
-
-Example:
-
- sound {
- compatible = "eukrea,asoc-tlv320";
- eukrea,model = "imx51-eukrea-tlv320aic23";
- ssi-controller = <&ssi2>;
- fsl,mux-int-port = <2>;
- fsl,mux-ext-port = <3>;
- };
diff --git a/Documentation/devicetree/bindings/sound/fsl,micfil.yaml b/Documentation/devicetree/bindings/sound/fsl,micfil.yaml
index c47b7a097490..4c7dadb310de 100644
--- a/Documentation/devicetree/bindings/sound/fsl,micfil.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,micfil.yaml
@@ -66,6 +66,10 @@ properties:
"#sound-dai-cells":
const: 0
+ port:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml b/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
index 61e8babed402..dc7f4afbb777 100644
--- a/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
+++ b/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
@@ -8,19 +8,22 @@ title: Loongson 7axxx/2kxxx ASoC audio sound card driver
maintainers:
- Yingkun Meng <mengyingkun@loongson.cn>
+ - Binbin Zhou <zhoubinbin@loongson.cn>
description:
The binding describes the sound card present in loongson
7axxx/2kxxx platform. The sound card is an ASoC component
which uses Loongson I2S controller to transfer the audio data.
+allOf:
+ - $ref: sound-card-common.yaml#
+
properties:
compatible:
- const: loongson,ls-audio-card
-
- model:
- $ref: /schemas/types.yaml#/definitions/string
- description: User specified audio sound card name
+ enum:
+ - loongson,ls-audio-card # Loongson-2K1000/Loongson-2K2000/LS7A
+ - loongson,ls2k0300-forever-pi-audio-card # CTCISZ Forever Pi
+ - loongson,ls2k0300-dl2k0300b-audio-card # ATK-DL2K0300B
mclk-fs:
$ref: simple-card.yaml#/definitions/mclk-fs
@@ -45,14 +48,25 @@ properties:
required:
- sound-dai
+ spkr-en-gpios:
+ maxItems: 1
+ description: The GPIO that enables the speakers
+
+ hp-ctl-gpios:
+ maxItems: 1
+ description: The GPIO that control the headphones
+
+ hp-det-gpios:
+ maxItems: 1
+ description: The GPIO that detect headphones are plugged in
+
required:
- compatible
- - model
- mclk-fs
- cpu
- codec
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
@@ -68,3 +82,28 @@ examples:
sound-dai = <&es8323>;
};
};
+
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ sound {
+ compatible = "loongson,ls2k0300-dl2k0300b-audio-card";
+ model = "loongson-audio";
+ mclk-fs = <512>;
+ hp-det-gpios = <&gpio 81 GPIO_ACTIVE_HIGH>;
+ spkr-en-gpios = <&gpio 86 GPIO_ACTIVE_HIGH>;
+ hp-ctl-gpios = <&gpio 87 GPIO_ACTIVE_HIGH>;
+ audio-routing =
+ "Headphone", "LOUT1",
+ "Headphone", "ROUT1",
+ "Speaker", "LOUT2",
+ "Speaker", "ROUT2";
+
+ cpu {
+ sound-dai = <&i2s>;
+ };
+
+ codec {
+ sound-dai = <&es8388>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml b/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml
index da79510bb2d9..51e23c189f7a 100644
--- a/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml
@@ -14,9 +14,12 @@ allOf:
properties:
compatible:
- const: loongson,ls2k1000-i2s
+ enum:
+ - loongson,ls2k0300-i2s
+ - loongson,ls2k1000-i2s
reg:
+ minItems: 1
items:
- description: Loongson I2S controller Registers.
- description: APB DMA config register for Loongson I2S controller.
@@ -49,6 +52,23 @@ required:
unevaluatedProperties: false
+if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - loongson,ls2k1000-i2s
+
+then:
+ properties:
+ reg:
+ minItems: 2
+
+else:
+ properties:
+ reg:
+ maxItems: 1
+
examples:
- |
#include <dt-bindings/clock/loongson,ls2k-clk.h>
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml b/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml
new file mode 100644
index 000000000000..1b7451655476
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mtk-btcvsd-snd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek ALSA BT SCO CVSD/MSBC
+
+maintainers:
+ - Luca Leonardo Scorcia <l.scorcia@gmail.com>
+
+properties:
+ compatible:
+ const: mediatek,mtk-btcvsd-snd
+
+ reg:
+ items:
+ - description: PKV region
+ - description: SRAM_BANK2 region
+
+ interrupts:
+ items:
+ - description: BT-SCO interrupt
+
+ mediatek,infracfg:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of the infracfg controller
+
+ mediatek,offset:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description: Array of register offsets and masks
+ items:
+ - description: infra_misc_offset
+ - description: infra_conn_bt_cvsd_mask
+ - description: cvsd_mcu_read_offset
+ - description: cvsd_mcu_write_offset
+ - description: cvsd_packet_indicator_offset
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - mediatek,infracfg
+ - mediatek,offset
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ mtk-btcvsd-snd@18000000 {
+ compatible = "mediatek,mtk-btcvsd-snd";
+ reg = <0x18000000 0x1000>,
+ <0x18080000 0x8000>;
+ interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_LOW>;
+ mediatek,infracfg = <&infrasys>;
+ mediatek,offset = <0xf00 0x800 0xfd0 0xfd4 0xfd8>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt b/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt
deleted file mode 100644
index 679e44839b48..000000000000
--- a/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-Mediatek ALSA BT SCO CVSD/MSBC Driver
-
-Required properties:
-- compatible = "mediatek,mtk-btcvsd-snd";
-- reg: register location and size of PKV and SRAM_BANK2
-- interrupts: should contain BTSCO interrupt
-- mediatek,infracfg: the phandles of INFRASYS
-- mediatek,offset: Array contains of register offset and mask
- infra_misc_offset,
- infra_conn_bt_cvsd_mask,
- cvsd_mcu_read_offset,
- cvsd_mcu_write_offset,
- cvsd_packet_indicator_offset
-
-Example:
-
- mtk-btcvsd-snd@18000000 {
- compatible = "mediatek,mtk-btcvsd-snd";
- reg=<0 0x18000000 0 0x1000>,
- <0 0x18080000 0 0x8000>;
- interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_LOW>;
- mediatek,infracfg = <&infrasys>;
- mediatek,offset = <0xf00 0x800 0xfd0 0xfd4 0xfd8>;
- };
diff --git a/Documentation/devicetree/bindings/sound/omap-dmic.txt b/Documentation/devicetree/bindings/sound/omap-dmic.txt
deleted file mode 100644
index 418e30e72e89..000000000000
--- a/Documentation/devicetree/bindings/sound/omap-dmic.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-* Texas Instruments OMAP4+ Digital Microphone Module
-
-Required properties:
-- compatible: "ti,omap4-dmic"
-- reg: Register location and size as an array:
- <MPU access base address, size>,
- <L3 interconnect address, size>;
-- interrupts: Interrupt number for DMIC
-- ti,hwmods: Name of the hwmod associated with OMAP dmic IP
-
-Example:
-
-dmic: dmic@4012e000 {
- compatible = "ti,omap4-dmic";
- reg = <0x4012e000 0x7f>, /* MPU private access */
- <0x4902e000 0x7f>; /* L3 Interconnect */
- interrupts = <0 114 0x4>;
- interrupt-parent = <&gic>;
- ti,hwmods = "dmic";
-};
diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml
index a899c4e7c1c9..33bc23b6176a 100644
--- a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml
@@ -14,7 +14,13 @@ description:
properties:
compatible:
- const: qcom,msm8916-wcd-digital-codec
+ oneOf:
+ - items:
+ - enum:
+ - qcom,sdm660-wcd-digital-codec
+ - const: qcom,msm8916-wcd-digital-codec
+
+ - const: qcom,msm8916-wcd-digital-codec
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml
index 94e7a1860977..be47dbdb2e92 100644
--- a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml
@@ -14,7 +14,16 @@ description:
properties:
compatible:
- const: qcom,pm8916-wcd-analog-codec
+ oneOf:
+ - items:
+ - enum:
+ - qcom,pm660l-wcd-analog-codec
+ - const: qcom,pm8953-wcd-analog-codec
+
+ - enum:
+ - qcom,pm8916-wcd-analog-codec
+ - qcom,pm8950-wcd-analog-codec
+ - qcom,pm8953-wcd-analog-codec
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml b/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml
index 2fb95544db8b..4878c424ef03 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml
@@ -21,6 +21,43 @@ properties:
'#sound-dai-cells':
const: 1
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+# Digital Audio Interfaces
+patternProperties:
+ '^dai@[0-9a-f]+$':
+ type: object
+ description:
+ Q6DSP Digital Audio Interfaces.
+
+ properties:
+ reg:
+ maxItems: 1
+ description:
+ Digital Audio Interface ID
+
+ clocks:
+ minItems: 1
+ maxItems: 2
+
+ clock-names:
+ minItems: 1
+ items:
+ - enum: [bclk, mclk]
+ - const: mclk
+
+ dependencies:
+ clocks: [clock-names]
+
+ required:
+ - reg
+
+ additionalProperties: false
+
required:
- compatible
- '#sound-dai-cells'
@@ -29,7 +66,20 @@ unevaluatedProperties: false
examples:
- |
+ #include <dt-bindings/sound/qcom,q6afe.h>
+
dais {
compatible = "qcom,q6apm-lpass-dais";
#sound-dai-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dai@10 {
+ reg = <PRIMARY_MI2S_RX>;
+ clocks = <&q6prmcc LPASS_CLK_ID_PRI_MI2S_IBIT
+ LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_CLK_ID_MCLK_1
+ LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+ clock-names = "bclk", "mclk";
+ };
};
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml
index 2b27d6c8f58f..3b03e2acd67e 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml
@@ -127,7 +127,7 @@ patternProperties:
contains:
# MI2S DAI ID range PRIMARY_MI2S_RX - QUATERNARY_MI2S_TX and
# QUINARY_MI2S_RX - QUINARY_MI2S_TX and
- # LPI_MI2S_RX_0 - SENARY_MI2S_TX
+ # LPI_MI2S_RX_0 - LPI_MI2S_TX_6
items:
oneOf:
- minimum: 16
@@ -135,7 +135,7 @@ patternProperties:
- minimum: 127
maximum: 128
- minimum: 137
- maximum: 148
+ maximum: 152
then:
required:
- qcom,sd-lines
diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
index dae440ecab59..c1bd19299763 100644
--- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
@@ -24,12 +24,15 @@ properties:
- items:
- enum:
- qcom,eliza-sndcard
+ - qcom,hawi-sndcard
- qcom,kaanapali-sndcard
+ - qcom,sm8475-sndcard
- qcom,sm8550-sndcard
- qcom,sm8650-sndcard
- qcom,sm8750-sndcard
- const: qcom,sm8450-sndcard
- enum:
+ - ayaneo,pocket-s2-sndcard
- fairphone,fp4-sndcard
- fairphone,fp5-sndcard
- qcom,apq8096-sndcard
@@ -45,6 +48,7 @@ properties:
- qcom,qrb5165-rb5-sndcard
- qcom,sc7180-qdsp6-sndcard
- qcom,sc8280xp-sndcard
+ - qcom,sdm660-sndcard
- qcom,sdm845-sndcard
- qcom,sm8250-sndcard
- qcom,sm8450-sndcard
diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml
new file mode 100644
index 000000000000..00a6a05e9443
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,wsa8855.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm WSA8855 stereo smart speaker amplifier
+
+maintainers:
+ - Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
+ - Prasad Kumpatla <prasad.kumpatla@oss.qualcomm.com>
+
+description:
+ WSA885X is a Qualcomm Aqstic stereo smart speaker amplifier. It uses a PCM
+ audio interface, an I2C control interface, and a Class-H amplifier path for
+ high efficiency, low output noise, and low idle power consumption.
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ const: qcom,wsa8855
+
+ reg:
+ maxItems: 1
+
+ '#sound-dai-cells':
+ const: 0
+
+ powerdown-gpios:
+ description: GPIO controlling the SD_N powerdown pin.
+ maxItems: 1
+
+ reset-gpios:
+ description: GPIO controlling the SD_N powerdown pin.
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ vdd-1p8-supply: true
+
+ vdd-io-supply: true
+
+ qcom,battery-config:
+ description:
+ Battery topology connected to the speaker amplifier. 1S indicates one
+ battery cell in series, while 2S indicates two battery cells in series.
+ $ref: /schemas/types.yaml#/definitions/string
+ default: 1s
+ enum:
+ - 1s
+ - 2s
+
+required:
+ - compatible
+ - reg
+ - '#sound-dai-cells'
+ - interrupts
+ - vdd-1p8-supply
+ - vdd-io-supply
+
+oneOf:
+ - required:
+ - powerdown-gpios
+ - required:
+ - reset-gpios
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ speaker@c {
+ compatible = "qcom,wsa8855";
+ reg = <0x0c>;
+ #sound-dai-cells = <0>;
+ powerdown-gpios = <&tlmm 11 GPIO_ACTIVE_LOW>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <77 IRQ_TYPE_EDGE_FALLING>;
+ vdd-1p8-supply = <&vreg_l2g_1p8>;
+ vdd-io-supply = <&vreg_l1g_1p2>;
+ qcom,battery-config = "1s";
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/sound/realtek,rt1015.yaml b/Documentation/devicetree/bindings/sound/realtek,rt1015.yaml
index 880196081a60..3c44ebf93a44 100644
--- a/Documentation/devicetree/bindings/sound/realtek,rt1015.yaml
+++ b/Documentation/devicetree/bindings/sound/realtek,rt1015.yaml
@@ -19,7 +19,7 @@ properties:
realtek,power-up-delay-ms:
description: Set a delay time for flush work to be completed,
- this vlaue is adjustable depending on platform.
+ this value is adjustable depending on platform.
maxItems: 1
required:
diff --git a/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml b/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml
index 240d90402e4f..72723f067b2a 100644
--- a/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml
@@ -23,9 +23,9 @@ allOf:
then:
properties:
clocks:
- minItems: 7
+ minItems: 6
clock-names:
- minItems: 7
+ minItems: 6
else:
properties:
clocks:
@@ -43,26 +43,50 @@ properties:
maxItems: 1
clocks:
- minItems: 4
- items:
- - description: clock for I2S sysclk
- - description: clock for I2S bclk
- - description: clock for I2S bus
- - description: clock for I2S controller
- - description: clock for I2S sysclk divider
- - description: clock for I2S common sysclk
- - description: clock for I2S common bclk
+ oneOf:
+ - items:
+ - description: clock for I2S sysclk
+ - description: clock for I2S bclk
+ - description: clock for I2S bus
+ - description: clock for I2S controller
+ - items:
+ - description: clock for I2S sysclk
+ - description: clock for I2S bclk
+ - description: clock for I2S bus
+ - description: clock for I2S controller
+ - description: clock for I2S common sysclk
+ - description: clock for I2S common bclk
+ - items:
+ - description: clock for I2S sysclk
+ - description: clock for I2S bclk
+ - description: clock for I2S bus
+ - description: clock for I2S controller
+ - description: clock for I2S sysclk divider
+ - description: clock for I2S common sysclk
+ - description: clock for I2S common bclk
clock-names:
- minItems: 4
- items:
- - const: sysclk
- - const: bclk
- - const: bus
- - const: func
- - const: sysclk_div
- - const: c_sysclk
- - const: c_bclk
+ oneOf:
+ - items:
+ - const: sysclk
+ - const: bclk
+ - const: bus
+ - const: func
+ - items:
+ - const: sysclk
+ - const: bclk
+ - const: bus
+ - const: func
+ - const: c_sysclk
+ - const: c_bclk
+ - items:
+ - const: sysclk
+ - const: bclk
+ - const: bus
+ - const: func
+ - const: sysclk_div
+ - const: c_sysclk
+ - const: c_bclk
dmas:
minItems: 1
diff --git a/Documentation/devicetree/bindings/sound/st,sta32x.txt b/Documentation/devicetree/bindings/sound/st,sta32x.txt
index 52265fb757c5..266b6fc9f009 100644
--- a/Documentation/devicetree/bindings/sound/st,sta32x.txt
+++ b/Documentation/devicetree/bindings/sound/st,sta32x.txt
@@ -73,7 +73,7 @@ Optional properties:
- st,odd-pwm-speed-mode:
If present, PWM speed mode run on odd speed mode (341.3 kHz) on all
- channels. If not present, normal PWM spped mode (384 kHz) will be used.
+ channels. If not present, normal PWM speed mode (384 kHz) will be used.
- st,invalid-input-detect-mute:
If present, automatic invalid input detect mute is enabled.
diff --git a/Documentation/devicetree/bindings/sound/ti,omap4-dmic.yaml b/Documentation/devicetree/bindings/sound/ti,omap4-dmic.yaml
new file mode 100644
index 000000000000..773b9bf2f1c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ti,omap4-dmic.yaml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/ti,omap4-dmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments OMAP4+ Digital Microphone Module
+
+maintainers:
+ - Peter Ujfalusi <peter.ujfalusi@ti.com>
+
+properties:
+ compatible:
+ const: ti,omap4-dmic
+
+ reg:
+ items:
+ - description: MPU access base address
+ - description: L3 interconnect address
+
+ reg-names:
+ items:
+ - const: mpu
+ - const: dma
+
+ interrupts:
+ maxItems: 1
+
+ dmas:
+ maxItems: 1
+
+ dma-names:
+ items:
+ - const: up_link
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - interrupts
+ - dmas
+ - dma-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ dmic@0 {
+ compatible = "ti,omap4-dmic";
+ reg = <0x0 0x7f>, /* MPU private access */
+ <0x4902e000 0x7f>; /* L3 Interconnect */
+ reg-names = "mpu", "dma";
+ interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&sdma 67>;
+ dma-names = "up_link";
+ };
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml
index 4d951ece394e..dffc41d5f7de 100644
--- a/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml
@@ -24,6 +24,10 @@ properties:
description:
a GPIO spec for the MUTE pin.
+ port:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+
required:
- compatible
- wlf,mute-gpios
diff --git a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h
index 45850f2d4342..ca84952c3884 100644
--- a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h
+++ b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h
@@ -152,6 +152,10 @@
#define LPI_MI2S_TX_4 146
#define SENARY_MI2S_RX 147
#define SENARY_MI2S_TX 148
+#define LPI_MI2S_RX_5 149
+#define LPI_MI2S_TX_5 150
+#define LPI_MI2S_RX_6 151
+#define LPI_MI2S_TX_6 152
#define LPASS_CLK_ID_PRI_MI2S_IBIT 1
#define LPASS_CLK_ID_PRI_MI2S_EBIT 2
@@ -236,8 +240,7 @@
#define LPASS_HW_AVTIMER_VOTE 101
#define LPASS_HW_MACRO_VOTE 102
#define LPASS_HW_DCODEC_VOTE 103
-
-#define Q6AFE_MAX_CLK_ID 104
+#define LPASS_HW_LPR_VOTE 104
#define LPASS_CLK_ATTRIBUTE_INVALID 0x0
#define LPASS_CLK_ATTRIBUTE_COUPLE_NO 0x1
diff --git a/include/linux/platform_data/omap-twl4030.h b/include/linux/platform_data/omap-twl4030.h
deleted file mode 100644
index 7fcb55fe21c9..000000000000
--- a/include/linux/platform_data/omap-twl4030.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/**
- * omap-twl4030.h - ASoC machine driver for TI SoC based boards with twl4030
- * codec, header.
- *
- * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com
- * All rights reserved.
- *
- * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
- */
-
-#ifndef _OMAP_TWL4030_H_
-#define _OMAP_TWL4030_H_
-
-/* To select if only one channel is connected in a stereo port */
-#define OMAP_TWL4030_LEFT (1 << 0)
-#define OMAP_TWL4030_RIGHT (1 << 1)
-
-struct omap_tw4030_pdata {
- const char *card_name;
- /* Voice port is connected to McBSP3 */
- bool voice_connected;
-
- /* The driver will parse the connection flags if this flag is set */
- bool custom_routing;
- /* Flags to indicate connected audio ports. */
- u8 has_hs;
- u8 has_hf;
- u8 has_predriv;
- u8 has_carkit;
- bool has_ear;
-
- bool has_mainmic;
- bool has_submic;
- bool has_hsmic;
- bool has_carkitmic;
- bool has_digimic0;
- bool has_digimic1;
- u8 has_linein;
-};
-
-#endif /* _OMAP_TWL4030_H_ */
diff --git a/include/sound/aw88399.h b/include/sound/aw88399.h
new file mode 100644
index 000000000000..a1e0de6be8ea
--- /dev/null
+++ b/include/sound/aw88399.h
@@ -0,0 +1,621 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * linux/sound/aw88399.h -- Platform data for AW88399
+ *
+ * Copyright (c) 2023 AWINIC Technology CO., LTD
+ *
+ * Author: Weidong Wang <wangweidong.a@awinic.com>
+ */
+
+#ifndef __SOUND_AW88399_H
+#define __SOUND_AW88399_H
+
+#include <linux/mutex.h>
+#include <linux/workqueue.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
+
+#define AW88399_START_RETRIES (5)
+#define AW88399_START_WORK_DELAY_MS (0)
+
+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 aw_device;
+struct aw_container;
+struct aw_cali_desc;
+struct gpio_desc;
+struct i2c_client;
+struct regmap;
+
+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;
+ bool bsts_unreliable;
+ bool fw_needs_reload;
+};
+
+int aw_dev_check_syspll(struct aw_device *aw_dev);
+void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable);
+int aw_dev_get_dsp_status(struct aw_device *aw_dev);
+int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value);
+int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc);
+int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name);
+void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute);
+void aw88399_dev_set_channel(struct aw88399 *aw88399, int channel);
+void aw88399_hw_reset(struct aw88399 *aw88399);
+int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap);
+extern const struct regmap_config aw88399_remap_config;
+int aw88399_request_firmware_file(struct aw88399 *aw88399);
+void aw88399_start(struct aw88399 *aw88399, bool sync_start);
+void aw88399_startup_work(struct work_struct *work);
+int aw88399_stop(struct aw_device *aw_dev);
+
+#endif /* __SOUND_AW88399_H */
diff --git a/include/sound/hda-mlink.h b/include/sound/hda-mlink.h
index fed69998c93f..ba35f03576b9 100644
--- a/include/sound/hda-mlink.h
+++ b/include/sound/hda-mlink.h
@@ -9,6 +9,22 @@
struct hdac_bus;
struct hdac_ext_link;
+/**
+ * enum hda_bus_ml_link_type - mlink link type, used by SOF link DMA
+ * allocator constraints (see struct sof_intel_hda_dev).
+ *
+ * @HDA_BUS_ML_LINK_HDA: non-alt link, i.e. HDA codec or iDisp
+ * @HDA_BUS_ML_LINK_SDW: alt link, SoundWire
+ * @HDA_BUS_ML_LINK_UAOL: alt link, USB Audio Offload
+ * @HDA_BUS_ML_LINK_OTHER: alt link, SSP or DMIC
+ */
+enum hda_bus_ml_link_type {
+ HDA_BUS_ML_LINK_HDA,
+ HDA_BUS_ML_LINK_SDW,
+ HDA_BUS_ML_LINK_UAOL,
+ HDA_BUS_ML_LINK_OTHER,
+};
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_MLINK)
int hda_bus_ml_init(struct hdac_bus *bus);
@@ -49,11 +65,12 @@ int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num);
int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
int channel_mask, int stream_id, int dir);
-void hda_bus_ml_put_all(struct hdac_bus *bus);
void hda_bus_ml_reset_losidv(struct hdac_bus *bus);
int hda_bus_ml_resume(struct hdac_bus *bus);
int hda_bus_ml_suspend(struct hdac_bus *bus);
+enum hda_bus_ml_link_type hda_bus_ml_link_get_type(struct hdac_ext_link *hlink);
+
struct hdac_ext_link *hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus);
struct hdac_ext_link *hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus);
struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus);
@@ -169,11 +186,13 @@ hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
return 0;
}
-static inline void hda_bus_ml_put_all(struct hdac_bus *bus) { }
static inline void hda_bus_ml_reset_losidv(struct hdac_bus *bus) { }
static inline int hda_bus_ml_resume(struct hdac_bus *bus) { return 0; }
static inline int hda_bus_ml_suspend(struct hdac_bus *bus) { return 0; }
+static inline enum hda_bus_ml_link_type
+hda_bus_ml_link_get_type(struct hdac_ext_link *hlink) { return HDA_BUS_ML_LINK_HDA; }
+
static inline struct hdac_ext_link *
hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus) { return NULL; }
diff --git a/include/sound/sdca_asoc.h b/include/sound/sdca_asoc.h
index ca35d5a44370..d3024c3b38b9 100644
--- a/include/sound/sdca_asoc.h
+++ b/include/sound/sdca_asoc.h
@@ -25,6 +25,8 @@ struct snd_soc_dai_driver;
struct snd_soc_dai_ops;
struct snd_soc_dapm_route;
struct snd_soc_dapm_widget;
+struct snd_soc_pcm_stream;
+struct sdca_entity;
/* convenient macro to handle the mono volume in 7.8 fixed format representation */
#define SDCA_SINGLE_Q78_TLV(xname, xreg, xmin, xmax, xstep, tlv_array) \
@@ -82,6 +84,11 @@ int sdca_asoc_populate_component(struct device *dev,
struct snd_soc_dai_driver **dai_drv, int *num_dai_drv,
const struct snd_soc_dai_ops *ops);
+int sdca_asoc_populate_rate_format(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct snd_soc_pcm_stream *stream);
+
int sdca_asoc_set_constraints(struct device *dev, struct regmap *regmap,
struct sdca_function_data *function,
struct snd_pcm_substream *substream,
diff --git a/include/sound/sdca_fdl.h b/include/sound/sdca_fdl.h
index dc33927b82bd..bc3600cdd2ec 100644
--- a/include/sound/sdca_fdl.h
+++ b/include/sound/sdca_fdl.h
@@ -83,6 +83,10 @@ static inline int sdca_fdl_alloc_state(struct sdca_interrupt *interrupt)
return 0;
}
+static inline void sdca_fdl_free_state(struct sdca_interrupt *interrupt)
+{
+}
+
static inline int sdca_fdl_process(struct sdca_interrupt *interrupt)
{
return 0;
diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h
index b1489178b0ef..fb931ae735a2 100644
--- a/include/sound/sdca_function.h
+++ b/include/sound/sdca_function.h
@@ -1469,5 +1469,7 @@ struct sdca_control_range *sdca_selector_find_range(struct device *dev,
struct sdca_cluster *sdca_id_find_cluster(struct device *dev,
struct sdca_function_data *function,
const int id);
+struct sdca_entity *sdca_find_entity_by_label(struct sdca_function_data *function,
+ const char *entity_label);
#endif
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index 915e6ae5f68d..bd8c3a033577 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -181,7 +181,7 @@ void simple_util_canonicalize_platform(struct snd_soc_dai_link_component *platfo
void simple_util_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
int is_single_links);
-void simple_util_clean_reference(struct snd_soc_card *card);
+void simple_util_clean_reference(struct simple_util_priv *priv);
void simple_util_parse_convert(struct device_node *np, char *prefix,
struct simple_util_data *data);
@@ -189,18 +189,37 @@ bool simple_util_is_convert_required(const struct simple_util_data *data);
int simple_util_get_sample_fmt(struct simple_util_data *data);
-int simple_util_parse_routing(struct snd_soc_card *card,
- char *prefix);
-int simple_util_parse_widgets(struct snd_soc_card *card,
- char *prefix);
-int simple_util_parse_pin_switches(struct snd_soc_card *card,
- char *prefix);
+int simple_util_parse_property(struct simple_util_priv *priv,
+ int (*func)(struct snd_soc_card *card, const char *propname),
+ char *prefix, char *property);
+static inline int simple_util_parse_routing(struct simple_util_priv *priv, char *prefix)
+{
+ return simple_util_parse_property(priv, snd_soc_of_parse_audio_routing,
+ prefix, "routing");
+}
+
+static inline int simple_util_parse_widgets(struct simple_util_priv *priv, char *prefix)
+{
+ return simple_util_parse_property(priv, snd_soc_of_parse_audio_simple_widgets,
+ prefix, "widgets");
+}
+
+static inline int simple_util_parse_pin_switches(struct simple_util_priv *priv, char *prefix)
+{
+ return simple_util_parse_property(priv, snd_soc_of_parse_pin_switches,
+ prefix, "pin-switches");
+}
+
+static inline int simple_util_parse_aux_devs(struct simple_util_priv *priv, char *prefix)
+{
+ return simple_util_parse_property(priv, snd_soc_of_parse_aux_devs,
+ prefix, "aux-devs");
+}
int simple_util_init_jack(struct snd_soc_card *card,
struct simple_util_jack *sjack,
int is_hp, char *prefix, char *pin);
-int simple_util_init_aux_jacks(struct simple_util_priv *priv,
- char *prefix);
+int simple_util_init_aux_jacks(struct snd_soc_card *card, char *prefix);
int simple_util_init_priv(struct simple_util_priv *priv,
struct link_info *li);
void simple_util_remove(struct platform_device *pdev);
diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h
index 79c21966220b..9b28e9aef4f1 100644
--- a/include/sound/soc_sdw_utils.h
+++ b/include/sound/soc_sdw_utils.h
@@ -44,6 +44,18 @@
struct asoc_sdw_codec_info;
+struct asoc_sdw_mc_private {
+ struct snd_soc_card card;
+ struct snd_soc_jack sdw_headset;
+ struct device *headset_codec_dev; /* only one headset per card */
+ struct device *amp_dev1, *amp_dev2;
+ bool append_dai_type;
+ bool ignore_internal_dmic;
+ void *private;
+ unsigned long mc_quirk;
+ int codec_info_list_count;
+};
+
struct asoc_sdw_dai_info {
const bool direction[2]; /* playback & capture support */
const char *codec_name;
@@ -88,25 +100,13 @@ struct asoc_sdw_codec_info {
int (*codec_card_late_probe)(struct snd_soc_card *card);
- int (*count_sidecar)(struct snd_soc_card *card,
+ int (*count_sidecar)(struct asoc_sdw_mc_private *ctx,
int *num_dais, int *num_devs);
int (*add_sidecar)(struct snd_soc_card *card,
struct snd_soc_dai_link **dai_links,
struct snd_soc_codec_conf **codec_conf);
};
-struct asoc_sdw_mc_private {
- struct snd_soc_card card;
- struct snd_soc_jack sdw_headset;
- struct device *headset_codec_dev; /* only one headset per card */
- struct device *amp_dev1, *amp_dev2;
- bool append_dai_type;
- bool ignore_internal_dmic;
- void *private;
- unsigned long mc_quirk;
- int codec_info_list_count;
-};
-
struct asoc_sdw_endpoint {
struct list_head list;
@@ -182,7 +182,8 @@ struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks
const struct snd_soc_acpi_endpoint *new);
int asoc_sdw_get_dai_type(u32 type);
-int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
+int asoc_sdw_parse_sdw_endpoints(struct device *dev,
+ struct asoc_sdw_mc_private *ctx,
struct snd_soc_aux_dev *soc_aux,
struct asoc_sdw_dailink *soc_dais,
struct asoc_sdw_endpoint *soc_ends,
@@ -235,7 +236,7 @@ int asoc_sdw_es9356_amp_init(struct snd_soc_card *card,
int asoc_sdw_es9356_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
/* CS AMP support */
-int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card,
+int asoc_sdw_bridge_cs35l56_count_sidecar(struct asoc_sdw_mc_private *ctx,
int *num_dais, int *num_devs);
int asoc_sdw_bridge_cs35l56_add_sidecar(struct snd_soc_card *card,
struct snd_soc_dai_link **dai_links,
diff --git a/include/sound/sof/dai-amd.h b/include/sound/sof/dai-amd.h
index 59cd014392c1..e2107da6558f 100644
--- a/include/sound/sof/dai-amd.h
+++ b/include/sound/sof/dai-amd.h
@@ -18,6 +18,7 @@ struct sof_ipc_dai_acp_params {
uint32_t fsync_rate; /* FSYNC frequency in Hz */
uint32_t tdm_slots;
uint32_t tdm_mode;
+ uint32_t format;
} __packed;
/* ACPDMIC Configuration Request - SOF_IPC_DAI_AMD_CONFIG */
diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h
index 36809f712723..e3fe492e78f5 100644
--- a/include/sound/sof/dai.h
+++ b/include/sound/sof/dai.h
@@ -90,6 +90,8 @@ enum sof_ipc_dai_type {
SOF_DAI_AMD_HS_VIRTUAL, /**< AMD ACP HS VIRTUAL */
SOF_DAI_IMX_MICFIL, /** < i.MX MICFIL PDM */
SOF_DAI_AMD_SDW, /**< AMD ACP SDW */
+ SOF_DAI_INTEL_UAOL, /**< Intel UAOL */
+ SOF_DAI_AMD_I2S, /**< AMD ACP I2S */
};
/* general purpose DAI configuration */
@@ -121,6 +123,7 @@ struct sof_ipc_dai_config {
struct sof_ipc_dai_mtk_afe_params afe;
struct sof_ipc_dai_micfil_params micfil;
struct sof_ipc_dai_acp_sdw_params acp_sdw;
+ struct sof_ipc_dai_acp_params acp_i2s;
};
} __packed;
diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h
index 4e406dc22f31..6c2c3a5fc90d 100644
--- a/include/sound/sof/header.h
+++ b/include/sound/sof/header.h
@@ -179,7 +179,7 @@ struct sof_ipc_compound_hdr {
uint32_t count; /**< count of 0 means end of compound sequence */
} __packed;
-/**
+/*
* OOPS header architecture specific data.
*/
struct sof_ipc_dsp_oops_arch_hdr {
@@ -187,7 +187,7 @@ struct sof_ipc_dsp_oops_arch_hdr {
uint32_t totalsize; /* Total size of oops message */
} __packed;
-/**
+/*
* OOPS header platform specific data.
*/
struct sof_ipc_dsp_oops_plat_hdr {
diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h
index 4554e5e8cab5..cea3d9453b84 100644
--- a/include/sound/sof/ipc4/header.h
+++ b/include/sound/sof/ipc4/header.h
@@ -187,6 +187,10 @@ enum sof_ipc4_pipeline_state {
#define SOF_IPC4_GLB_PIPE_EXT_CORE_ID_MASK GENMASK(23, 20)
#define SOF_IPC4_GLB_PIPE_EXT_CORE_ID(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_CORE_ID_SHIFT)
+#define SOF_IPC4_GLB_PIPE_PAYLOAD_SHIFT 29
+#define SOF_IPC4_GLB_PIPE_PAYLOAD_MASK BIT(29)
+#define SOF_IPC4_GLB_PIPE_PAYLOAD(x) ((x) << SOF_IPC4_GLB_PIPE_PAYLOAD_SHIFT)
+
/* pipeline set state ipc msg */
#define SOF_IPC4_GLB_PIPE_STATE_ID_SHIFT 16
#define SOF_IPC4_GLB_PIPE_STATE_ID_MASK GENMASK(23, 16)
@@ -536,12 +540,63 @@ enum sof_ipc4_notification_type {
SOF_IPC4_NOTIFY_TYPE_LAST,
};
+enum sof_ipc4_resource_type {
+ SOF_IPC4_MODULE_INSTANCE,
+ SOF_IPC4_PIPELINE,
+ SOF_IPC4_GATEWAY,
+ SOF_IPC4_EDF_TASK,
+ SOF_IPC4_INVALID_RESOURCE_TYPE,
+};
+
+enum sof_ipc4_event_type {
+ /* Underrun detected by the Mixer */
+ SOF_IPC4_MIXER_UNDERRUN_DETECTED = 1,
+ /* Error caught during data processing */
+ SOF_IPC4_PROCESS_DATA_ERROR = 3,
+ /* Underrun detected by gateway. */
+ SOF_IPC4_GATEWAY_UNDERRUN_DETECTED = 6,
+ /* Overrun detected by gateway */
+ SOF_IPC4_GATEWAY_OVERRUN_DETECTED,
+};
+
+/**
+ * struct sof_ipc4_process_data_error_event_data - process data error event payload
+ * @error_code: Error code returned by data processing function
+ */
+struct sof_ipc4_process_data_error_event_data {
+ uint32_t error_code;
+};
+
+/**
+ * struct sof_ipc4_mixer_underrun_event_data - mixer underrun event payload
+ * @eos_flag: Indicates EndOfStream
+ * @data_mixed: Data processed by module (in bytes)
+ * @expected_data_mixed: Expected data to be processed (in bytes)
+ */
+struct sof_ipc4_mixer_underrun_event_data {
+ uint32_t eos_flag;
+ uint32_t data_mixed;
+ uint32_t expected_data_mixed;
+};
+
+/**
+ * union sof_ipc4_resource_event_data - resource event specific payload
+ * @dws: Raw event data payload as six dwords
+ * @process_data_error: SOF_IPC4_PROCESS_DATA_ERROR payload
+ * @mixer_underrun: SOF_IPC4_MIXER_UNDERRUN_DETECTED payload
+ */
+union sof_ipc4_resource_event_data {
+ uint32_t dws[6];
+ struct sof_ipc4_process_data_error_event_data process_data_error;
+ struct sof_ipc4_mixer_underrun_event_data mixer_underrun;
+};
+
struct sof_ipc4_notify_resource_data {
uint32_t resource_type;
uint32_t resource_id;
uint32_t event_type;
uint32_t reserved;
- uint32_t data[6];
+ union sof_ipc4_resource_event_data data;
} __packed __aligned(4);
#define SOF_IPC4_DEBUG_DESCRIPTOR_SIZE 12 /* 3 x u32 */
@@ -654,11 +709,81 @@ enum sof_ipc4_mod_init_ext_obj_id {
SOF_IPC4_MOD_INIT_DATA_ID_MAX = SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA,
};
-/* DP module memory configuration data object for ext_init object array */
+/* DP module memory configuration data object for object array */
struct sof_ipc4_mod_init_ext_dp_memory_data {
+ u32 domain_id; /* userspace domain ID */
+ u32 stack_bytes; /* required stack size in bytes */
+ u32 heap_bytes; /* required heap size in bytes */
+} __packed __aligned(4);
+
+/*
+ * This set of macros are very similar to the set above, but these are
+ * for building payload to SOF_IPC4_GLB_CREATE_PIPELINE message.
+ *
+ * Macros for creating struct sof_ipc4_glb_pipe_payload payload with
+ * its associated data. struct sof_ipc4_glb_pipe_payload should be the
+ * first piece of payload following SOF_IPC4_GLB_CREATE_PIPELINE msg,
+ * and its existence is indicated with SOF_IPC4_GLB_PIPE_PAYLOAD bit.
+ *
+ * The macros below apply to sof_ipc4_glb_pipe_payload.word0
+ */
+#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_SHIFT 0
+#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_MASK GENMASK(23, 0)
+#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS(x) ((x) << SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_SHIFT)
+
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_SHIFT 24
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_MASK BIT(24)
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_SHIFT)
+
+struct sof_ipc4_glb_pipe_payload {
+ u32 word0;
+ u32 rsvd1;
+ u32 rsvd2;
+} __packed __aligned(4);
+
+/*
+ * SOF_IPC4_GLB_CREATE_PIPELINE payload may be followed by arbitrary
+ * number of object array objects. SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY-bit
+ * indicates that an array object follows struct
+ * sof_ipc4_glb_pipe_payload.
+ *
+ * The object header's SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST-bit in struct
+ * sof_ipc4_glb_pipe_ext_object indicates if the array is continued
+ * with another object. The header has also fields to identify the
+ * object, SOF_IPC4_GLB_PIPE_EXT_OBJ_ID, and to indicate the object's
+ * size in 32-bit words, SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS, not
+ * including the header itself.
+ *
+ * The macros below apply to sof_ipc4_glb_pipe_ext_object.header
+ */
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_SHIFT 0
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_MASK BIT(0)
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_SHIFT)
+
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_SHIFT 1
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_MASK GENMASK(15, 1)
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_SHIFT)
+
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_SHIFT 16
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_MASK GENMASK(31, 16)
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_SHIFT)
+
+struct sof_ipc4_glb_pipe_ext_object {
+ u32 header;
+ u32 data[];
+} __packed __aligned(4);
+
+enum sof_ipc4_glb_pipe_ext_obj_id {
+ SOF_IPC4_GLB_PIPE_DATA_ID_INVALID = 0,
+ SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA,
+ SOF_IPC4_GLB_PIPE_DATA_ID_MAX = SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA,
+};
+
+/* Pipeline memory configuration data object for ext_init object array */
+struct sof_ipc4_glb_pipe_ext_obj_memory_data {
u32 domain_id; /* userspace domain ID */
- u32 stack_bytes; /* stack size in bytes, 0 means default size */
- u32 heap_bytes; /* stack size in bytes, 0 means default size */
+ u32 stack_bytes; /* stack size in bytes */
+ u32 heap_bytes; /* heap size in bytes */
} __packed __aligned(4);
/** @}*/
diff --git a/include/sound/tlv320aic32x4.h b/include/sound/tlv320aic32x4.h
deleted file mode 100644
index b779d671a995..000000000000
--- a/include/sound/tlv320aic32x4.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * tlv320aic32x4.h -- TLV320AIC32X4 Soc Audio driver platform data
- *
- * Copyright 2011 Vista Silicon S.L.
- *
- * Author: Javier Martin <javier.martin@vista-silicon.com>
- */
-
-#ifndef _AIC32X4_PDATA_H
-#define _AIC32X4_PDATA_H
-
-#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
-
-struct aic32x4_setup_data {
- unsigned int gpio_func[5];
-};
-#endif
diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h
index f4a7baadb44d..d42adbef0478 100644
--- a/include/uapi/sound/sof/tokens.h
+++ b/include/uapi/sound/sof/tokens.h
@@ -111,8 +111,8 @@
#define SOF_TKN_COMP_SCHED_DOMAIN 418
#define SOF_TKN_COMP_DOMAIN_ID 419
-#define SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT 420
-#define SOF_TKN_COMP_STACK_BYTES_REQUIREMENT 421
+#define SOF_TKN_COMP_STACK_BYTES_REQUIREMENT 420
+#define SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT 421
/* SSP */
#define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500
@@ -223,6 +223,7 @@
#define SOF_TKN_AMD_ACPI2S_RATE 1700
#define SOF_TKN_AMD_ACPI2S_CH 1701
#define SOF_TKN_AMD_ACPI2S_TDM_MODE 1702
+#define SOF_TKN_AMD_ACPI2S_FORMAT 1703
/* MICFIL PDM */
#define SOF_TKN_IMX_MICFIL_RATE 2000
diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c
index 88e4230d66c3..77a8fe42b70c 100644
--- a/sound/soc/amd/acp-config.c
+++ b/sound/soc/amd/acp-config.c
@@ -379,5 +379,17 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[] = {
};
EXPORT_SYMBOL(snd_soc_acpi_amd_acp70_sof_machines);
+struct snd_soc_acpi_mach snd_soc_acpi_amd_acp7x_sof_machines[] = {
+ {
+ .id = "AMDI1010",
+ .drv_name = "acp7x-dsp",
+ .pdata = &acp_quirk_data,
+ .fw_filename = "sof-acp7x.ri",
+ .sof_tplg_filename = "sof-acp7x.tplg",
+ },
+ {},
+};
+EXPORT_SYMBOL(snd_soc_acpi_amd_acp7x_sof_machines);
+
MODULE_DESCRIPTION("AMD ACP Machine Configuration Module");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c
index 283a674c7e2c..bb58a9d34993 100644
--- a/sound/soc/amd/acp/acp-i2s.c
+++ b/sound/soc/amd/acp/acp-i2s.c
@@ -686,6 +686,10 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d
return 0;
}
+static const u64 acp_i2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
.startup = acp_i2s_startup,
.hw_params = acp_i2s_hwparams,
@@ -693,6 +697,8 @@ const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
.trigger = acp_i2s_trigger,
.set_fmt = acp_i2s_set_fmt,
.set_tdm_slot = acp_i2s_set_tdm_slot,
+ .auto_selectable_formats = &acp_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, "SND_SOC_ACP_COMMON");
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index ef784cca13f2..01a0aaa60246 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -938,15 +938,10 @@ static int acp_max98388_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai =
snd_soc_card_get_codec_dai(card,
MAX98388_CODEC_DAI);
- int ret;
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF);
- if (ret < 0)
- return ret;
-
- return ret;
+ return snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF);
}
static const struct snd_soc_ops acp_max98388_ops = {
diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c
index f83708755ed1..98771323eace 100644
--- a/sound/soc/amd/acp/acp-pci.c
+++ b/sound/soc/amd/acp/acp-pci.c
@@ -118,17 +118,10 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
if (!chip)
return -ENOMEM;
- if (pci_enable_device(pci))
+ if (pcim_enable_device(pci))
return dev_err_probe(&pci->dev, -ENODEV,
"pci_enable_device failed\n");
- ret = pci_request_regions(pci, "AMD ACP3x audio");
- if (ret < 0) {
- dev_err(&pci->dev, "pci_request_regions failed\n");
- ret = -ENOMEM;
- goto disable_pci;
- }
-
pci_set_master(pci);
chip->acp_rev = pci->revision;
@@ -161,24 +154,21 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
break;
default:
dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision);
- ret = -EINVAL;
- goto release_regions;
+ return -EINVAL;
}
chip->flag = flag;
addr = pci_resource_start(pci, 0);
- chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0));
- if (!chip->base) {
- ret = -ENOMEM;
- goto release_regions;
- }
+ chip->base = pcim_iomap_region(pci, 0, "AMD ACP3x audio");
+ if (IS_ERR(chip->base))
+ return PTR_ERR(chip->base);
chip->addr = addr;
chip->acp_hw_ops_init(chip);
ret = acp_hw_init(chip);
if (ret)
- goto release_regions;
+ goto de_init;
ret = devm_request_irq(dev, pci->irq, irq_handler,
IRQF_SHARED, "ACP_I2S_IRQ", chip);
@@ -214,10 +204,6 @@ skip_pdev_creation:
de_init:
acp_hw_deinit(chip);
-release_regions:
- pci_release_regions(pci);
-disable_pci:
- pci_disable_device(pci);
return ret;
};
diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
index e8b6819cc4b4..6eac42bac855 100644
--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
@@ -432,7 +432,7 @@ static int soc_card_dai_links_create(struct snd_soc_card *card)
if (!soc_aux)
return -ENOMEM;
- ret = asoc_sdw_parse_sdw_endpoints(card, soc_aux, soc_dais, soc_ends, &num_confs);
+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, soc_aux, soc_dais, soc_ends, &num_confs);
if (ret < 0)
return ret;
@@ -521,15 +521,15 @@ static int mc_probe(struct platform_device *pdev)
dmi_check_system(soc_sdw_quirk_table);
if (quirk_override != -1) {
- dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
+ dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
soc_sdw_quirk, quirk_override);
soc_sdw_quirk = quirk_override;
}
- log_quirks(card->dev);
+ log_quirks(&pdev->dev);
ctx->mc_quirk = soc_sdw_quirk;
- dev_dbg(card->dev, "legacy quirk 0x%lx\n", ctx->mc_quirk);
+ dev_dbg(&pdev->dev, "legacy quirk 0x%lx\n", ctx->mc_quirk);
/* reset amp_num to ensure amp_num++ starts from 0 in each probe */
for (i = 0; i < ctx->codec_info_list_count; i++)
codec_info_list[i].amp_num = 0;
@@ -546,12 +546,12 @@ static int mc_probe(struct platform_device *pdev)
for (i = 0; i < ctx->codec_info_list_count; i++)
amp_num += codec_info_list[i].amp_num;
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL,
" cfg-amp:%d", amp_num);
if (!card->components)
return -ENOMEM;
if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC) {
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"%s mic:acp-dmic cfg-mics:%d",
card->components,
1);
@@ -560,9 +560,9 @@ static int mc_probe(struct platform_device *pdev)
}
/* Register the card */
- ret = devm_snd_soc_register_card(card->dev, card);
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
- dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
+ dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed %d\n", ret);
asoc_sdw_mc_dailink_exit_loop(card);
return ret;
}
@@ -580,8 +580,8 @@ static void mc_remove(struct platform_device *pdev)
}
static const struct platform_device_id mc_id_table[] = {
- { "amd_sdw", },
- {}
+ { .name = "amd_sdw" },
+ { }
};
MODULE_DEVICE_TABLE(platform, mc_id_table);
diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c
index a423853f3a97..a9cd1f335167 100644
--- a/sound/soc/amd/acp/acp-sdw-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c
@@ -303,7 +303,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
if (!sof_aux)
return -ENOMEM;
- ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_devs);
+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_devs);
if (ret < 0)
return ret;
@@ -388,12 +388,12 @@ static int mc_probe(struct platform_device *pdev)
dmi_check_system(sof_sdw_quirk_table);
if (quirk_override != -1) {
- dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
+ dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
sof_sdw_quirk, quirk_override);
sof_sdw_quirk = quirk_override;
}
- log_quirks(card->dev);
+ log_quirks(&pdev->dev);
ctx->mc_quirk = sof_sdw_quirk;
/* reset amp_num to ensure amp_num++ starts from 0 in each probe */
@@ -412,15 +412,15 @@ static int mc_probe(struct platform_device *pdev)
for (i = 0; i < ctx->codec_info_list_count; i++)
amp_num += codec_info_list[i].amp_num;
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL,
" cfg-amp:%d", amp_num);
if (!card->components)
return -ENOMEM;
/* Register the card */
- ret = devm_snd_soc_register_card(card->dev, card);
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
- dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
+ dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed %d\n", ret);
asoc_sdw_mc_dailink_exit_loop(card);
return ret;
}
@@ -438,8 +438,8 @@ static void mc_remove(struct platform_device *pdev)
}
static const struct platform_device_id mc_id_table[] = {
- { "amd_sof_sdw", },
- {}
+ { .name = "amd_sof_sdw" },
+ { }
};
MODULE_DEVICE_TABLE(platform, mc_id_table);
diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c
index 36ecef7013b9..8874151e159a 100644
--- a/sound/soc/amd/acp/acp-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sof-mach.c
@@ -128,31 +128,31 @@ static int acp_sof_probe(struct platform_device *pdev)
static const struct platform_device_id board_ids[] = {
{
.name = "rt5682-rt1019",
- .driver_data = (kernel_ulong_t)&sof_rt5682_rt1019_data
+ .driver_data = (kernel_ulong_t)&sof_rt5682_rt1019_data,
},
{
.name = "rt5682-max",
- .driver_data = (kernel_ulong_t)&sof_rt5682_max_data
+ .driver_data = (kernel_ulong_t)&sof_rt5682_max_data,
},
{
.name = "rt5682s-max",
- .driver_data = (kernel_ulong_t)&sof_rt5682s_max_data
+ .driver_data = (kernel_ulong_t)&sof_rt5682s_max_data,
},
{
.name = "rt5682s-rt1019",
- .driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data
+ .driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data,
},
{
.name = "nau8825-max",
- .driver_data = (kernel_ulong_t)&sof_nau8825_data
+ .driver_data = (kernel_ulong_t)&sof_nau8825_data,
},
{
.name = "rt5682s-hs-rt1019",
- .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data
+ .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data,
},
{
.name = "nau8821-max",
- .driver_data = (kernel_ulong_t)&sof_nau8821_max98388_data
+ .driver_data = (kernel_ulong_t)&sof_nau8821_max98388_data,
},
{ }
};
diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h
index 5b6362103ca0..b602a983feb7 100644
--- a/sound/soc/amd/mach-config.h
+++ b/sound/soc/amd/mach-config.h
@@ -28,6 +28,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_sdw_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp7x_sof_machines[];
struct config_entry {
u32 flags;
diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c
index 352485dd98b1..b0147e88ba54 100644
--- a/sound/soc/amd/raven/acp3x-i2s.c
+++ b/sound/soc/amd/raven/acp3x-i2s.c
@@ -250,11 +250,17 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream,
return ret;
}
+static const u64 acp3x_i2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
static const struct snd_soc_dai_ops acp3x_i2s_dai_ops = {
.hw_params = acp3x_i2s_hwparams,
.trigger = acp3x_i2s_trigger,
.set_fmt = acp3x_i2s_set_fmt,
.set_tdm_slot = acp3x_i2s_set_tdm_slot,
+ .auto_selectable_formats = &acp3x_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_component_driver acp3x_dai_component = {
diff --git a/sound/soc/amd/vangogh/acp5x-i2s.c b/sound/soc/amd/vangogh/acp5x-i2s.c
index bf719f628617..dbfb87e2fe92 100644
--- a/sound/soc/amd/vangogh/acp5x-i2s.c
+++ b/sound/soc/amd/vangogh/acp5x-i2s.c
@@ -337,11 +337,17 @@ static int acp5x_i2s_trigger(struct snd_pcm_substream *substream,
return ret;
}
+static const u64 acp5x_i2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
static const struct snd_soc_dai_ops acp5x_i2s_dai_ops = {
.hw_params = acp5x_i2s_hwparams,
.trigger = acp5x_i2s_trigger,
.set_fmt = acp5x_i2s_set_fmt,
.set_tdm_slot = acp5x_i2s_set_tdm_slot,
+ .auto_selectable_formats = &acp5x_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_component_driver acp5x_dai_component = {
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index b62dd77b588d..1b03a17f4daa 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -781,12 +781,12 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
}
},
{
- .driver_data = &acp6x_card,
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "Vivobook_ASUSLaptop M6501RR_M6501RR"),
- }
- },
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Vivobook_ASUSLaptop M6501RR_M6501RR"),
+ }
+ },
{
.driver_data = &acp6x_card,
.matches = {
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index 492165c0e1ea..be702b2942a5 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -133,12 +133,17 @@ struct mca_cluster {
struct clk *clk_parent;
struct dma_chan *dma_chans[SNDRV_PCM_STREAM_LAST + 1];
- bool port_started[SNDRV_PCM_STREAM_LAST + 1];
- int port_driver; /* The cluster driving this cluster's port */
+ bool clk_provider;
+
+ bool port_clk_started[SNDRV_PCM_STREAM_LAST + 1];
+ int port_clk_driver; /* The cluster driving this cluster's port */
bool clocks_in_use[SNDRV_PCM_STREAM_LAST + 1];
struct device_link *pd_link;
+ /* In case of clock consumer FE */
+ int syncgen_in_use;
+
unsigned int bclk_ratio;
/* Masks etc. picked up via the set_tdm_slot method */
@@ -157,7 +162,7 @@ struct mca_data {
struct reset_control *rstc;
struct device_link *pd_link;
- /* Mutex for accessing port_driver of foreign clusters */
+ /* Mutex for accessing port_clk_driver of foreign clusters */
struct mutex port_mutex;
int nclusters;
@@ -210,16 +215,22 @@ static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd,
SERDES_STATUS_EN | SERDES_STATUS_RST,
SERDES_STATUS_RST);
/*
- * Experiments suggest that it takes at most ~1 us
- * for the bit to clear, so wait 2 us for good measure.
+ * The SERDES cluster needs a bit of time to reset itself
+ * and settle before we start poking it. This is... slow...
*/
- udelay(2);
+ udelay(25);
WARN_ON(readl_relaxed(cl->base + serdes_unit + REG_SERDES_STATUS) &
SERDES_STATUS_RST);
mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
FIELD_PREP(SERDES_CONF_SYNC_SEL, 0));
mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
FIELD_PREP(SERDES_CONF_SYNC_SEL, cl->no + 1));
+ /*
+ * ADMAC gets started right after this. This delay seems
+ * to be needed for that to be reliable, e.g. ensure the
+ * clock is stable?
+ */
+ udelay(100);
break;
default:
break;
@@ -256,11 +267,29 @@ static int mca_fe_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
+static int mca_fe_get_portmask(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dpcm *dpcm;
+ int mask = 0;
+
+ for_each_dpcm_be(fe, substream->stream, dpcm) {
+ int no = mca_dai_to_cluster(snd_soc_rtd_to_cpu(dpcm->be, 0))->no;
+
+ mask |= 1 << no;
+ }
+
+ return mask;
+}
+
static int mca_fe_enable_clocks(struct mca_cluster *cl)
{
struct mca_data *mca = cl->host;
int ret;
+ if (!cl->clk_provider)
+ return -EINVAL;
+
ret = clk_prepare_enable(cl->clk_parent);
if (ret) {
dev_err(mca->dev,
@@ -311,7 +340,7 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl)
for (i = 0; i < mca->nclusters; i++) {
be_cl = &mca->clusters[i];
- if (be_cl->port_driver != cl->no)
+ if (be_cl->port_clk_driver != cl->no)
continue;
for_each_pcm_streams(stream) {
@@ -323,59 +352,79 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl)
return false;
}
-static int mca_be_prepare(struct snd_pcm_substream *substream,
+static int mca_be_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mca_cluster *cl = mca_dai_to_cluster(dai);
struct mca_data *mca = cl->host;
struct mca_cluster *fe_cl;
- int ret;
- if (cl->port_driver < 0)
+ if (cl->port_clk_driver < 0)
return -EINVAL;
- fe_cl = &mca->clusters[cl->port_driver];
-
/*
- * Typically the CODECs we are paired with will require clocks
- * to be present at time of unmute with the 'mute_stream' op
- * or at time of DAPM widget power-up. We need to enable clocks
- * here at the latest (frontend prepare would be too late).
+ * We are operating on a foreign cluster here, but since we
+ * belong to the same PCM, accesses should have been
+ * synchronized at ASoC level.
*/
- if (!mca_fe_clocks_in_use(fe_cl)) {
- ret = mca_fe_enable_clocks(fe_cl);
- if (ret < 0)
- return ret;
- }
+ fe_cl = &mca->clusters[cl->port_clk_driver];
+ if (!mca_fe_clocks_in_use(fe_cl))
+ return 0; /* Nothing to do */
- cl->clocks_in_use[substream->stream] = true;
+ cl->clocks_in_use[substream->stream] = false;
+
+ if (!mca_fe_clocks_in_use(fe_cl))
+ mca_fe_disable_clocks(fe_cl);
return 0;
}
-static int mca_be_hw_free(struct snd_pcm_substream *substream,
+static int mca_fe_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mca_cluster *cl = mca_dai_to_cluster(dai);
struct mca_data *mca = cl->host;
- struct mca_cluster *fe_cl;
- if (cl->port_driver < 0)
- return -EINVAL;
+ if (cl->clk_provider)
+ return 0;
- /*
- * We are operating on a foreign cluster here, but since we
- * belong to the same PCM, accesses should have been
- * synchronized at ASoC level.
- */
- fe_cl = &mca->clusters[cl->port_driver];
- if (!mca_fe_clocks_in_use(fe_cl))
- return 0; /* Nothing to do */
+ /* Turn on the cluster power domain if not already in use */
+ if (!cl->syncgen_in_use) {
+ int port = ffs(mca_fe_get_portmask(substream));
- cl->clocks_in_use[substream->stream] = false;
+ cl->pd_link = device_link_add(mca->dev, cl->pd_dev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (!cl->pd_link) {
+ dev_err(mca->dev,
+ "cluster %d: unable to prop-up power domain\n", cl->no);
+ return -EINVAL;
+ }
- if (!mca_fe_clocks_in_use(fe_cl))
- mca_fe_disable_clocks(fe_cl);
+ mca_modify(cl, REG_SYNCGEN_MCLK_SEL, SYNCGEN_MCLK_SEL, BIT(port));
+ mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN,
+ SYNCGEN_STATUS_EN);
+ }
+ cl->syncgen_in_use |= 1 << substream->stream;
+
+ return 0;
+}
+
+static int mca_fe_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mca_cluster *cl = mca_dai_to_cluster(dai);
+
+ if (cl->clk_provider)
+ return 0;
+
+ cl->syncgen_in_use &= ~(1 << substream->stream);
+ if (cl->syncgen_in_use)
+ return 0;
+
+ mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN, 0);
+ if (cl->pd_link)
+ device_link_del(cl->pd_link);
return 0;
}
@@ -390,7 +439,7 @@ static unsigned int mca_crop_mask(unsigned int mask, int nchans)
static int mca_configure_serdes(struct mca_cluster *cl, int serdes_unit,
unsigned int mask, int slots, int nchans,
- int slot_width, bool is_tx, int port)
+ int slot_width, bool is_tx, int portmask)
{
__iomem void *serdes_base = cl->base + serdes_unit;
u32 serdes_conf, serdes_conf_mask;
@@ -449,7 +498,7 @@ static int mca_configure_serdes(struct mca_cluster *cl, int serdes_unit,
serdes_base + REG_RX_SERDES_SLOTMASK);
writel_relaxed(~((u32)mca_crop_mask(mask, nchans)),
serdes_base + REG_RX_SERDES_SLOTMASK + 0x4);
- writel_relaxed(1 << port,
+ writel_relaxed(portmask,
serdes_base + REG_RX_SERDES_PORT);
}
@@ -505,9 +554,18 @@ static int mca_fe_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
u32 serdes_conf = 0;
u32 bitstart;
- if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) !=
- SND_SOC_DAIFMT_BP_FP)
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
+ cl->clk_provider = true;
+ break;
+
+ case SND_SOC_DAIFMT_BC_FC:
+ cl->clk_provider = false;
+ break;
+
+ default:
goto err;
+ }
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
@@ -564,24 +622,6 @@ static int mca_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
return 0;
}
-static int mca_fe_get_port(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
- struct snd_soc_pcm_runtime *be;
- struct snd_soc_dpcm *dpcm;
-
- be = NULL;
- for_each_dpcm_be(fe, substream->stream, dpcm) {
- be = dpcm->be;
- break;
- }
-
- if (!be)
- return -EINVAL;
-
- return mca_dai_to_cluster(snd_soc_rtd_to_cpu(be, 0))->no;
-}
-
static int mca_fe_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -595,7 +635,7 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream,
unsigned long bclk_ratio;
unsigned int tdm_slots, tdm_slot_width, tdm_mask;
u32 regval, pad;
- int ret, port, nchans_ceiled;
+ int ret, portmask, nchans_ceiled;
if (!cl->tdm_slot_width) {
/*
@@ -644,13 +684,13 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream,
tdm_mask = (1 << tdm_slots) - 1;
}
- port = mca_fe_get_port(substream);
- if (port < 0)
- return port;
+ portmask = mca_fe_get_portmask(substream);
+ if (!portmask)
+ return -EINVAL;
ret = mca_configure_serdes(cl, is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF,
tdm_mask, tdm_slots, params_channels(params),
- tdm_slot_width, is_tx, port);
+ tdm_slot_width, is_tx, portmask);
if (ret)
return ret;
@@ -699,6 +739,19 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static const u64 mca_fe_selectable_formats[] =
+{
+ /* pattern 1 */
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_NB_IF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+
+ /* pattern 2 */
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_NF
+};
+
static const struct snd_soc_dai_ops mca_fe_ops = {
.startup = mca_fe_startup,
.set_fmt = mca_fe_set_fmt,
@@ -706,66 +759,128 @@ static const struct snd_soc_dai_ops mca_fe_ops = {
.set_tdm_slot = mca_fe_set_tdm_slot,
.hw_params = mca_fe_hw_params,
.trigger = mca_fe_trigger,
+ .prepare = mca_fe_prepare,
+ .hw_free = mca_fe_hw_free,
+ .auto_selectable_formats = mca_fe_selectable_formats,
+ .num_auto_selectable_formats = ARRAY_SIZE(mca_fe_selectable_formats),
};
-static bool mca_be_started(struct mca_cluster *cl)
+/*
+ * Is there a FE attached which will be feeding this port's clocks?
+ */
+static bool mca_be_clk_started(struct mca_cluster *cl)
{
int stream;
for_each_pcm_streams(stream)
- if (cl->port_started[stream])
+ if (cl->port_clk_started[stream])
return true;
return false;
}
-static int mca_be_startup(struct snd_pcm_substream *substream,
+static struct snd_soc_pcm_runtime *mca_be_get_fe(struct snd_soc_pcm_runtime *be,
+ int stream)
+{
+ struct snd_soc_pcm_runtime *fe = NULL;
+ struct snd_soc_dpcm *dpcm;
+
+ for_each_dpcm_fe(be, stream, dpcm) {
+ if (fe && dpcm->fe != fe) {
+ dev_err(be->dev, "many FE per one BE unsupported\n");
+ return NULL;
+ }
+
+ fe = dpcm->fe;
+ }
+
+ return fe;
+}
+
+static int mca_be_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);
- struct snd_soc_pcm_runtime *fe;
+ struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream);
struct mca_cluster *cl = mca_dai_to_cluster(dai);
- struct mca_cluster *fe_cl;
struct mca_data *mca = cl->host;
- struct snd_soc_dpcm *dpcm;
+ struct mca_cluster *fe_cl, *fe_clk_cl;
+ int ret;
- fe = NULL;
+ fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0));
- for_each_dpcm_fe(be, substream->stream, dpcm) {
- if (fe && dpcm->fe != fe) {
- dev_err(mca->dev, "many FE per one BE unsupported\n");
- return -EINVAL;
- }
+ if (!fe_cl->clk_provider)
+ return 0;
- fe = dpcm->fe;
+ if (cl->port_clk_driver < 0)
+ return 0;
+
+ fe_clk_cl = &mca->clusters[cl->port_clk_driver];
+
+ /*
+ * Typically the CODECs we are paired with will require clocks
+ * to be present at time of unmute with the 'mute_stream' op
+ * or at time of DAPM widget power-up. We need to enable clocks
+ * here at the latest (frontend prepare would be too late).
+ */
+ if (!mca_fe_clocks_in_use(fe_clk_cl)) {
+ ret = mca_fe_enable_clocks(fe_clk_cl);
+ if (ret < 0)
+ return ret;
}
+ cl->clocks_in_use[substream->stream] = true;
+
+ return 0;
+}
+
+static int mca_be_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream);
+ struct mca_cluster *cl = mca_dai_to_cluster(dai);
+ struct mca_cluster *fe_cl;
+ struct mca_data *mca = cl->host;
+
if (!fe)
return -EINVAL;
-
fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0));
- if (mca_be_started(cl)) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no),
+ cl->base + REG_PORT_DATA_SEL);
+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_TX_DATA,
+ PORT_ENABLES_TX_DATA);
+ }
+
+ if (!fe_cl->clk_provider)
+ return 0;
+
+ if (mca_be_clk_started(cl)) {
/*
* Port is already started in the other direction.
* Make sure there isn't a conflict with another cluster
- * driving the port.
+ * driving the port clocks.
*/
- if (cl->port_driver != fe_cl->no)
+ if (cl->port_clk_driver != fe_cl->no)
return -EINVAL;
- cl->port_started[substream->stream] = true;
+ cl->port_clk_started[substream->stream] = true;
return 0;
}
- writel_relaxed(PORT_ENABLES_CLOCKS | PORT_ENABLES_TX_DATA,
- cl->base + REG_PORT_ENABLES);
writel_relaxed(FIELD_PREP(PORT_CLOCK_SEL, fe_cl->no + 1),
cl->base + REG_PORT_CLOCK_SEL);
+
writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no),
cl->base + REG_PORT_DATA_SEL);
+
+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_CLOCKS,
+ PORT_ENABLES_CLOCKS);
+
scoped_guard(mutex, &mca->port_mutex)
- cl->port_driver = fe_cl->no;
- cl->port_started[substream->stream] = true;
+ cl->port_clk_driver = fe_cl->no;
+ cl->port_clk_started[substream->stream] = true;
return 0;
}
@@ -773,20 +888,34 @@ static int mca_be_startup(struct snd_pcm_substream *substream,
static void mca_be_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream);
struct mca_cluster *cl = mca_dai_to_cluster(dai);
+ struct mca_cluster *fe_cl;
struct mca_data *mca = cl->host;
- cl->port_started[substream->stream] = false;
+ if (!fe)
+ return;
+ fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0));
- if (!mca_be_started(cl)) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_TX_DATA, 0);
+ writel_relaxed(0, cl->base + REG_PORT_DATA_SEL);
+ }
+
+ if (!fe_cl->clk_provider)
+ return;
+
+ cl->port_clk_started[substream->stream] = false;
+ if (!mca_be_clk_started(cl)) {
/*
* Were we the last direction to shutdown?
- * Turn off the lights.
+ * Turn off the lights (clocks).
*/
- writel_relaxed(0, cl->base + REG_PORT_ENABLES);
- writel_relaxed(0, cl->base + REG_PORT_DATA_SEL);
+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_CLOCKS, 0);
+ writel_relaxed(0, cl->base + REG_PORT_CLOCK_SEL);
scoped_guard(mutex, &mca->port_mutex)
- cl->port_driver = -1;
+ cl->port_clk_driver = -1;
}
}
@@ -1092,7 +1221,7 @@ static int apple_mca_probe(struct platform_device *pdev)
cl->host = mca;
cl->no = i;
cl->base = base + CLUSTER_STRIDE * i;
- cl->port_driver = -1;
+ cl->port_clk_driver = -1;
cl->clk_parent = of_clk_get(pdev->dev.of_node, i);
if (IS_ERR(cl->clk_parent)) {
dev_err(&pdev->dev, "unable to obtain clock %d: %ld\n",
diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c
index 762199faf872..d9ad262ec44d 100644
--- a/sound/soc/atmel/atmel-i2s.c
+++ b/sound/soc/atmel/atmel-i2s.c
@@ -540,12 +540,16 @@ static int atmel_i2s_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const u64 atmel_i2s_selectable_formats = SND_SOC_POSSIBLE_DAIFMT_I2S;
+
static const struct snd_soc_dai_ops atmel_i2s_dai_ops = {
.probe = atmel_i2s_dai_probe,
.prepare = atmel_i2s_prepare,
.trigger = atmel_i2s_trigger,
.hw_params = atmel_i2s_hw_params,
.set_fmt = atmel_i2s_set_dai_fmt,
+ .auto_selectable_formats = &atmel_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver atmel_i2s_dai = {
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 89098f41679c..f4f886bf678d 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -825,6 +825,11 @@ static int atmel_ssc_resume(struct snd_soc_component *component)
#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
+static const u64 atmel_ssc_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
.startup = atmel_ssc_startup,
.shutdown = atmel_ssc_shutdown,
@@ -833,6 +838,8 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
.hw_params = atmel_ssc_hw_params,
.set_fmt = atmel_ssc_set_dai_fmt,
.set_clkdiv = atmel_ssc_set_dai_clkdiv,
+ .auto_selectable_formats = &atmel_ssc_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver atmel_ssc_dai = {
diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c
index 0f4021c6c588..df3e5ef8fa61 100644
--- a/sound/soc/atmel/atmel_wm8904.c
+++ b/sound/soc/atmel/atmel_wm8904.c
@@ -82,32 +82,33 @@ static struct snd_soc_card atmel_asoc_wm8904_card = {
static int atmel_asoc_wm8904_dt_init(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct device_node *codec_np, *cpu_np;
struct snd_soc_card *card = &atmel_asoc_wm8904_card;
struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
int ret;
if (!np) {
- dev_err(&pdev->dev, "only device tree supported\n");
+ dev_err(dev, "only device tree supported\n");
return -EINVAL;
}
ret = snd_soc_of_parse_card_name(card, "atmel,model");
if (ret) {
- dev_err(&pdev->dev, "failed to parse card name\n");
+ dev_err(dev, "failed to parse card name\n");
return ret;
}
ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing");
if (ret) {
- dev_err(&pdev->dev, "failed to parse audio routing\n");
+ dev_err(dev, "failed to parse audio routing\n");
return ret;
}
cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
if (!cpu_np) {
- dev_err(&pdev->dev, "failed to get dai and pcm info\n");
+ dev_err(dev, "failed to get dai and pcm info\n");
ret = -EINVAL;
return ret;
}
@@ -117,7 +118,7 @@ static int atmel_asoc_wm8904_dt_init(struct platform_device *pdev)
codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
if (!codec_np) {
- dev_err(&pdev->dev, "failed to get codec info\n");
+ dev_err(dev, "failed to get codec info\n");
ret = -EINVAL;
return ret;
}
diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c
index 17d138bb9064..a832dee73ac7 100644
--- a/sound/soc/atmel/mchp-i2s-mcc.c
+++ b/sound/soc/atmel/mchp-i2s-mcc.c
@@ -912,6 +912,13 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const u64 mchp_i2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_GATED |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = {
.probe = mchp_i2s_mcc_dai_probe,
.set_sysclk = mchp_i2s_mcc_set_sysclk,
@@ -922,6 +929,8 @@ static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = {
.hw_free = mchp_i2s_mcc_hw_free,
.set_fmt = mchp_i2s_mcc_set_dai_fmt,
.set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot,
+ .auto_selectable_formats = &mchp_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
#define MCHP_I2SMCC_RATES SNDRV_PCM_RATE_8000_192000
diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c
index ec7233ce1f78..a6a9b5e6cd95 100644
--- a/sound/soc/atmel/mchp-pdmc.c
+++ b/sound/soc/atmel/mchp-pdmc.c
@@ -741,6 +741,8 @@ static int mchp_pdmc_pcm_new(struct snd_soc_pcm_runtime *rtd,
return ret;
}
+static const u64 mchp_selectable_formats = SND_SOC_POSSIBLE_DAIFMT_PDM;
+
static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = {
.probe = mchp_pdmc_dai_probe,
.set_fmt = mchp_pdmc_set_fmt,
@@ -748,6 +750,8 @@ static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = {
.hw_params = mchp_pdmc_hw_params,
.trigger = mchp_pdmc_trigger,
.pcm_new = &mchp_pdmc_pcm_new,
+ .auto_selectable_formats = &mchp_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver mchp_pdmc_dai = {
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index 81abe2e18402..78346cd7959c 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -42,7 +42,7 @@ static const struct platform_device_id db1200_pids[] = {
.name = "db1550-i2s",
.driver_data = 5,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, db1200_pids);
diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c
index 57735004f416..0e9c7eef9ee8 100644
--- a/sound/soc/au1x/i2sc.c
+++ b/sound/soc/au1x/i2sc.c
@@ -202,11 +202,22 @@ static int au1xi2s_startup(struct snd_pcm_substream *substream,
return 0;
}
+static const u64 au1xi2s_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 |
+ 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 au1xi2s_dai_ops = {
.startup = au1xi2s_startup,
.trigger = au1xi2s_trigger,
.hw_params = au1xi2s_hw_params,
.set_fmt = au1xi2s_set_fmt,
+ .auto_selectable_formats = &au1xi2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver au1xi2s_dai_driver = {
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index 94698e08a513..0f9d80883116 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -210,9 +210,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
{
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
unsigned long r, ro, stat;
- int chans, t, stype = substream->stream;
-
- chans = params_channels(params);
+ int t, stype = substream->stream;
r = ro = __raw_readl(AC97_CFG(pscdata));
stat = __raw_readl(AC97_STAT(pscdata));
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index bf59105fcb7a..72aa5177147f 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -262,11 +262,22 @@ static int au1xpsc_i2s_startup(struct snd_pcm_substream *substream,
return 0;
}
+static const u64 au1xpsc_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 |
+ 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 au1xpsc_i2s_dai_ops = {
.startup = au1xpsc_i2s_startup,
.trigger = au1xpsc_i2s_trigger,
.hw_params = au1xpsc_i2s_hw_params,
.set_fmt = au1xpsc_i2s_set_fmt,
+ .auto_selectable_formats = &au1xpsc_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index 87d2f06c2f53..208977828254 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -748,6 +748,17 @@ static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const u64 bcm2835_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 |
+ 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 bcm2835_i2s_dai_ops = {
.probe = bcm2835_i2s_dai_probe,
.startup = bcm2835_i2s_startup,
@@ -758,6 +769,8 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
.set_fmt = bcm2835_i2s_set_dai_fmt,
.set_bclk_ratio = bcm2835_i2s_set_dai_bclk_ratio,
.set_tdm_slot = bcm2835_i2s_set_dai_tdm_slot,
+ .auto_selectable_formats = &bcm2835_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver bcm2835_i2s_dai = {
diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 47706ae0a31f..753021789a52 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -1133,6 +1133,11 @@ static int cygnus_ssp_resume(struct snd_soc_component *component)
#define cygnus_ssp_resume NULL
#endif
+static const u64 cygnus_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
.startup = cygnus_ssp_startup,
.shutdown = cygnus_ssp_shutdown,
@@ -1141,6 +1146,8 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
.set_fmt = cygnus_ssp_set_fmt,
.set_sysclk = cygnus_ssp_set_sysclk,
.set_tdm_slot = cygnus_set_dai_tdm_slot,
+ .auto_selectable_formats = &cygnus_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_dai_ops cygnus_spdif_dai_ops = {
diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
index 5dba741594fa..8195ed7c6dd6 100644
--- a/sound/soc/cirrus/ep93xx-i2s.c
+++ b/sound/soc/cirrus/ep93xx-i2s.c
@@ -401,6 +401,15 @@ static int ep93xx_i2s_resume(struct snd_soc_component *component)
#define ep93xx_i2s_resume NULL
#endif
+static const u64 ep93xx_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 |
+ 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 ep93xx_i2s_dai_ops = {
.probe = ep93xx_i2s_dai_probe,
.startup = ep93xx_i2s_startup,
@@ -408,6 +417,8 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
.hw_params = ep93xx_i2s_hw_params,
.set_sysclk = ep93xx_i2s_set_sysclk,
.set_fmt = ep93xx_i2s_set_dai_fmt,
+ .auto_selectable_formats = &ep93xx_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 252f683be3c1..a678e68b0bd2 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -367,6 +367,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 +616,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 +727,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 +738,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
@@ -1201,16 +1207,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 +1894,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
@@ -2296,8 +2302,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
@@ -2770,6 +2776,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
@@ -2893,28 +2909,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..2e006f5a8abd 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
@@ -426,6 +427,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 +498,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
@@ -876,6 +879,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/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/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..8150670fde2d 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;
}
@@ -280,14 +278,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..a3cc027de606 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;
}
@@ -1165,11 +1162,9 @@ static int aw88081_request_firmware_file(struct aw88081 *aw88081)
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 +1173,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 +1184,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..b72f87f677dd 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;
}
@@ -1607,12 +1604,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 +1636,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 +1647,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..acbd7de2e40e 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;
}
@@ -1188,12 +1185,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..e9ff2c79ac15 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;
}
@@ -495,12 +491,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..5c7982891def
--- /dev/null
+++ b/sound/soc/codecs/aw88399-lib.c
@@ -0,0 +1,1411 @@
+// 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 = 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;
+}
+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/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c
index 7dc5a7c3ca96..fd2d5d7f9276 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>
@@ -608,10 +609,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 +625,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 +894,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 +909,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-sdw.c b/sound/soc/codecs/cs35l56-sdw.c
index 0a55b93b96f9..303d37e7d0bf 100644
--- a/sound/soc/codecs/cs35l56-sdw.c
+++ b/sound/soc/codecs/cs35l56-sdw.c
@@ -457,6 +457,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:
@@ -509,6 +510,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..b40bd3a8d27b 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));
@@ -640,23 +643,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 +682,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,14 +690,7 @@ 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;
-
-err:
- pm_runtime_put(cs35l56_base->dev);
-err_unlock:
- mutex_unlock(&cs35l56_base->irq_lock);
-
- return ret;
+ return IRQ_HANDLED;
}
EXPORT_SYMBOL_NS_GPL(cs35l56_irq, "SND_SOC_CS35L56_SHARED");
@@ -816,14 +811,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 +1461,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.c b/sound/soc/codecs/cs35l56.c
index 063ef7a70de0..0b7b080939a1 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -1402,6 +1402,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;
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 f2a58163de0e..36533a13319d 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>
@@ -281,10 +282,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;
}
@@ -831,7 +831,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,
@@ -902,8 +902,6 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data)
break;
}
- mutex_unlock(&cs42l84->irq_lock);
-
return IRQ_HANDLED;
}
@@ -919,8 +917,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 83c6cbd40804..908344ee5892 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.h>
@@ -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..87f331868dc7 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/acpi.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -620,15 +621,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 +682,6 @@ static irqreturn_t es8316_irq(int irq, void *data)
}
}
-out:
- mutex_unlock(&es8316->lock);
return IRQ_HANDLED;
}
@@ -699,18 +698,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);
+ scoped_guard(mutex, &es8316->lock) {
+ es8316->jack = jack;
- 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 +723,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 +734,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,
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/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..1ab5f8a26e03 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -642,10 +642,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/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..55ea6950ca90 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;
}
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..66309e87fdbd 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -952,11 +952,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/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/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/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..bf143e3fec54 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>
@@ -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..a2b66eae6ac4 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;
}
@@ -1645,9 +1645,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 +1889,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..5a1ed02abb84 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>
@@ -1704,13 +1705,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 +1717,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..307b66025426 100644
--- a/sound/soc/codecs/pm4125-sdw.c
+++ b/sound/soc/codecs/pm4125-sdw.c
@@ -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/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
index ca318dbd946e..359b52ba1ef9 100644
--- a/sound/soc/codecs/rt1316-sdw.c
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -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..ef18cd63d461 100644
--- a/sound/soc/codecs/rt1318-sdw.c
+++ b/sound/soc/codecs/rt1318-sdw.c
@@ -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/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index 1e930b27c67a..3a5eebcfefdd 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]);
@@ -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;
@@ -1382,30 +1875,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_;
}
@@ -1483,22 +1963,48 @@ 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__);
+ release_firmware(rae_fw);
+ 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__);
+ release_firmware(rae_fw);
+ 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);
@@ -1559,18 +2065,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,8 +2120,7 @@ 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];
@@ -1610,20 +2131,10 @@ struct rt1320_dspfwheader {
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 +2164,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;
@@ -1709,9 +2215,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 +2229,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;
@@ -1743,24 +2267,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 +2382,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 +2452,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 +2904,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 +2918,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 +3022,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 +3033,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 +3385,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 +3423,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 +3660,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/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/rt5645.c b/sound/soc/codecs/rt5645.c
index e9819653b30d..0d546fb34e52 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)
@@ -3518,9 +3516,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;
}
@@ -4331,9 +4335,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..3e4d1dbce740 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;
}
@@ -940,21 +936,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);
+ /* 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);
-
- 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 +4762,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 +4844,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 +4991,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 +5013,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 +5410,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 +5418,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/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.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.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-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.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/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.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..27bb0eb1ece7 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,
@@ -1906,6 +1906,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/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/sigmadsp.c b/sound/soc/codecs/sigmadsp.c
index 2e08fde3989c..b7dbeb237447 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;
}
@@ -677,10 +674,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/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/tas2552.c b/sound/soc/codecs/tas2552.c
index 1a7650b9b2a7..22f93e29454f 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -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/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-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 209067e98e1f..01442fd57d7e 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[] = {
@@ -1765,13 +1770,10 @@ 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);
return 0;
}
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c
index 3d0b116544cc..34f17e063fa3 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>
@@ -693,12 +694,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 +928,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 +968,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 +976,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 +1097,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 +1229,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);
diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c
index bcc8cab8d667..f76e04b403b5 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;
}
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/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..58c0c601ee6c 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));
@@ -734,9 +730,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 +827,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..897b0acac5f3 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[] = {
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/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/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index f23c21032287..df4817ae91b1 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -222,10 +222,9 @@ static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
enum asrc_pair_index index = ASRC_INVALID_PAIR;
struct fsl_asrc *asrc = pair->asrc;
struct device *dev = &asrc->pdev->dev;
- unsigned long lock_flags;
int i, ret = 0;
- spin_lock_irqsave(&asrc->lock, lock_flags);
+ guard(spinlock_irqsave)(&asrc->lock);
for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) {
if (asrc->pair[i] != NULL)
@@ -250,8 +249,6 @@ static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
pair->index = index;
}
- spin_unlock_irqrestore(&asrc->lock, lock_flags);
-
return ret;
}
@@ -265,19 +262,16 @@ static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair)
{
struct fsl_asrc *asrc = pair->asrc;
enum asrc_pair_index index = pair->index;
- unsigned long lock_flags;
/* Make sure the pair is disabled */
regmap_update_bits(asrc->regmap, REG_ASRCTR,
ASRCTR_ASRCEi_MASK(index), 0);
- spin_lock_irqsave(&asrc->lock, lock_flags);
+ guard(spinlock_irqsave)(&asrc->lock);
asrc->channel_avail += pair->channels;
asrc->pair[index] = NULL;
pair->error = 0;
-
- spin_unlock_irqrestore(&asrc->lock, lock_flags);
}
/**
diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c
index f819f33ec46b..d4140e170edf 100644
--- a/sound/soc/fsl/fsl_audmix.c
+++ b/sound/soc/fsl/fsl_audmix.c
@@ -286,7 +286,6 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct fsl_audmix *priv = snd_soc_dai_get_drvdata(dai);
- unsigned long lock_flags;
/* Capture stream shall not be handled */
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
@@ -296,16 +295,14 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- spin_lock_irqsave(&priv->lock, lock_flags);
- priv->tdms |= BIT(dai->driver->id);
- spin_unlock_irqrestore(&priv->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &priv->lock)
+ priv->tdms |= BIT(dai->driver->id);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- spin_lock_irqsave(&priv->lock, lock_flags);
- priv->tdms &= ~BIT(dai->driver->id);
- spin_unlock_irqrestore(&priv->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &priv->lock)
+ priv->tdms &= ~BIT(dai->driver->id);
break;
default:
return -EINVAL;
@@ -457,6 +454,9 @@ static const struct of_device_id fsl_audmix_ids[] = {
};
MODULE_DEVICE_TABLE(of, fsl_audmix_ids);
+static int fsl_audmix_runtime_resume(struct device *dev);
+static int fsl_audmix_runtime_suspend(struct device *dev);
+
static int fsl_audmix_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -488,13 +488,25 @@ static int fsl_audmix_probe(struct platform_device *pdev)
spin_lock_init(&priv->lock);
platform_set_drvdata(pdev, priv);
pm_runtime_enable(dev);
+ if (!pm_runtime_enabled(dev)) {
+ ret = fsl_audmix_runtime_resume(dev);
+ if (ret)
+ goto err_disable_pm;
+ }
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ goto err_pm_get_sync;
+
+ /* To enable regmap cache only when runtime PM enabled */
+ pm_runtime_put(dev);
ret = devm_snd_soc_register_component(dev, &fsl_audmix_component,
fsl_audmix_dai,
ARRAY_SIZE(fsl_audmix_dai));
if (ret) {
dev_err(dev, "failed to register ASoC DAI\n");
- goto err_disable_pm;
+ goto err_pm_get_sync;
}
/*
@@ -506,12 +518,15 @@ static int fsl_audmix_probe(struct platform_device *pdev)
if (IS_ERR(priv->pdev)) {
ret = PTR_ERR(priv->pdev);
dev_err(dev, "failed to register platform: %d\n", ret);
- goto err_disable_pm;
+ goto err_pm_get_sync;
}
}
return 0;
+err_pm_get_sync:
+ if (!pm_runtime_status_suspended(dev))
+ fsl_audmix_runtime_suspend(dev);
err_disable_pm:
pm_runtime_disable(dev);
return ret;
@@ -522,6 +537,8 @@ static void fsl_audmix_remove(struct platform_device *pdev)
struct fsl_audmix *priv = dev_get_drvdata(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ fsl_audmix_runtime_suspend(&pdev->dev);
if (priv->pdev)
platform_device_unregister(priv->pdev);
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index b12474880185..b1b341132dd6 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -18,8 +18,6 @@
#include <linux/delay.h>
#include <linux/gfp.h>
#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
#include <linux/list.h>
#include <linux/slab.h>
@@ -824,9 +822,34 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct device_node *ssi_np;
struct resource res;
+ void __iomem *channel;
const uint32_t *iprop;
+ int irq;
int ret;
+ channel = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(channel))
+ return PTR_ERR(channel);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ dma = devm_kzalloc(&pdev->dev, sizeof(*dma), GFP_KERNEL);
+ if (!dma)
+ return -ENOMEM;
+
+ dma->dai.name = DRV_NAME;
+ dma->dai.open = fsl_dma_open;
+ dma->dai.close = fsl_dma_close;
+ dma->dai.hw_params = fsl_dma_hw_params;
+ dma->dai.hw_free = fsl_dma_hw_free;
+ dma->dai.pointer = fsl_dma_pointer;
+ dma->dai.pcm_new = fsl_dma_new;
+
+ dma->channel = channel;
+ dma->irq = irq;
+
/* Find the SSI node that points to us. */
ssi_np = find_ssi_node(np);
if (!ssi_np) {
@@ -842,55 +865,19 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
return ret;
}
- dma = kzalloc_obj(*dma);
- if (!dma) {
- of_node_put(ssi_np);
- return -ENOMEM;
- }
-
- dma->dai.name = DRV_NAME;
- dma->dai.open = fsl_dma_open;
- dma->dai.close = fsl_dma_close;
- dma->dai.hw_params = fsl_dma_hw_params;
- dma->dai.hw_free = fsl_dma_hw_free;
- dma->dai.pointer = fsl_dma_pointer;
- dma->dai.pcm_new = fsl_dma_new;
-
/* Store the SSI-specific information that we need */
dma->ssi_stx_phys = res.start + REG_SSI_STX0;
dma->ssi_srx_phys = res.start + REG_SSI_SRX0;
iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL);
+ of_node_put(ssi_np);
if (iprop)
dma->ssi_fifo_depth = be32_to_cpup(iprop);
else
/* Older 8610 DTs didn't have the fifo-depth property */
dma->ssi_fifo_depth = 8;
- of_node_put(ssi_np);
-
- ret = devm_snd_soc_register_component(&pdev->dev, &dma->dai, NULL, 0);
- if (ret) {
- dev_err(&pdev->dev, "could not register platform\n");
- kfree(dma);
- return ret;
- }
-
- dma->channel = of_iomap(np, 0);
- dma->irq = irq_of_parse_and_map(np, 0);
-
- dev_set_drvdata(&pdev->dev, dma);
-
- return 0;
-}
-
-static void fsl_soc_dma_remove(struct platform_device *pdev)
-{
- struct dma_object *dma = dev_get_drvdata(&pdev->dev);
-
- iounmap(dma->channel);
- irq_dispose_mapping(dma->irq);
- kfree(dma);
+ return devm_snd_soc_register_component(&pdev->dev, &dma->dai, NULL, 0);
}
static const struct of_device_id fsl_soc_dma_ids[] = {
@@ -905,7 +892,6 @@ static struct platform_driver fsl_soc_dma_driver = {
.of_match_table = fsl_soc_dma_ids,
},
.probe = fsl_soc_dma_probe,
- .remove = fsl_soc_dma_remove,
};
module_platform_driver(fsl_soc_dma_driver);
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index 8535ef844ce0..bb9e036c7937 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -1025,7 +1025,6 @@ static int fsl_easrc_config_context(struct fsl_asrc *easrc, unsigned int ctx_id)
struct fsl_easrc_ctx_priv *ctx_priv;
struct fsl_asrc_pair *ctx;
struct device *dev;
- unsigned long lock_flags;
int ret;
if (!easrc)
@@ -1053,9 +1052,8 @@ static int fsl_easrc_config_context(struct fsl_asrc *easrc, unsigned int ctx_id)
if (ret)
return ret;
- spin_lock_irqsave(&easrc->lock, lock_flags);
- ret = fsl_easrc_config_slot(easrc, ctx->index);
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &easrc->lock)
+ ret = fsl_easrc_config_slot(easrc, ctx->index);
if (ret)
return ret;
@@ -1301,13 +1299,12 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx)
enum asrc_pair_index index = ASRC_INVALID_PAIR;
struct fsl_asrc *easrc = ctx->asrc;
struct device *dev;
- unsigned long lock_flags;
int ret = 0;
int i;
dev = &easrc->pdev->dev;
- spin_lock_irqsave(&easrc->lock, lock_flags);
+ guard(spinlock_irqsave)(&easrc->lock);
for (i = ASRC_PAIR_A; i < EASRC_CTX_MAX_NUM; i++) {
if (easrc->pair[i])
@@ -1331,8 +1328,6 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx)
easrc->channel_avail -= channels;
}
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
-
return ret;
}
@@ -1343,7 +1338,6 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx)
*/
static void fsl_easrc_release_context(struct fsl_asrc_pair *ctx)
{
- unsigned long lock_flags;
struct fsl_asrc *easrc;
if (!ctx)
@@ -1351,14 +1345,12 @@ static void fsl_easrc_release_context(struct fsl_asrc_pair *ctx)
easrc = ctx->asrc;
- spin_lock_irqsave(&easrc->lock, lock_flags);
+ guard(spinlock_irqsave)(&easrc->lock);
fsl_easrc_release_slot(easrc, ctx->index);
easrc->channel_avail += ctx->channels;
easrc->pair[ctx->index] = NULL;
-
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
}
/*
@@ -2058,7 +2050,7 @@ static int fsl_easrc_m2m_calc_out_len(struct fsl_asrc_pair *pair, int input_buff
/* right shift 12 bit to make ratio in 32bit space */
val2 = (u64)in_samples << (frac_bits - 12);
val1 = val1 >> 12;
- do_div(val2, val1);
+ val2 = div64_u64(val2, val1);
out_samples = val2;
out_length = out_samples * out_width * channels;
@@ -2292,15 +2284,13 @@ static int fsl_easrc_runtime_suspend(struct device *dev)
{
struct fsl_asrc *easrc = dev_get_drvdata(dev);
struct fsl_easrc_priv *easrc_priv = easrc->private;
- unsigned long lock_flags;
regcache_cache_only(easrc->regmap, true);
clk_disable_unprepare(easrc->mem_clk);
- spin_lock_irqsave(&easrc->lock, lock_flags);
- easrc_priv->firmware_loaded = 0;
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &easrc->lock)
+ easrc_priv->firmware_loaded = 0;
return 0;
}
@@ -2311,7 +2301,6 @@ static int fsl_easrc_runtime_resume(struct device *dev)
struct fsl_easrc_priv *easrc_priv = easrc->private;
struct fsl_easrc_ctx_priv *ctx_priv;
struct fsl_asrc_pair *ctx;
- unsigned long lock_flags;
int ret;
int i;
@@ -2323,13 +2312,11 @@ static int fsl_easrc_runtime_resume(struct device *dev)
regcache_mark_dirty(easrc->regmap);
regcache_sync(easrc->regmap);
- spin_lock_irqsave(&easrc->lock, lock_flags);
- if (easrc_priv->firmware_loaded) {
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
- goto skip_load;
+ scoped_guard(spinlock_irqsave, &easrc->lock) {
+ if (easrc_priv->firmware_loaded)
+ return 0;
+ easrc_priv->firmware_loaded = 1;
}
- easrc_priv->firmware_loaded = 1;
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
ret = fsl_easrc_get_firmware(easrc);
if (ret) {
@@ -2377,9 +2364,6 @@ static int fsl_easrc_runtime_resume(struct device *dev)
goto disable_mem_clk;
}
-skip_load:
- return 0;
-
disable_mem_clk:
clk_disable_unprepare(easrc->mem_clk);
return ret;
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index cde0b0c6c1ef..4a530a6c33f0 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -709,10 +709,9 @@ static void fsl_esai_hw_reset(struct work_struct *work)
{
struct fsl_esai *esai_priv = container_of(work, struct fsl_esai, work);
bool tx = true, rx = false, enabled[2];
- unsigned long lock_flags;
u32 tfcr, rfcr;
- spin_lock_irqsave(&esai_priv->lock, lock_flags);
+ guard(spinlock_irqsave)(&esai_priv->lock);
/* Save the registers */
regmap_read(esai_priv->regmap, REG_ESAI_TFCR, &tfcr);
regmap_read(esai_priv->regmap, REG_ESAI_RFCR, &rfcr);
@@ -750,8 +749,6 @@ static void fsl_esai_hw_reset(struct work_struct *work)
fsl_esai_trigger_start(esai_priv, tx);
if (enabled[rx])
fsl_esai_trigger_start(esai_priv, rx);
-
- spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
}
static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -759,7 +756,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
{
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- unsigned long lock_flags;
esai_priv->channels[tx] = substream->runtime->channels;
@@ -767,16 +763,14 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- spin_lock_irqsave(&esai_priv->lock, lock_flags);
- fsl_esai_trigger_start(esai_priv, tx);
- spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &esai_priv->lock)
+ fsl_esai_trigger_start(esai_priv, tx);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- spin_lock_irqsave(&esai_priv->lock, lock_flags);
- fsl_esai_trigger_stop(esai_priv, tx);
- spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &esai_priv->lock)
+ fsl_esai_trigger_stop(esai_priv, tx);
break;
default:
return -EINVAL;
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 1b9be85b34c2..ad1206ed9882 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -853,17 +853,15 @@ static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol,
struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
- unsigned long flags;
int ret = -EAGAIN;
- spin_lock_irqsave(&ctrl->ctl_lock, flags);
+ guard(spinlock_irqsave)(&ctrl->ctl_lock);
if (ctrl->ready_buf) {
int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE;
memcpy(&ucontrol->value.iec958.subcode[0],
&ctrl->subcode[idx], SPDIF_UBITS_SIZE);
ret = 0;
}
- spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
return ret;
}
@@ -885,17 +883,15 @@ static int fsl_spdif_qget(struct snd_kcontrol *kcontrol,
struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
- unsigned long flags;
int ret = -EAGAIN;
- spin_lock_irqsave(&ctrl->ctl_lock, flags);
+ guard(spinlock_irqsave)(&ctrl->ctl_lock);
if (ctrl->ready_buf) {
int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE;
memcpy(&ucontrol->value.bytes.data[0],
&ctrl->qsub[idx], SPDIF_QSUB_SIZE);
ret = 0;
}
- spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
return ret;
}
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index b2e1da1781ae..dc022976c982 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -1218,13 +1218,13 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
if (reg > 0x7f)
return;
- mutex_lock(&fsl_ac97_data->ac97_reg_lock);
+ guard(mutex)(&fsl_ac97_data->ac97_reg_lock);
ret = clk_prepare_enable(fsl_ac97_data->clk);
if (ret) {
pr_err("ac97 write clk_prepare_enable failed: %d\n",
ret);
- goto ret_unlock;
+ return;
}
lreg = reg << 12;
@@ -1238,9 +1238,6 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
udelay(100);
clk_disable_unprepare(fsl_ac97_data->clk);
-
-ret_unlock:
- mutex_unlock(&fsl_ac97_data->ac97_reg_lock);
}
static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
@@ -1252,12 +1249,12 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
unsigned int lreg;
int ret;
- mutex_lock(&fsl_ac97_data->ac97_reg_lock);
+ guard(mutex)(&fsl_ac97_data->ac97_reg_lock);
ret = clk_prepare_enable(fsl_ac97_data->clk);
if (ret) {
pr_err("ac97 read clk_prepare_enable failed: %d\n", ret);
- goto ret_unlock;
+ return val;
}
lreg = (reg & 0x7f) << 12;
@@ -1272,8 +1269,6 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
clk_disable_unprepare(fsl_ac97_data->clk);
-ret_unlock:
- mutex_unlock(&fsl_ac97_data->ac97_reg_lock);
return val;
}
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
index 6677d3bf36ec..41d100500534 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -797,10 +797,9 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
{
struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- unsigned long lock_flags;
int ret = 0;
- spin_lock_irqsave(&xcvr->lock, lock_flags);
+ guard(spinlock_irqsave)(&xcvr->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -812,7 +811,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_EXT_CTRL_DPTH_RESET(tx));
if (ret < 0) {
dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret);
- goto release_lock;
+ return ret;
}
if (tx) {
@@ -824,7 +823,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_ISR_CMDC_TX_EN);
if (ret < 0) {
dev_err(dai->dev, "err updating isr %d\n", ret);
- goto release_lock;
+ return ret;
}
fallthrough;
case FSL_XCVR_MODE_SPDIF:
@@ -833,7 +832,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
if (ret < 0) {
dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret);
- goto release_lock;
+ return ret;
}
break;
}
@@ -844,14 +843,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0);
if (ret < 0) {
dev_err(dai->dev, "Failed to enable DMA: %d\n", ret);
- goto release_lock;
+ return ret;
}
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL);
if (ret < 0) {
dev_err(dai->dev, "Error while setting IER0: %d\n", ret);
- goto release_lock;
+ return ret;
}
/* clear DPATH RESET */
@@ -860,7 +859,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
0);
if (ret < 0) {
dev_err(dai->dev, "Failed to clear DPATH RESET: %d\n", ret);
- goto release_lock;
+ return ret;
}
break;
@@ -873,14 +872,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_EXT_CTRL_DMA_DIS(tx));
if (ret < 0) {
dev_err(dai->dev, "Failed to disable DMA: %d\n", ret);
- goto release_lock;
+ return ret;
}
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
FSL_XCVR_IRQ_EARC_ALL, 0);
if (ret < 0) {
dev_err(dai->dev, "Failed to clear IER0: %d\n", ret);
- goto release_lock;
+ return ret;
}
if (tx) {
@@ -891,7 +890,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
if (ret < 0) {
dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret);
- goto release_lock;
+ return ret;
}
if (xcvr->soc_data->spdif_only)
break;
@@ -905,7 +904,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
if (ret < 0) {
dev_err(dai->dev,
"Err updating ISR %d\n", ret);
- goto release_lock;
+ return ret;
}
break;
}
@@ -916,8 +915,6 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
break;
}
-release_lock:
- spin_unlock_irqrestore(&xcvr->lock, lock_flags);
return ret;
}
@@ -1448,11 +1445,10 @@ static void reset_rx_work(struct work_struct *work)
{
struct fsl_xcvr *xcvr = container_of(work, struct fsl_xcvr, work_rst);
struct device *dev = &xcvr->pdev->dev;
- unsigned long lock_flags;
u32 ext_ctrl;
dev_dbg(dev, "reset rx path\n");
- spin_lock_irqsave(&xcvr->lock, lock_flags);
+ guard(spinlock_irqsave)(&xcvr->lock);
regmap_read(xcvr->regmap, FSL_XCVR_EXT_CTRL, &ext_ctrl);
if (!(ext_ctrl & FSL_XCVR_EXT_CTRL_DMA_RD_DIS)) {
@@ -1469,7 +1465,6 @@ static void reset_rx_work(struct work_struct *work)
FSL_XCVR_EXT_CTRL_RX_DPTH_RESET,
0);
}
- spin_unlock_irqrestore(&xcvr->lock, lock_flags);
}
static irqreturn_t irq0_isr(int irq, void *devid)
diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c
index 38aafb8954c7..b55dfbdb4502 100644
--- a/sound/soc/fsl/imx-audio-rpmsg.c
+++ b/sound/soc/fsl/imx-audio-rpmsg.c
@@ -22,7 +22,6 @@ static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
struct rpmsg_r_msg *r_msg = (struct rpmsg_r_msg *)data;
struct rpmsg_info *info;
struct rpmsg_msg *msg;
- unsigned long flags;
if (!rpmsg->rpmsg_pdev)
return 0;
@@ -37,21 +36,21 @@ static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
/* TYPE C is notification from M core */
switch (r_msg->header.cmd) {
case TX_PERIOD_DONE:
- spin_lock_irqsave(&info->lock[TX], flags);
- msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
- msg->r_msg.param.buffer_tail =
- r_msg->param.buffer_tail;
- msg->r_msg.param.buffer_tail %= info->num_period[TX];
- spin_unlock_irqrestore(&info->lock[TX], flags);
+ scoped_guard(spinlock_irqsave, &info->lock[TX]) {
+ msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
+ msg->r_msg.param.buffer_tail =
+ r_msg->param.buffer_tail;
+ msg->r_msg.param.buffer_tail %= info->num_period[TX];
+ }
info->callback[TX](info->callback_param[TX]);
break;
case RX_PERIOD_DONE:
- spin_lock_irqsave(&info->lock[RX], flags);
- msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
- msg->r_msg.param.buffer_tail =
- r_msg->param.buffer_tail;
- msg->r_msg.param.buffer_tail %= info->num_period[1];
- spin_unlock_irqrestore(&info->lock[RX], flags);
+ scoped_guard(spinlock_irqsave, &info->lock[RX]) {
+ msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
+ msg->r_msg.param.buffer_tail =
+ r_msg->param.buffer_tail;
+ msg->r_msg.param.buffer_tail %= info->num_period[1];
+ }
info->callback[RX](info->callback_param[RX]);
break;
default:
diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c
index 2a4813c6cda9..7086fb7fc1eb 100644
--- a/sound/soc/fsl/imx-pcm-rpmsg.c
+++ b/sound/soc/fsl/imx-pcm-rpmsg.c
@@ -39,10 +39,9 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
struct rpmsg_device *rpdev = info->rpdev;
int ret = 0;
- mutex_lock(&info->msg_lock);
+ guard(mutex)(&info->msg_lock);
if (!rpdev) {
dev_err(info->dev, "rpmsg channel not ready\n");
- mutex_unlock(&info->msg_lock);
return -EINVAL;
}
@@ -55,15 +54,12 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
sizeof(struct rpmsg_s_msg));
if (ret) {
dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
- mutex_unlock(&info->msg_lock);
return ret;
}
/* No receive msg for TYPE_C command */
- if (msg->s_msg.header.type == MSG_TYPE_C) {
- mutex_unlock(&info->msg_lock);
+ if (msg->s_msg.header.type == MSG_TYPE_C)
return 0;
- }
/* wait response from rpmsg */
ret = wait_for_completion_timeout(&info->cmd_complete,
@@ -71,7 +67,6 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
if (!ret) {
dev_err(&rpdev->dev, "rpmsg_send cmd %d timeout!\n",
msg->s_msg.header.cmd);
- mutex_unlock(&info->msg_lock);
return -ETIMEDOUT;
}
@@ -100,8 +95,6 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
dev_dbg(&rpdev->dev, "cmd:%d, resp %d\n", msg->s_msg.header.cmd,
info->r_msg.param.resp);
- mutex_unlock(&info->msg_lock);
-
return 0;
}
@@ -109,14 +102,13 @@ static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream,
struct rpmsg_msg *msg,
struct rpmsg_info *info)
{
- unsigned long flags;
int ret = 0;
/*
* Queue the work to workqueue.
* If the queue is full, drop the message.
*/
- spin_lock_irqsave(&info->wq_lock, flags);
+ guard(spinlock_irqsave)(&info->wq_lock);
if (info->work_write_index != info->work_read_index) {
int index = info->work_write_index;
@@ -130,7 +122,6 @@ static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream,
info->msg_drop_count[substream->stream]++;
ret = -EPIPE;
}
- spin_unlock_irqrestore(&info->wq_lock, flags);
return ret;
}
@@ -523,7 +514,6 @@ static int imx_rpmsg_pcm_ack(struct snd_soc_component *component,
snd_pcm_sframes_t avail;
struct timer_list *timer;
struct rpmsg_msg *msg;
- unsigned long flags;
int buffer_tail = 0;
int written_num;
@@ -553,11 +543,11 @@ static int imx_rpmsg_pcm_ack(struct snd_soc_component *component,
msg->s_msg.param.buffer_tail = buffer_tail;
/* The notification message is updated to latest */
- spin_lock_irqsave(&info->lock[substream->stream], flags);
- memcpy(&info->notify[substream->stream], msg,
- sizeof(struct rpmsg_s_msg));
- info->notify_updated[substream->stream] = true;
- spin_unlock_irqrestore(&info->lock[substream->stream], flags);
+ scoped_guard(spinlock_irqsave, &info->lock[substream->stream]) {
+ memcpy(&info->notify[substream->stream], msg,
+ sizeof(struct rpmsg_s_msg));
+ info->notify_updated[substream->stream] = true;
+ }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
avail = snd_pcm_playback_hw_avail(runtime);
@@ -641,7 +631,7 @@ static void imx_rpmsg_pcm_work(struct work_struct *work)
bool is_notification = false;
struct rpmsg_info *info;
struct rpmsg_msg msg;
- unsigned long flags;
+ bool updated;
work_of_rpmsg = container_of(work, struct work_of_rpmsg, work);
info = work_of_rpmsg->info;
@@ -652,25 +642,26 @@ static void imx_rpmsg_pcm_work(struct work_struct *work)
* enough data in M core side, need to let M core know
* data is updated immediately.
*/
- spin_lock_irqsave(&info->lock[TX], flags);
- if (info->notify_updated[TX]) {
- memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg));
- info->notify_updated[TX] = false;
- spin_unlock_irqrestore(&info->lock[TX], flags);
- info->send_message(&msg, info);
- } else {
- spin_unlock_irqrestore(&info->lock[TX], flags);
+ scoped_guard(spinlock_irqsave, &info->lock[TX]) {
+ updated = info->notify_updated[TX];
+ if (updated) {
+ memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg));
+ info->notify_updated[TX] = false;
+ }
}
-
- spin_lock_irqsave(&info->lock[RX], flags);
- if (info->notify_updated[RX]) {
- memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg));
- info->notify_updated[RX] = false;
- spin_unlock_irqrestore(&info->lock[RX], flags);
+ if (updated)
info->send_message(&msg, info);
- } else {
- spin_unlock_irqrestore(&info->lock[RX], flags);
+
+ scoped_guard(spinlock_irqsave, &info->lock[RX]) {
+ updated = info->notify_updated[RX];
+ if (updated) {
+ memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg));
+ info->notify_updated[RX] = false;
+ }
}
+ if (updated)
+ info->send_message(&msg, info);
+
/* Skip the notification message for it has been processed above */
if (work_of_rpmsg->msg.s_msg.header.type == MSG_TYPE_C &&
@@ -682,10 +673,10 @@ static void imx_rpmsg_pcm_work(struct work_struct *work)
info->send_message(&work_of_rpmsg->msg, info);
/* update read index */
- spin_lock_irqsave(&info->wq_lock, flags);
- info->work_read_index++;
- info->work_read_index %= WORK_MAX_NUM;
- spin_unlock_irqrestore(&info->wq_lock, flags);
+ scoped_guard(spinlock_irqsave, &info->wq_lock) {
+ info->work_read_index++;
+ info->work_read_index %= WORK_MAX_NUM;
+ }
}
static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
@@ -819,9 +810,9 @@ static const struct dev_pm_ops imx_rpmsg_pcm_pm_ops = {
};
static const struct platform_device_id imx_rpmsg_pcm_id_table[] = {
- { .name = "rpmsg-audio-channel" },
- { .name = "rpmsg-micfil-channel" },
- { },
+ { .name = "rpmsg-audio-channel" },
+ { .name = "rpmsg-micfil-channel" },
+ { }
};
MODULE_DEVICE_TABLE(platform, imx_rpmsg_pcm_id_table);
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 56e2cf2f727b..8327fff3e1b5 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -77,18 +77,20 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
{
struct psc_dma_stream *s = _psc_dma_stream;
- spin_lock(&s->psc_dma->lock);
- /* For each finished period, dequeue the completed period buffer
- * and enqueue a new one in it's place. */
- while (bcom_buffer_done(s->bcom_task)) {
- bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+ scoped_guard(spinlock, &s->psc_dma->lock) {
+ /*
+ * For each finished period, dequeue the completed period buffer
+ * and enqueue a new one in its place
+ */
+ while (bcom_buffer_done(s->bcom_task)) {
+ bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
- s->period_current = (s->period_current+1) % s->runtime->periods;
- s->period_count++;
+ s->period_current = (s->period_current+1) % s->runtime->periods;
+ s->period_count++;
- psc_dma_bcom_enqueue_next_buffer(s);
+ psc_dma_bcom_enqueue_next_buffer(s);
+ }
}
- spin_unlock(&s->psc_dma->lock);
/* If the stream is active, then also inform the PCM middle layer
* of the period finished event. */
@@ -116,7 +118,6 @@ static int psc_dma_trigger(struct snd_soc_component *component,
struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
u16 imr;
- unsigned long flags;
int i;
switch (cmd) {
@@ -135,19 +136,18 @@ static int psc_dma_trigger(struct snd_soc_component *component,
/* Fill up the bestcomm bd queue and enable DMA.
* This will begin filling the PSC's fifo.
*/
- spin_lock_irqsave(&psc_dma->lock, flags);
-
- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
- bcom_gen_bd_rx_reset(s->bcom_task);
- else
- bcom_gen_bd_tx_reset(s->bcom_task);
+ scoped_guard(spinlock_irqsave, &psc_dma->lock) {
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+ bcom_gen_bd_rx_reset(s->bcom_task);
+ else
+ bcom_gen_bd_tx_reset(s->bcom_task);
- for (i = 0; i < runtime->periods; i++)
- if (!bcom_queue_full(s->bcom_task))
- psc_dma_bcom_enqueue_next_buffer(s);
+ for (i = 0; i < runtime->periods; i++)
+ if (!bcom_queue_full(s->bcom_task))
+ psc_dma_bcom_enqueue_next_buffer(s);
- bcom_enable(s->bcom_task);
- spin_unlock_irqrestore(&psc_dma->lock, flags);
+ bcom_enable(s->bcom_task);
+ }
out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
@@ -158,13 +158,13 @@ static int psc_dma_trigger(struct snd_soc_component *component,
substream->pstr->stream, s->period_count);
s->active = 0;
- spin_lock_irqsave(&psc_dma->lock, flags);
- bcom_disable(s->bcom_task);
- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
- bcom_gen_bd_rx_reset(s->bcom_task);
- else
- bcom_gen_bd_tx_reset(s->bcom_task);
- spin_unlock_irqrestore(&psc_dma->lock, flags);
+ scoped_guard(spinlock_irqsave, &psc_dma->lock) {
+ bcom_disable(s->bcom_task);
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+ bcom_gen_bd_rx_reset(s->bcom_task);
+ else
+ bcom_gen_bd_tx_reset(s->bcom_task);
+ }
break;
@@ -314,35 +314,29 @@ int mpc5200_audio_dma_create(struct platform_device *op)
{
phys_addr_t fifo;
struct psc_dma *psc_dma;
- struct resource res;
+ struct resource *res;
int size, irq, rc;
const __be32 *prop;
void __iomem *regs;
- int ret;
+
+ regs = devm_platform_get_and_ioremap_resource(op, 0, &res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
/* Fetch the registers and IRQ of the PSC */
- irq = irq_of_parse_and_map(op->dev.of_node, 0);
- if (of_address_to_resource(op->dev.of_node, 0, &res)) {
- dev_err(&op->dev, "Missing reg property\n");
- return -ENODEV;
- }
- regs = devm_ioremap(&op->dev, res.start, resource_size(&res));
- if (!regs) {
- dev_err(&op->dev, "Could not map registers\n");
- return -ENODEV;
- }
+ irq = platform_get_irq(op, 0);
+ if (irq < 0)
+ return irq;
/* Allocate and initialize the driver private data */
- psc_dma = kzalloc_obj(*psc_dma);
+ psc_dma = devm_kzalloc(&op->dev, sizeof(*psc_dma), GFP_KERNEL);
if (!psc_dma)
return -ENOMEM;
/* Get the PSC ID */
prop = of_get_property(op->dev.of_node, "cell-index", &size);
- if (!prop || size < sizeof *prop) {
- ret = -ENODEV;
- goto out_free;
- }
+ if (!prop || size < sizeof *prop)
+ return -ENODEV;
spin_lock_init(&psc_dma->lock);
mutex_init(&psc_dma->mutex);
@@ -357,7 +351,7 @@ int mpc5200_audio_dma_create(struct platform_device *op)
/* Find the address of the fifo data registers and setup the
* DMA tasks */
- fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
+ fifo = res->start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
psc_dma->capture.bcom_task =
bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512);
psc_dma->playback.bcom_task =
@@ -365,8 +359,7 @@ int mpc5200_audio_dma_create(struct platform_device *op)
if (!psc_dma->capture.bcom_task ||
!psc_dma->playback.bcom_task) {
dev_err(&op->dev, "Could not allocate bestcomm tasks\n");
- ret = -ENODEV;
- goto out_free;
+ return -ENODEV;
}
/* Disable all interrupts and reset the PSC */
@@ -399,16 +392,14 @@ int mpc5200_audio_dma_create(struct platform_device *op)
psc_dma->capture.irq =
bcom_get_task_irq(psc_dma->capture.bcom_task);
- rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,
+ rc = devm_request_irq(&op->dev, psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,
"psc-dma-status", psc_dma);
- rc |= request_irq(psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED,
+ rc |= devm_request_irq(&op->dev, psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED,
"psc-dma-capture", &psc_dma->capture);
- rc |= request_irq(psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED,
+ rc |= devm_request_irq(&op->dev, psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED,
"psc-dma-playback", &psc_dma->playback);
- if (rc) {
- ret = -ENODEV;
- goto out_irq;
- }
+ if (rc)
+ return -ENODEV;
/* Save what we've done so it can be found again later */
dev_set_drvdata(&op->dev, psc_dma);
@@ -416,13 +407,6 @@ int mpc5200_audio_dma_create(struct platform_device *op)
/* Tell the ASoC OF helpers about it */
return devm_snd_soc_register_component(&op->dev,
&mpc5200_audio_dma_component, NULL, 0);
-out_irq:
- free_irq(psc_dma->irq, psc_dma);
- free_irq(psc_dma->capture.irq, &psc_dma->capture);
- free_irq(psc_dma->playback.irq, &psc_dma->playback);
-out_free:
- kfree(psc_dma);
- return ret;
}
EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
@@ -435,12 +419,6 @@ int mpc5200_audio_dma_destroy(struct platform_device *op)
bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);
- /* Release irqs */
- free_irq(psc_dma->irq, psc_dma);
- free_irq(psc_dma->capture.irq, &psc_dma->capture);
- free_irq(psc_dma->playback.irq, &psc_dma->playback);
-
- kfree(psc_dma);
dev_set_drvdata(&op->dev, NULL);
return 0;
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index c21104355aa0..ccd8bda05860 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -30,14 +30,13 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
int status;
unsigned int val;
- mutex_lock(&psc_dma->mutex);
+ guard(mutex)(&psc_dma->mutex);
/* Wait for command send status zero = ready */
status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
MPC52xx_PSC_SR_CMDSEND), 100, 0);
if (status == 0) {
pr_err("timeout on ac97 bus (rdy)\n");
- mutex_unlock(&psc_dma->mutex);
return -ENODEV;
}
@@ -53,19 +52,16 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
if (status == 0) {
pr_err("timeout on ac97 read (val) %x\n",
in_be16(&psc_dma->psc_regs->sr_csr.status));
- mutex_unlock(&psc_dma->mutex);
return -ENODEV;
}
/* Get the data */
val = in_be32(&psc_dma->psc_regs->ac97_data);
if (((val >> 24) & 0x7f) != reg) {
pr_err("reg echo error on ac97 read\n");
- mutex_unlock(&psc_dma->mutex);
return -ENODEV;
}
val = (val >> 8) & 0xffff;
- mutex_unlock(&psc_dma->mutex);
return (unsigned short) val;
}
@@ -74,52 +70,46 @@ static void psc_ac97_write(struct snd_ac97 *ac97,
{
int status;
- mutex_lock(&psc_dma->mutex);
+ guard(mutex)(&psc_dma->mutex);
/* Wait for command status zero = ready */
status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
MPC52xx_PSC_SR_CMDSEND), 100, 0);
if (status == 0) {
pr_err("timeout on ac97 bus (write)\n");
- goto out;
+ return;
}
/* Write data */
out_be32(&psc_dma->psc_regs->ac97_cmd,
((reg & 0x7f) << 24) | (val << 8));
-
- out:
- mutex_unlock(&psc_dma->mutex);
}
static void psc_ac97_warm_reset(struct snd_ac97 *ac97)
{
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
- mutex_lock(&psc_dma->mutex);
+ guard(mutex)(&psc_dma->mutex);
out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR);
udelay(3);
out_be32(&regs->sicr, psc_dma->sicr);
-
- mutex_unlock(&psc_dma->mutex);
}
static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
{
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
- mutex_lock(&psc_dma->mutex);
- dev_dbg(psc_dma->dev, "cold reset\n");
+ scoped_guard(mutex, &psc_dma->mutex) {
+ dev_dbg(psc_dma->dev, "cold reset\n");
- mpc5200_psc_ac97_gpio_reset(psc_dma->id);
+ mpc5200_psc_ac97_gpio_reset(psc_dma->id);
- /* Notify the PSC that a reset has occurred */
- out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_ACRB);
+ /* Notify the PSC that a reset has occurred */
+ out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_ACRB);
- /* Re-enable RX and TX */
- out_8(&regs->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
-
- mutex_unlock(&psc_dma->mutex);
+ /* Re-enable RX and TX */
+ out_8(&regs->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+ }
usleep_range(1000, 2000);
psc_ac97_warm_reset(ac97);
@@ -286,7 +276,7 @@ static int psc_ac97_of_probe(struct platform_device *op)
return rc;
}
- rc = snd_soc_register_component(&op->dev, &psc_ac97_component,
+ rc = devm_snd_soc_register_component(&op->dev, &psc_ac97_component,
psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
if (rc != 0) {
dev_err(&op->dev, "Failed to register DAI\n");
@@ -312,8 +302,6 @@ static int psc_ac97_of_probe(struct platform_device *op)
static void psc_ac97_of_remove(struct platform_device *op)
{
mpc5200_audio_dma_destroy(op);
- snd_soc_unregister_component(&op->dev);
- snd_soc_set_ac97_ops(NULL);
}
/* Match table for of_platform binding */
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 9ad44eeed6ad..55a12be6ad18 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -166,10 +166,11 @@ static int psc_i2s_of_probe(struct platform_device *op)
if (rc != 0)
return rc;
- rc = snd_soc_register_component(&op->dev, &psc_i2s_component,
+ rc = devm_snd_soc_register_component(&op->dev, &psc_i2s_component,
psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
if (rc != 0) {
pr_err("Failed to register DAI\n");
+ mpc5200_audio_dma_destroy(op);
return rc;
}
@@ -212,7 +213,6 @@ static int psc_i2s_of_probe(struct platform_device *op)
static void psc_i2s_of_remove(struct platform_device *op)
{
mpc5200_audio_dma_destroy(op);
- snd_soc_unregister_component(&op->dev);
}
/* Match table for of_platform binding */
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index db07817a8024..98389f53246c 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -73,6 +73,8 @@ struct machine_data {
char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
};
+#define card_to_mdata(_card) container_of(_card, struct machine_data, card)
+
/**
* p1022_ds_machine_probe: initialize the board
*
@@ -82,8 +84,7 @@ struct machine_data {
*/
static int p1022_ds_machine_probe(struct snd_soc_card *card)
{
- struct machine_data *mdata =
- container_of(card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(card);
struct ccsr_guts __iomem *guts;
guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
@@ -122,8 +123,7 @@ static int p1022_ds_machine_probe(struct snd_soc_card *card)
static int p1022_ds_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- struct machine_data *mdata =
- container_of(rtd->card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(rtd->card);
struct device *dev = rtd->card->dev;
int ret = 0;
@@ -156,8 +156,7 @@ static int p1022_ds_startup(struct snd_pcm_substream *substream)
*/
static int p1022_ds_machine_remove(struct snd_soc_card *card)
{
- struct machine_data *mdata =
- container_of(card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(card);
struct ccsr_guts __iomem *guts;
guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
@@ -399,8 +398,7 @@ error_put:
static void p1022_ds_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- struct machine_data *mdata =
- container_of(card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(card);
snd_soc_unregister_card(card);
kfree(mdata);
diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c
index f80d6d04e791..d82fe22ca5c5 100644
--- a/sound/soc/fsl/p1022_rdk.c
+++ b/sound/soc/fsl/p1022_rdk.c
@@ -79,6 +79,8 @@ struct machine_data {
char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
};
+#define card_to_mdata(_card) container_of(_card, struct machine_data, card)
+
/**
* p1022_rdk_machine_probe - initialize the board
* @card: ASoC card instance
@@ -91,8 +93,7 @@ struct machine_data {
*/
static int p1022_rdk_machine_probe(struct snd_soc_card *card)
{
- struct machine_data *mdata =
- container_of(card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(card);
struct ccsr_guts __iomem *guts;
guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
@@ -134,8 +135,7 @@ static int p1022_rdk_machine_probe(struct snd_soc_card *card)
static int p1022_rdk_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- struct machine_data *mdata =
- container_of(rtd->card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(rtd->card);
struct device *dev = rtd->card->dev;
int ret = 0;
@@ -169,8 +169,7 @@ static int p1022_rdk_startup(struct snd_pcm_substream *substream)
*/
static int p1022_rdk_machine_remove(struct snd_soc_card *card)
{
- struct machine_data *mdata =
- container_of(card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(card);
struct ccsr_guts __iomem *guts;
guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
@@ -361,8 +360,7 @@ error_put:
static void p1022_rdk_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- struct machine_data *mdata =
- container_of(card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(card);
snd_soc_unregister_card(card);
kfree(mdata);
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 18ce4ee06350..0a8a6d891d1f 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -579,11 +579,11 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev)
goto end;
}
- ret = simple_util_parse_widgets(card, NULL);
+ ret = simple_util_parse_widgets(priv, NULL);
if (ret < 0)
goto end;
- ret = simple_util_parse_routing(card, NULL);
+ ret = simple_util_parse_routing(priv, NULL);
if (ret < 0)
goto end;
@@ -594,6 +594,7 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev)
if (ret < 0)
goto err;
+ /* Card name should be set after graph_for_each_link() */
ret = simple_util_parse_card_name(priv, NULL);
if (ret < 0)
goto err;
@@ -603,14 +604,13 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev)
simple_util_debug_info(priv);
ret = devm_snd_soc_register_card(dev, card);
- if (ret < 0)
- goto err;
-
- return 0;
err:
- simple_util_clean_reference(card);
+ if (ret < 0) {
+ simple_util_clean_reference(priv);
+ return dev_err_probe(dev, ret, "parse error\n");
+ }
end:
- return dev_err_probe(dev, ret, "parse error\n");
+ return graph_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(audio_graph_parse_of);
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index 0202ed0ee78e..9fb3d3df5cf6 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -1303,11 +1303,11 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
struct graph2_custom_hooks *hooks)
{
struct snd_soc_card *card = simple_priv_to_card(priv);
- int ret;
+ int ret = -ENOMEM;
struct link_info *li __free(kfree) = kzalloc_obj(*li);
if (!li)
- return -ENOMEM;
+ goto end;
card->probe = graph_util_card_probe;
card->owner = THIS_MODULE;
@@ -1316,31 +1316,35 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
if ((hooks) && (hooks)->hook_pre) {
ret = (hooks)->hook_pre(priv);
if (ret < 0)
- goto err;
+ goto end;
}
ret = graph_for_each_link(priv, hooks, li, graph_count);
if (!li->link)
ret = -EINVAL;
if (ret < 0)
- goto err;
+ goto end;
ret = simple_util_init_priv(priv, li);
if (ret < 0)
- goto err;
+ goto end;
priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
if (IS_ERR(priv->pa_gpio)) {
ret = PTR_ERR(priv->pa_gpio);
dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
- goto err;
+ goto end;
}
- ret = simple_util_parse_widgets(card, NULL);
+ ret = simple_util_parse_widgets(priv, NULL);
if (ret < 0)
- goto err;
+ goto end;
+
+ ret = simple_util_parse_routing(priv, NULL);
+ if (ret < 0)
+ goto end;
- ret = simple_util_parse_routing(card, NULL);
+ ret = simple_util_parse_aux_devs(priv, NULL);
if (ret < 0)
goto err;
@@ -1349,6 +1353,7 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
if (ret < 0)
goto err;
+ /* Card name should be set after graph_for_each_link() */
ret = simple_util_parse_card_name(priv, NULL);
if (ret < 0)
goto err;
@@ -1363,15 +1368,13 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
simple_util_debug_info(priv);
- ret = snd_soc_of_parse_aux_devs(card, "aux-devs");
- if (ret < 0)
- goto err;
-
ret = devm_snd_soc_register_card(dev, card);
err:
- if (ret < 0)
- dev_err_probe(dev, ret, "parse error\n");
-
+ if (ret < 0) {
+ simple_util_clean_reference(priv);
+ return dev_err_probe(dev, ret, "parse error\n");
+ }
+end:
return graph_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(audio_graph2_parse_of);
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index e5cb602fd248..42019daa5e04 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -216,6 +216,27 @@ int simple_util_set_dailink_name(struct simple_util_priv *priv,
}
EXPORT_SYMBOL_GPL(simple_util_set_dailink_name);
+int simple_util_parse_property(struct simple_util_priv *priv,
+ int (*func)(struct snd_soc_card *card, const char *propname),
+ char *prefix, char *property)
+{
+ struct snd_soc_card *card = simple_priv_to_card(priv);
+ struct device_node *node = card->dev->of_node;
+ char prop[128];
+
+ if (!prefix)
+ prefix = "";
+
+ snprintf(prop, sizeof(prop), "%s%s", prefix, property);
+
+ /* no property is not error */
+ if (!of_property_present(node, prop))
+ return 0;
+
+ return func(card, prop);
+}
+EXPORT_SYMBOL_GPL(simple_util_parse_property);
+
int simple_util_parse_card_name(struct simple_util_priv *priv,
char *prefix)
{
@@ -731,11 +752,12 @@ void simple_util_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
}
EXPORT_SYMBOL_GPL(simple_util_canonicalize_cpu);
-void simple_util_clean_reference(struct snd_soc_card *card)
+void simple_util_clean_reference(struct simple_util_priv *priv)
{
struct snd_soc_dai_link *dai_link;
struct snd_soc_dai_link_component *cpu;
struct snd_soc_dai_link_component *codec;
+ struct snd_soc_card *card = simple_priv_to_card(priv);
int i, j;
for_each_card_prelinks(card, i, dai_link) {
@@ -747,57 +769,6 @@ void simple_util_clean_reference(struct snd_soc_card *card)
}
EXPORT_SYMBOL_GPL(simple_util_clean_reference);
-int simple_util_parse_routing(struct snd_soc_card *card,
- char *prefix)
-{
- struct device_node *node = card->dev->of_node;
- char prop[128];
-
- if (!prefix)
- prefix = "";
-
- snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
-
- if (!of_property_present(node, prop))
- return 0;
-
- return snd_soc_of_parse_audio_routing(card, prop);
-}
-EXPORT_SYMBOL_GPL(simple_util_parse_routing);
-
-int simple_util_parse_widgets(struct snd_soc_card *card,
- char *prefix)
-{
- struct device_node *node = card->dev->of_node;
- char prop[128];
-
- if (!prefix)
- prefix = "";
-
- snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
-
- if (of_property_present(node, prop))
- return snd_soc_of_parse_audio_simple_widgets(card, prop);
-
- /* no widgets is not error */
- return 0;
-}
-EXPORT_SYMBOL_GPL(simple_util_parse_widgets);
-
-int simple_util_parse_pin_switches(struct snd_soc_card *card,
- char *prefix)
-{
- char prop[128];
-
- if (!prefix)
- prefix = "";
-
- snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches");
-
- return snd_soc_of_parse_pin_switches(card, prop);
-}
-EXPORT_SYMBOL_GPL(simple_util_parse_pin_switches);
-
int simple_util_init_jack(struct snd_soc_card *card,
struct simple_util_jack *sjack,
int is_hp, char *prefix,
@@ -854,9 +825,9 @@ int simple_util_init_jack(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(simple_util_init_jack);
-int simple_util_init_aux_jacks(struct simple_util_priv *priv, char *prefix)
+int simple_util_init_aux_jacks(struct snd_soc_card *card, char *prefix)
{
- struct snd_soc_card *card = simple_priv_to_card(priv);
+ struct simple_util_priv *priv = snd_soc_card_get_drvdata(card);
struct snd_soc_component *component;
int found_jack_index = 0;
int type = 0;
@@ -1026,8 +997,9 @@ EXPORT_SYMBOL_GPL(simple_util_init_priv);
void simple_util_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct simple_util_priv *priv = snd_soc_card_get_drvdata(card);
- simple_util_clean_reference(card);
+ simple_util_clean_reference(priv);
}
EXPORT_SYMBOL_GPL(simple_util_remove);
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index b4957e025211..e7ad7af04714 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -517,44 +517,6 @@ end:
return simple_ret(priv, ret);
}
-static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li)
-{
- struct snd_soc_card *card = simple_priv_to_card(priv);
- int ret;
-
- ret = simple_util_parse_widgets(card, PREFIX);
- if (ret < 0)
- goto end;
-
- ret = simple_util_parse_routing(card, PREFIX);
- if (ret < 0)
- goto end;
-
- ret = simple_util_parse_pin_switches(card, PREFIX);
- if (ret < 0)
- goto end;
-
- /* Single/Muti DAI link(s) & New style of DT node */
- memset(li, 0, sizeof(*li));
- ret = simple_for_each_link(priv, li,
- simple_dai_link_of,
- simple_dai_link_of_dpcm);
- if (ret < 0)
- goto end;
-
- ret = simple_util_parse_card_name(priv, PREFIX);
- if (ret < 0)
- goto end;
-
- ret = simple_populate_aux(priv);
- if (ret < 0)
- goto end;
-
- ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs");
-end:
- return simple_ret(priv, ret);
-}
-
static int simple_count_noml(struct simple_util_priv *priv,
struct device_node *np,
struct device_node *codec,
@@ -699,28 +661,19 @@ static int simple_soc_probe(struct snd_soc_card *card)
if (ret < 0)
goto end;
- ret = simple_util_init_aux_jacks(priv, PREFIX);
+ ret = simple_util_init_aux_jacks(card, PREFIX);
end:
return simple_ret(priv, ret);
}
-static int simple_probe(struct platform_device *pdev)
+static int simple_parse_of(struct simple_util_priv *priv)
{
- struct simple_util_priv *priv;
- struct device *dev = &pdev->dev;
- struct snd_soc_card *card;
- int ret;
-
- /* Allocate the private data and the DAI link array */
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
+ struct snd_soc_card *card = simple_priv_to_card(priv);
+ struct device *dev = card->dev;
+ int ret = -EINVAL;
- card = simple_priv_to_card(priv);
- card->owner = THIS_MODULE;
- card->dev = dev;
- card->probe = simple_soc_probe;
- card->driver_name = "simple-card";
+ if (!dev)
+ return simple_ret(priv, ret);
ret = -ENOMEM;
struct link_info *li __free(kfree) = kzalloc_obj(*li);
@@ -739,25 +692,71 @@ static int simple_probe(struct platform_device *pdev)
if (ret < 0)
goto end;
- ret = simple_parse_of(priv, li);
- if (ret < 0) {
- dev_err_probe(dev, ret, "parse error\n");
+ ret = simple_util_parse_widgets(priv, PREFIX);
+ if (ret < 0)
+ goto end;
+
+ ret = simple_util_parse_routing(priv, PREFIX);
+ if (ret < 0)
+ goto end;
+
+ ret = simple_util_parse_pin_switches(priv, PREFIX);
+ if (ret < 0)
+ goto end;
+
+ ret = simple_util_parse_aux_devs(priv, PREFIX);
+ if (ret < 0)
goto err;
- }
- snd_soc_card_set_drvdata(card, priv);
+ /* Single/Muti DAI link(s) & New style of DT node */
+ memset(li, 0, sizeof(*li));
+ ret = simple_for_each_link(priv, li,
+ simple_dai_link_of,
+ simple_dai_link_of_dpcm);
+ if (ret < 0)
+ goto err;
- simple_util_debug_info(priv);
+ /* Card name should be set after simple_for_each_link() */
+ ret = simple_util_parse_card_name(priv, PREFIX);
+ if (ret < 0)
+ goto err;
- ret = devm_snd_soc_register_card(dev, card);
+ ret = simple_populate_aux(priv);
if (ret < 0)
goto err;
- return 0;
+ snd_soc_card_set_drvdata(card, priv);
+
+ simple_util_debug_info(priv);
+
+ ret = devm_snd_soc_register_card(dev, card);
err:
- simple_util_clean_reference(card);
+ if (ret < 0) {
+ simple_util_clean_reference(priv);
+ return dev_err_probe(dev, ret, "parse error\n");
+ }
end:
- return dev_err_probe(dev, ret, "parse error\n");
+ return simple_ret(priv, ret);
+}
+
+static int simple_probe(struct platform_device *pdev)
+{
+ struct simple_util_priv *priv;
+ struct device *dev = &pdev->dev;
+ struct snd_soc_card *card;
+
+ /* Allocate the private data and the DAI link array */
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ card = simple_priv_to_card(priv);
+ card->owner = THIS_MODULE;
+ card->dev = dev;
+ card->probe = simple_soc_probe;
+ card->driver_name = "simple-card";
+
+ return simple_parse_of(priv);
}
static const struct of_device_id simple_of_match[] = {
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c
index 3629ceaaac17..82df398237da 100644
--- a/sound/soc/intel/atom/sst-atom-controls.c
+++ b/sound/soc/intel/atom/sst-atom-controls.c
@@ -14,6 +14,7 @@
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/cleanup.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/tlv.h>
@@ -73,14 +74,10 @@ static int sst_fill_and_send_cmd(struct sst_data *drv,
u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
void *cmd_data, u16 len)
{
- int ret;
+ guard(mutex)(&drv->lock);
- mutex_lock(&drv->lock);
- ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block,
- task_id, pipe_id, cmd_data, len);
- mutex_unlock(&drv->lock);
-
- return ret;
+ return sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block,
+ task_id, pipe_id, cmd_data, len);
}
/*
@@ -167,7 +164,7 @@ static int sst_slot_get(struct snd_kcontrol *kcontrol,
unsigned int val, mux;
u8 *map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map;
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
val = 1 << ctl_no;
/* search which slot/channel has this bit set - there should be only one */
for (mux = e->max; mux > 0; mux--)
@@ -175,7 +172,6 @@ static int sst_slot_get(struct snd_kcontrol *kcontrol,
break;
ucontrol->value.enumerated.item[0] = mux;
- mutex_unlock(&drv->lock);
dev_dbg(c->dev, "%s - %s map = %#x\n",
is_tx ? "tx channel" : "rx slot",
@@ -235,7 +231,7 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol,
if (mux > e->max - 1)
return -EINVAL;
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
/* first clear all registers of this bit */
for (i = 0; i < e->max; i++)
map[i] &= ~val;
@@ -244,7 +240,6 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol,
/* kctl set to 'none' and we reset the bits so send IPC */
ret = sst_check_and_send_slot_map(drv, kcontrol);
- mutex_unlock(&drv->lock);
return ret;
}
@@ -258,7 +253,6 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol,
ret = sst_check_and_send_slot_map(drv, kcontrol);
- mutex_unlock(&drv->lock);
return ret;
}
@@ -354,13 +348,12 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
struct sst_algo_control *bc = (void *)kcontrol->private_value;
dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name);
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
switch (bc->type) {
case SST_ALGO_PARAMS:
memcpy(bc->params, ucontrol->value.bytes.data, bc->max);
break;
default:
- mutex_unlock(&drv->lock);
dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n",
bc->type);
return -EINVAL;
@@ -368,7 +361,6 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
/*if pipe is enabled, need to send the algo params from here*/
if (bc->w && bc->w->power)
ret = sst_send_algo_cmd(drv, bc);
- mutex_unlock(&drv->lock);
return ret;
}
@@ -475,7 +467,7 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol,
struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value;
struct sst_gain_value *gv = mc->gain_val;
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
switch (mc->type) {
case SST_GAIN_TLV:
@@ -497,7 +489,6 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol,
break;
default:
- mutex_unlock(&drv->lock);
dev_err(cmpnt->dev, "Invalid Input- gain type:%d\n",
mc->type);
return -EINVAL;
@@ -506,7 +497,6 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol,
if (mc->w && mc->w->power)
ret = sst_send_gain_cmd(drv, gv, mc->task_id,
mc->pipe_id | mc->instance_id, mc->module_id, 0);
- mutex_unlock(&drv->lock);
return ret;
}
@@ -521,10 +511,9 @@ static int sst_send_pipe_module_params(struct snd_soc_dapm_widget *w,
struct sst_data *drv = snd_soc_component_get_drvdata(c);
struct sst_ids *ids = w->priv;
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
sst_find_and_send_pipe_algo(drv, w->name, ids);
sst_set_pipe_gain(ids, drv, 0);
- mutex_unlock(&drv->lock);
return 0;
}
@@ -761,27 +750,29 @@ int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable)
return ret;
}
- mutex_lock(&drv->lock);
- if (enable)
- timer_usage++;
- else
- timer_usage--;
-
- /*
- * Send the command only if this call is the first enable or last
- * disable
- */
- if ((enable && (timer_usage == 1)) ||
- (!enable && (timer_usage == 0))) {
- ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD,
- SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd,
- sizeof(cmd.header) + cmd.header.length);
- if (ret && enable) {
+ scoped_guard(mutex, &drv->lock) {
+ if (enable)
+ timer_usage++;
+ else
timer_usage--;
- enable = false;
+
+ /*
+ * Send the command only if this call is the first enable or last
+ * disable
+ */
+ if ((enable && timer_usage == 1) ||
+ (!enable && timer_usage == 0)) {
+ ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD,
+ SST_FLAG_BLOCKED,
+ SST_TASK_SBA, 0, &cmd,
+ sizeof(cmd.header) +
+ cmd.header.length);
+ if (ret && enable) {
+ timer_usage--;
+ enable = false;
+ }
}
}
- mutex_unlock(&drv->lock);
if (!enable)
sst->ops->power(sst->dev, false);
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index f074af2499c8..a4c8cbfba096 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -11,6 +11,7 @@
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/cleanup.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -32,7 +33,7 @@ int sst_register_dsp(struct sst_device *dev)
return -EINVAL;
if (!try_module_get(dev->dev->driver->owner))
return -ENODEV;
- mutex_lock(&sst_lock);
+ guard(mutex)(&sst_lock);
if (sst) {
dev_err(dev->dev, "we already have a device %s\n", sst->name);
module_put(dev->dev->driver->owner);
@@ -41,7 +42,7 @@ int sst_register_dsp(struct sst_device *dev)
}
dev_dbg(dev->dev, "registering device %s\n", dev->name);
sst = dev;
- mutex_unlock(&sst_lock);
+
return 0;
}
EXPORT_SYMBOL_GPL(sst_register_dsp);
@@ -53,17 +54,15 @@ int sst_unregister_dsp(struct sst_device *dev)
if (dev != sst)
return -EINVAL;
- mutex_lock(&sst_lock);
+ guard(mutex)(&sst_lock);
- if (!sst) {
- mutex_unlock(&sst_lock);
+ if (!sst)
return -EIO;
- }
module_put(sst->dev->driver->owner);
dev_dbg(dev->dev, "unreg %s\n", sst->name);
sst = NULL;
- mutex_unlock(&sst_lock);
+
return 0;
}
EXPORT_SYMBOL_GPL(sst_unregister_dsp);
@@ -103,21 +102,14 @@ static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
void sst_set_stream_status(struct sst_runtime_stream *stream,
int state)
{
- unsigned long flags;
- spin_lock_irqsave(&stream->status_lock, flags);
+ guard(spinlock_irqsave)(&stream->status_lock);
stream->stream_status = state;
- spin_unlock_irqrestore(&stream->status_lock, flags);
}
static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
{
- int state;
- unsigned long flags;
-
- spin_lock_irqsave(&stream->status_lock, flags);
- state = stream->stream_status;
- spin_unlock_irqrestore(&stream->status_lock, flags);
- return state;
+ guard(spinlock_irqsave)(&stream->status_lock);
+ return stream->stream_status;
}
static void sst_fill_alloc_params(struct snd_pcm_substream *substream,
@@ -244,12 +236,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
stream->stream_info.str_id = str_params.stream_id;
- ret_val = stream->ops->open(sst->dev, &str_params);
- if (ret_val <= 0)
- return ret_val;
-
-
- return ret_val;
+ return stream->ops->open(sst->dev, &str_params);
}
static void sst_period_elapsed(void *arg)
@@ -304,7 +291,7 @@ static int sst_media_open(struct snd_pcm_substream *substream,
{
int ret_val = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
- struct sst_runtime_stream *stream;
+ struct sst_runtime_stream *stream __free(kfree) = NULL;
stream = kzalloc_obj(*stream);
if (!stream)
@@ -312,15 +299,14 @@ static int sst_media_open(struct snd_pcm_substream *substream,
spin_lock_init(&stream->status_lock);
/* get the sst ops */
- mutex_lock(&sst_lock);
- if (!sst ||
- !try_module_get(sst->dev->driver->owner)) {
- dev_err(dai->dev, "no device available to run\n");
- ret_val = -ENODEV;
- goto out_ops;
+ scoped_guard(mutex, &sst_lock) {
+ if (!sst ||
+ !try_module_get(sst->dev->driver->owner)) {
+ dev_err(dai->dev, "no device available to run\n");
+ return -ENODEV;
+ }
+ stream->ops = sst->ops;
}
- stream->ops = sst->ops;
- mutex_unlock(&sst_lock);
stream->stream_info.str_id = 0;
@@ -330,7 +316,7 @@ static int sst_media_open(struct snd_pcm_substream *substream,
ret_val = power_up_sst(stream);
if (ret_val < 0)
- goto out_power_up;
+ return ret_val;
/*
* Make sure the period to be multiple of 1ms to align the
@@ -347,12 +333,14 @@ static int sst_media_open(struct snd_pcm_substream *substream,
snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIODS, 2);
- return snd_pcm_hw_constraint_integer(runtime,
- SNDRV_PCM_HW_PARAM_PERIODS);
-out_ops:
- mutex_unlock(&sst_lock);
-out_power_up:
- kfree(stream);
+ ret_val = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+
+ if (ret_val < 0)
+ return ret_val;
+
+ stream = NULL;
+
return ret_val;
}
diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c
index 0d5e71e8a5b5..6c19ab63aa4f 100644
--- a/sound/soc/intel/atom/sst/sst_ipc.c
+++ b/sound/soc/intel/atom/sst/sst_ipc.c
@@ -11,6 +11,7 @@
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
+#include <linux/cleanup.h>
#include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/sched.h>
@@ -180,9 +181,8 @@ void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx)
union interrupt_reg_mrfld isr;
union interrupt_reg_mrfld imr;
union ipc_header_mrfld clear_ipc;
- unsigned long irq_flags;
- spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+ guard(spinlock_irqsave)(&sst_drv_ctx->ipc_spin_lock);
imr.full = sst_shim_read64(sst_drv_ctx->shim, SST_IMRX);
isr.full = sst_shim_read64(sst_drv_ctx->shim, SST_ISRX);
@@ -200,7 +200,6 @@ void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx)
/* un mask busy interrupt */
imr.part.busy_interrupt = 0;
sst_shim_write64(sst_drv_ctx->shim, SST_IMRX, imr.full);
- spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
}
diff --git a/sound/soc/intel/atom/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c
index 22ae2d22f121..44bb11c69490 100644
--- a/sound/soc/intel/atom/sst/sst_pci.c
+++ b/sound/soc/intel/atom/sst/sst_pci.c
@@ -130,13 +130,15 @@ static int intel_sst_probe(struct pci_dev *pci,
sst_drv_ctx->pci = pci_dev_get(pci);
ret = sst_platform_get_resources(sst_drv_ctx);
if (ret < 0)
- goto do_free_drv_ctx;
+ goto do_put_pci;
pci_set_drvdata(pci, sst_drv_ctx);
sst_configure_runtime_pm(sst_drv_ctx);
return ret;
+do_put_pci:
+ pci_dev_put(sst_drv_ctx->pci);
do_free_drv_ctx:
sst_context_cleanup(sst_drv_ctx);
dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret);
diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c
index 67b1ab14239f..0b0cfd70efbc 100644
--- a/sound/soc/intel/atom/sst/sst_pvt.c
+++ b/sound/soc/intel/atom/sst/sst_pvt.c
@@ -11,6 +11,7 @@
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
+#include <linux/cleanup.h>
#include <linux/kobject.h>
#include <linux/pci.h>
#include <linux/fs.h>
@@ -64,9 +65,8 @@ u64 sst_shim_read64(void __iomem *addr, int offset)
void sst_set_fw_state_locked(
struct intel_sst_drv *sst_drv_ctx, int sst_state)
{
- mutex_lock(&sst_drv_ctx->sst_lock);
+ guard(mutex)(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = sst_state;
- mutex_unlock(&sst_drv_ctx->sst_lock);
}
/*
@@ -302,18 +302,17 @@ int sst_assign_pvt_id(struct intel_sst_drv *drv)
{
int local;
- spin_lock(&drv->block_lock);
+ guard(spinlock)(&drv->block_lock);
/* find first zero index from lsb */
local = ffz(drv->pvt_id);
dev_dbg(drv->dev, "pvt_id assigned --> %d\n", local);
if (local >= SST_MAX_BLOCKS){
- spin_unlock(&drv->block_lock);
dev_err(drv->dev, "PVT _ID error: no free id blocks ");
return -EINVAL;
}
/* toggle the index */
change_bit(local, &drv->pvt_id);
- spin_unlock(&drv->block_lock);
+
return local;
}
diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c
index b922eeaba843..cf600e1c986e 100644
--- a/sound/soc/intel/avs/apl.c
+++ b/sound/soc/intel/avs/apl.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/devcoredump.h>
#include <linux/slab.h>
#include <sound/hdaudio_ext.h>
@@ -190,7 +191,7 @@ static bool avs_apl_lp_streaming(struct avs_dev *adev)
{
struct avs_path *path;
- spin_lock(&adev->path_list_lock);
+ guard(spinlock)(&adev->path_list_lock);
/* Any gateway without buffer allocated in LP area disqualifies D0IX. */
list_for_each_entry(path, &adev->path_list, node) {
struct avs_path_pipeline *ppl;
@@ -210,14 +211,11 @@ static bool avs_apl_lp_streaming(struct avs_dev *adev)
if (cfg->copier.dma_type == INVALID_OBJECT_ID)
continue;
- if (!mod->gtw_attrs.lp_buffer_alloc) {
- spin_unlock(&adev->path_list_lock);
+ if (!mod->gtw_attrs.lp_buffer_alloc)
return false;
- }
}
}
}
- spin_unlock(&adev->path_list_lock);
return true;
}
diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c
index 2b17abcbd2bc..b7bdd8a690cf 100644
--- a/sound/soc/intel/avs/boards/da7219.c
+++ b/sound/soc/intel/avs/boards/da7219.c
@@ -175,7 +175,6 @@ static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
if (!dl || !platform)
return -ENOMEM;
- dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
dl->name = devm_kasprintf(dev, GFP_KERNEL,
AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
@@ -259,10 +258,8 @@ static int avs_da7219_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_da7219_driver_ids[] = {
- {
- .name = "avs_da7219",
- },
- {},
+ { .name = "avs_da7219" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_da7219_driver_ids);
diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c
index bf6f580a5164..8d36bc7ddf16 100644
--- a/sound/soc/intel/avs/boards/dmic.c
+++ b/sound/soc/intel/avs/boards/dmic.c
@@ -104,10 +104,8 @@ static int avs_dmic_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_dmic_driver_ids[] = {
- {
- .name = "avs_dmic",
- },
- {},
+ { .name = "avs_dmic" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_dmic_driver_ids);
diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c
index 301cfb3cf15b..36c13db3a272 100644
--- a/sound/soc/intel/avs/boards/es8336.c
+++ b/sound/soc/intel/avs/boards/es8336.c
@@ -309,10 +309,8 @@ static int avs_es8336_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_es8336_driver_ids[] = {
- {
- .name = "avs_es8336",
- },
- {},
+ { .name = "avs_es8336" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_es8336_driver_ids);
diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c
index aec769e2396c..03cfd91202d3 100644
--- a/sound/soc/intel/avs/boards/hdaudio.c
+++ b/sound/soc/intel/avs/boards/hdaudio.c
@@ -231,10 +231,8 @@ static int avs_hdaudio_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_hdaudio_driver_ids[] = {
- {
- .name = "avs_hdaudio",
- },
- {},
+ { .name = "avs_hdaudio" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_hdaudio_driver_ids);
diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c
index 9a6b89ffdf14..787d781ba1d9 100644
--- a/sound/soc/intel/avs/boards/i2s_test.c
+++ b/sound/soc/intel/avs/boards/i2s_test.c
@@ -107,10 +107,8 @@ static int avs_i2s_test_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_i2s_test_driver_ids[] = {
- {
- .name = "avs_i2s_test",
- },
- {},
+ { .name = "avs_i2s_test" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_i2s_test_driver_ids);
diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c
index e9a87804f918..389a50923d3b 100644
--- a/sound/soc/intel/avs/boards/max98357a.c
+++ b/sound/soc/intel/avs/boards/max98357a.c
@@ -136,10 +136,8 @@ static int avs_max98357a_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_max98357a_driver_ids[] = {
- {
- .name = "avs_max98357a",
- },
- {},
+ { .name = "avs_max98357a" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_max98357a_driver_ids);
diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c
index 8b45b643ca29..b8231f71d3d6 100644
--- a/sound/soc/intel/avs/boards/max98373.c
+++ b/sound/soc/intel/avs/boards/max98373.c
@@ -191,10 +191,8 @@ static int avs_max98373_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_max98373_driver_ids[] = {
- {
- .name = "avs_max98373",
- },
- {},
+ { .name = "avs_max98373" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_max98373_driver_ids);
diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c
index db073125fa4d..d657e7da1cc0 100644
--- a/sound/soc/intel/avs/boards/max98927.c
+++ b/sound/soc/intel/avs/boards/max98927.c
@@ -188,10 +188,8 @@ static int avs_max98927_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_max98927_driver_ids[] = {
- {
- .name = "avs_max98927",
- },
- {},
+ { .name = "avs_max98927" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_max98927_driver_ids);
diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c
index d44edacbfc9a..d7ea08bb27cd 100644
--- a/sound/soc/intel/avs/boards/nau8825.c
+++ b/sound/soc/intel/avs/boards/nau8825.c
@@ -293,10 +293,8 @@ static int avs_nau8825_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_nau8825_driver_ids[] = {
- {
- .name = "avs_nau8825",
- },
- {},
+ { .name = "avs_nau8825" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_nau8825_driver_ids);
diff --git a/sound/soc/intel/avs/boards/pcm3168a.c b/sound/soc/intel/avs/boards/pcm3168a.c
index b5bebadbbcb2..9d415fd0499a 100644
--- a/sound/soc/intel/avs/boards/pcm3168a.c
+++ b/sound/soc/intel/avs/boards/pcm3168a.c
@@ -132,10 +132,8 @@ static int avs_pcm3168a_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_pcm3168a_driver_ids[] = {
- {
- .name = "avs_pcm3168a",
- },
- {},
+ { .name = "avs_pcm3168a" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_pcm3168a_driver_ids);
diff --git a/sound/soc/intel/avs/boards/probe.c b/sound/soc/intel/avs/boards/probe.c
index 73884f8a535c..4053d14289b9 100644
--- a/sound/soc/intel/avs/boards/probe.c
+++ b/sound/soc/intel/avs/boards/probe.c
@@ -64,7 +64,7 @@ static const struct platform_device_id avs_probe_mb_driver_ids[] = {
{
.name = "avs_probe_mb",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_probe_mb_driver_ids);
diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c
index a689f4c80867..289f1230851f 100644
--- a/sound/soc/intel/avs/boards/rt274.c
+++ b/sound/soc/intel/avs/boards/rt274.c
@@ -261,7 +261,7 @@ static const struct platform_device_id avs_rt274_driver_ids[] = {
{
.name = "avs_rt274",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_rt274_driver_ids);
diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c
index 4c9ac545555a..9364d60cfcc7 100644
--- a/sound/soc/intel/avs/boards/rt286.c
+++ b/sound/soc/intel/avs/boards/rt286.c
@@ -231,7 +231,7 @@ static const struct platform_device_id avs_rt286_driver_ids[] = {
{
.name = "avs_rt286",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_rt286_driver_ids);
diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c
index 2d7a7748d577..5d3b3cdc9564 100644
--- a/sound/soc/intel/avs/boards/rt298.c
+++ b/sound/soc/intel/avs/boards/rt298.c
@@ -250,7 +250,7 @@ static const struct platform_device_id avs_rt298_driver_ids[] = {
{
.name = "avs_rt298",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_rt298_driver_ids);
diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c
index 22139eaad83a..e448bc9fa5ad 100644
--- a/sound/soc/intel/avs/boards/rt5514.c
+++ b/sound/soc/intel/avs/boards/rt5514.c
@@ -178,7 +178,7 @@ static const struct platform_device_id avs_rt5514_driver_ids[] = {
{
.name = "avs_rt5514",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_rt5514_driver_ids);
diff --git a/sound/soc/intel/avs/boards/rt5640.c b/sound/soc/intel/avs/boards/rt5640.c
index 2990d32f2301..c4e33d71e82f 100644
--- a/sound/soc/intel/avs/boards/rt5640.c
+++ b/sound/soc/intel/avs/boards/rt5640.c
@@ -252,7 +252,7 @@ static const struct platform_device_id avs_rt5640_driver_ids[] = {
{
.name = "avs_rt5640",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_rt5640_driver_ids);
diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c
index 68fea325376a..aadbd3f2a1b2 100644
--- a/sound/soc/intel/avs/boards/rt5663.c
+++ b/sound/soc/intel/avs/boards/rt5663.c
@@ -249,7 +249,7 @@ static const struct platform_device_id avs_rt5663_driver_ids[] = {
{
.name = "avs_rt5663",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_rt5663_driver_ids);
diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c
index 81863728da1d..d33699cca595 100644
--- a/sound/soc/intel/avs/boards/rt5682.c
+++ b/sound/soc/intel/avs/boards/rt5682.c
@@ -325,7 +325,7 @@ static const struct platform_device_id avs_rt5682_driver_ids[] = {
{
.name = "avs_rt5682",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_rt5682_driver_ids);
diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c
index ae0e6e27a8b8..d7c9bff37556 100644
--- a/sound/soc/intel/avs/boards/ssm4567.c
+++ b/sound/soc/intel/avs/boards/ssm4567.c
@@ -180,7 +180,7 @@ static const struct platform_device_id avs_ssm4567_driver_ids[] = {
{
.name = "avs_ssm4567",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_ssm4567_driver_ids);
diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c
index a8f05de338e0..370069247a7d 100644
--- a/sound/soc/intel/avs/control.c
+++ b/sound/soc/intel/avs/control.c
@@ -27,7 +27,7 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i
struct avs_path_pipeline *ppl;
struct avs_path_module *mod;
- spin_lock(&adev->path_list_lock);
+ guard(spinlock)(&adev->path_list_lock);
list_for_each_entry(path, &adev->path_list, node) {
list_for_each_entry(ppl, &path->ppl_list, node) {
list_for_each_entry(mod, &ppl->mod_list, node) {
@@ -35,14 +35,11 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i
if ((guid_equal(type, &AVS_PEAKVOL_MOD_UUID) ||
guid_equal(type, &AVS_GAIN_MOD_UUID)) &&
- mod->template->ctl_id == id) {
- spin_unlock(&adev->path_list_lock);
+ mod->template->ctl_id == id)
return mod;
- }
}
}
}
- spin_unlock(&adev->path_list_lock);
return NULL;
}
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index 1a53856c2ffb..2afe59646896 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -14,6 +14,7 @@
// foundation of this driver
//
+#include <linux/cleanup.h>
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -273,7 +274,7 @@ static irqreturn_t avs_hda_interrupt(struct hdac_bus *bus)
if (snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream))
ret = IRQ_HANDLED;
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
/* Clear RIRB interrupt. */
status = snd_hdac_chip_readb(bus, RIRBSTS);
if (status & RIRB_INT_MASK) {
@@ -283,7 +284,6 @@ static irqreturn_t avs_hda_interrupt(struct hdac_bus *bus)
ret = IRQ_HANDLED;
}
- spin_unlock_irq(&bus->reg_lock);
return ret;
}
diff --git a/sound/soc/intel/avs/debug.h b/sound/soc/intel/avs/debug.h
index 94fe8729a5c1..c47fc4e8b02b 100644
--- a/sound/soc/intel/avs/debug.h
+++ b/sound/soc/intel/avs/debug.h
@@ -9,6 +9,7 @@
#ifndef __SOUND_SOC_INTEL_AVS_DEBUG_H
#define __SOUND_SOC_INTEL_AVS_DEBUG_H
+#include <linux/cleanup.h>
#include "messages.h"
#include "registers.h"
@@ -26,14 +27,9 @@ struct avs_dev;
static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg)
{
- unsigned long flags;
- int ret;
+ guard(spinlock_irqsave)(&adev->trace_lock);
- spin_lock_irqsave(&adev->trace_lock, flags);
- ret = avs_dsp_op(adev, log_buffer_status, msg);
- spin_unlock_irqrestore(&adev->trace_lock, flags);
-
- return ret;
+ return avs_dsp_op(adev, log_buffer_status, msg);
}
struct avs_apl_log_buffer_layout {
diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c
index 701c247227bf..9ab503da3b75 100644
--- a/sound/soc/intel/avs/debugfs.c
+++ b/sound/soc/intel/avs/debugfs.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/kfifo.h>
#include <linux/wait.h>
@@ -251,24 +252,22 @@ static int strace_release(struct inode *inode, struct file *file)
union avs_notify_msg msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS);
struct avs_dev *adev = file->private_data;
unsigned long resource_mask;
- unsigned long flags, i;
+ unsigned long i;
u32 num_cores;
resource_mask = adev->logged_resources;
num_cores = adev->hw_cfg.dsp_cores;
- spin_lock_irqsave(&adev->trace_lock, flags);
+ scoped_guard(spinlock_irqsave, &adev->trace_lock) {
+ /* Gather any remaining logs. */
+ for_each_set_bit(i, &resource_mask, num_cores) {
+ msg.log.core = i;
+ avs_dsp_op(adev, log_buffer_status, &msg);
+ }
- /* Gather any remaining logs. */
- for_each_set_bit(i, &resource_mask, num_cores) {
- msg.log.core = i;
- avs_dsp_op(adev, log_buffer_status, &msg);
+ kfifo_free(&adev->trace_fifo);
}
- kfifo_free(&adev->trace_fifo);
-
- spin_unlock_irqrestore(&adev->trace_lock, flags);
-
module_put(adev->dev->driver->owner);
return 0;
}
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index c0feb9edd7f6..71e7997e52c2 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/slab.h>
#include <sound/hdaudio_ext.h>
@@ -99,39 +100,39 @@ static void avs_dsp_recovery(struct avs_dev *adev)
unsigned int core_mask;
int ret;
- mutex_lock(&adev->comp_list_mutex);
- /* disconnect all running streams */
- list_for_each_entry(acomp, &adev->comp_list, node) {
- struct snd_soc_pcm_runtime *rtd;
- struct snd_soc_card *card;
+ scoped_guard(mutex, &adev->comp_list_mutex) {
+ /* disconnect all running streams */
+ list_for_each_entry(acomp, &adev->comp_list, node) {
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_card *card;
- card = acomp->base.card;
- if (!card)
- continue;
-
- for_each_card_rtds(card, rtd) {
- struct snd_pcm *pcm;
- int dir;
-
- pcm = rtd->pcm;
- if (!pcm || rtd->dai_link->no_pcm)
+ card = acomp->base.card;
+ if (!card)
continue;
- for_each_pcm_streams(dir) {
- struct snd_pcm_substream *substream;
+ for_each_card_rtds(card, rtd) {
+ struct snd_pcm *pcm;
+ int dir;
- substream = pcm->streams[dir].substream;
- if (!substream || !substream->runtime)
+ pcm = rtd->pcm;
+ if (!pcm || rtd->dai_link->no_pcm)
continue;
- /* No need for _irq() as we are in nonatomic context. */
- snd_pcm_stream_lock(substream);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
- snd_pcm_stream_unlock(substream);
+ for_each_pcm_streams(dir) {
+ struct snd_pcm_substream *substream;
+
+ substream = pcm->streams[dir].substream;
+ if (!substream || !substream->runtime)
+ continue;
+
+ /* No need for _irq() as we are in nonatomic context. */
+ snd_pcm_stream_lock(substream);
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
+ snd_pcm_stream_unlock(substream);
+ }
}
}
}
- mutex_unlock(&adev->comp_list_mutex);
/* forcibly shutdown all cores */
core_mask = GENMASK(adev->hw_cfg.dsp_cores - 1, 0);
@@ -397,7 +398,7 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
if (!ipc->ready)
return -EPERM;
- mutex_lock(&ipc->msg_mutex);
+ guard(mutex)(&ipc->msg_mutex);
spin_lock(&ipc->rx_lock);
avs_ipc_msg_init(ipc, reply);
@@ -412,7 +413,7 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
/* Same treatment as on exception, just stack_dump=0. */
avs_dsp_exception_caught(adev, &msg);
}
- goto exit;
+ return ret;
}
ret = ipc->rx.rsp.status;
@@ -436,8 +437,6 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
memcpy(reply->data, ipc->rx.data, reply->size);
}
-exit:
- mutex_unlock(&ipc->msg_mutex);
return ret;
}
@@ -501,7 +500,7 @@ static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *req
struct avs_ipc *ipc = adev->ipc;
int ret;
- mutex_lock(&ipc->msg_mutex);
+ guard(mutex)(&ipc->msg_mutex);
spin_lock(&ipc->rx_lock);
avs_ipc_msg_init(ipc, NULL);
@@ -522,8 +521,6 @@ static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *req
dev_err(adev->dev, "%s (0x%08x 0x%08x) failed: %d\n",
name, request->glb.primary, request->glb.ext.val, ret);
- mutex_unlock(&ipc->msg_mutex);
-
return ret;
}
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index 353e343b1d28..bebdc79ec88e 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -630,15 +631,15 @@ static int avs_load_firmware(struct avs_dev *adev, bool purge)
if (ret)
goto reenable_gating;
- mutex_lock(&adev->comp_list_mutex);
- list_for_each_entry(acomp, &adev->comp_list, node) {
- struct avs_tplg *tplg = acomp->tplg;
+ scoped_guard(mutex, &adev->comp_list_mutex) {
+ list_for_each_entry(acomp, &adev->comp_list, node) {
+ struct avs_tplg *tplg = acomp->tplg;
- ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs);
- if (ret < 0)
- break;
+ ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs);
+ if (ret < 0)
+ break;
+ }
}
- mutex_unlock(&adev->comp_list_mutex);
reenable_gating:
avs_hda_l1sen_enable(adev, true);
diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c
index 2291f9728a54..213d6ecdd7cc 100644
--- a/sound/soc/intel/avs/path.c
+++ b/sound/soc/intel/avs/path.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/acpi.h>
#include <acpi/nhlt.h>
#include <sound/pcm_params.h>
@@ -69,16 +70,13 @@ avs_path_find_path(struct avs_dev *adev, const char *name, u32 template_id)
if (!template)
return NULL;
- spin_lock(&adev->path_list_lock);
+ guard(spinlock)(&adev->path_list_lock);
/* Only one variant of given path template may be instantiated at a time. */
list_for_each_entry(path, &adev->path_list, node) {
- if (path->template->owner == template) {
- spin_unlock(&adev->path_list_lock);
+ if (path->template->owner == template)
return path;
- }
}
- spin_unlock(&adev->path_list_lock);
return NULL;
}
@@ -1305,7 +1303,7 @@ void avs_path_free(struct avs_path *path)
struct avs_path *cpath, *csave;
struct avs_dev *adev = path->owner;
- mutex_lock(&adev->path_mutex);
+ guard(mutex)(&adev->path_mutex);
/* Free all condpaths this path spawned. */
list_for_each_entry_safe(cpath, csave, &path->source_list, source_node)
@@ -1314,8 +1312,6 @@ void avs_path_free(struct avs_path *path)
avs_condpath_free(path->owner, cpath);
avs_path_free_unlocked(path);
-
- mutex_unlock(&adev->path_mutex);
}
struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
@@ -1334,13 +1330,13 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
}
/* Serialize path and its components creation. */
- mutex_lock(&adev->path_mutex);
+ guard(mutex)(&adev->path_mutex);
/* Satisfy needs of avs_path_find_tplg(). */
- mutex_lock(&adev->comp_list_mutex);
+ guard(mutex)(&adev->comp_list_mutex);
path = avs_path_create_unlocked(adev, dma_id, variant);
if (IS_ERR(path))
- goto exit;
+ return path;
ret = avs_condpaths_walk_all(adev, path);
if (ret) {
@@ -1348,10 +1344,6 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
path = ERR_PTR(ret);
}
-exit:
- mutex_unlock(&adev->comp_list_mutex);
- mutex_unlock(&adev->path_mutex);
-
return path;
}
@@ -1496,15 +1488,13 @@ static void avs_condpaths_pause(struct avs_dev *adev, struct avs_path *path)
{
struct avs_path *cpath;
- mutex_lock(&adev->path_mutex);
+ guard(mutex)(&adev->path_mutex);
/* If either source or sink stops, so do the attached conditional paths. */
list_for_each_entry(cpath, &path->source_list, source_node)
avs_condpath_pause(adev, cpath);
list_for_each_entry(cpath, &path->sink_list, sink_node)
avs_condpath_pause(adev, cpath);
-
- mutex_unlock(&adev->path_mutex);
}
int avs_path_pause(struct avs_path *path)
@@ -1560,7 +1550,7 @@ static void avs_condpaths_run(struct avs_dev *adev, struct avs_path *path, int t
{
struct avs_path *cpath;
- mutex_lock(&adev->path_mutex);
+ guard(mutex)(&adev->path_mutex);
/* Run conditional paths only if source and sink are both running. */
list_for_each_entry(cpath, &path->source_list, source_node)
@@ -1572,8 +1562,6 @@ static void avs_condpaths_run(struct avs_dev *adev, struct avs_path *path, int t
if (cpath->source->state == AVS_PPL_STATE_RUNNING &&
cpath->sink->state == AVS_PPL_STATE_RUNNING)
avs_condpath_run(adev, cpath, trigger);
-
- mutex_unlock(&adev->path_mutex);
}
int avs_path_run(struct avs_path *path, int trigger)
diff --git a/sound/soc/intel/avs/utils.c b/sound/soc/intel/avs/utils.c
index ee36725ac731..ea14ec173855 100644
--- a/sound/soc/intel/avs/utils.c
+++ b/sound/soc/intel/avs/utils.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/firmware.h>
#include <linux/kfifo.h>
#include <linux/slab.h>
@@ -48,13 +49,12 @@ int avs_get_module_entry(struct avs_dev *adev, const guid_t *uuid, struct avs_mo
{
int idx;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_entry_index(adev, uuid);
if (idx >= 0)
memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry));
- mutex_unlock(&adev->modres_mutex);
return (idx < 0) ? idx : 0;
}
@@ -62,13 +62,12 @@ int avs_get_module_id_entry(struct avs_dev *adev, u32 module_id, struct avs_modu
{
int idx;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_id_entry_index(adev, module_id);
if (idx >= 0)
memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry));
- mutex_unlock(&adev->modres_mutex);
return (idx < 0) ? idx : 0;
}
@@ -86,13 +85,12 @@ bool avs_is_module_ida_empty(struct avs_dev *adev, u32 module_id)
bool ret = false;
int idx;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_id_entry_index(adev, module_id);
if (idx >= 0)
ret = ida_is_empty(adev->mod_idas[idx]);
- mutex_unlock(&adev->modres_mutex);
return ret;
}
@@ -163,68 +161,57 @@ int avs_module_info_init(struct avs_dev *adev, bool purge)
if (ret)
return AVS_IPC_RET(ret);
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
ret = avs_module_ida_alloc(adev, info, purge);
if (ret < 0) {
dev_err(adev->dev, "initialize module idas failed: %d\n", ret);
- goto exit;
+ return ret;
}
/* Refresh current information with newly received table. */
kfree(adev->mods_info);
adev->mods_info = info;
-exit:
- mutex_unlock(&adev->modres_mutex);
return ret;
}
void avs_module_info_free(struct avs_dev *adev)
{
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
avs_module_ida_destroy(adev);
kfree(adev->mods_info);
adev->mods_info = NULL;
-
- mutex_unlock(&adev->modres_mutex);
}
int avs_module_id_alloc(struct avs_dev *adev, u16 module_id)
{
- int ret, idx, max_id;
+ int idx, max_id;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_id_entry_index(adev, module_id);
if (idx == -ENOENT) {
dev_err(adev->dev, "invalid module id: %d", module_id);
- ret = -EINVAL;
- goto exit;
+ return -EINVAL;
}
max_id = adev->mods_info->entries[idx].instance_max_count - 1;
- ret = ida_alloc_max(adev->mod_idas[idx], max_id, GFP_KERNEL);
-exit:
- mutex_unlock(&adev->modres_mutex);
- return ret;
+
+ return ida_alloc_max(adev->mod_idas[idx], max_id, GFP_KERNEL);
}
void avs_module_id_free(struct avs_dev *adev, u16 module_id, u8 instance_id)
{
int idx;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_id_entry_index(adev, module_id);
- if (idx == -ENOENT) {
+ if (idx == -ENOENT)
dev_err(adev->dev, "invalid module id: %d", module_id);
- goto exit;
- }
-
- ida_free(adev->mod_idas[idx], instance_id);
-exit:
- mutex_unlock(&adev->modres_mutex);
+ else
+ ida_free(adev->mod_idas[idx], instance_id);
}
/*
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index c527d575d1ed..72fe013fffe8 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -1288,7 +1288,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
goto err_dai;
}
- ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_confs);
+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs);
if (ret < 0)
goto err_end;
@@ -1483,12 +1483,12 @@ static int mc_probe(struct platform_device *pdev)
dmi_check_system(sof_sdw_quirk_table);
if (quirk_override != -1) {
- dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
+ dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
sof_sdw_quirk, quirk_override);
sof_sdw_quirk = quirk_override;
}
- log_quirks(card->dev);
+ log_quirks(&pdev->dev);
ctx->mc_quirk = sof_sdw_quirk;
/* reset amp_num to ensure amp_num++ starts from 0 in each probe */
@@ -1507,13 +1507,13 @@ static int mc_probe(struct platform_device *pdev)
for (i = 0; i < ctx->codec_info_list_count; i++)
amp_num += codec_info_list[i].amp_num;
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL,
" cfg-amp:%d", amp_num);
if (!card->components)
return -ENOMEM;
if (mach->mach_params.dmic_num) {
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"%s mic:dmic cfg-mics:%d",
card->components,
mach->mach_params.dmic_num);
@@ -1524,7 +1524,7 @@ static int mc_probe(struct platform_device *pdev)
/* Register the card */
ret = devm_snd_soc_register_card(card->dev, card);
if (ret) {
- dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
+ dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed %d\n", ret);
asoc_sdw_mc_dailink_exit_loop(card);
return ret;
}
@@ -1542,8 +1542,8 @@ static void mc_remove(struct platform_device *pdev)
}
static const struct platform_device_id mc_id_table[] = {
- { "sof_sdw", },
- {}
+ { .name = "sof_sdw" },
+ { }
};
MODULE_DEVICE_TABLE(platform, mc_id_table);
diff --git a/sound/soc/intel/catpt/core.h b/sound/soc/intel/catpt/core.h
index 3881164422b8..f68807c454c9 100644
--- a/sound/soc/intel/catpt/core.h
+++ b/sound/soc/intel/catpt/core.h
@@ -139,9 +139,7 @@ int catpt_dsp_send_msg(struct catpt_dev *cdev, struct catpt_ipc_msg request,
int catpt_first_boot_firmware(struct catpt_dev *cdev);
int catpt_boot_firmware(struct catpt_dev *cdev, bool restore);
-int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan);
-int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan);
-int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan);
+int catpt_store_firmware_context(struct catpt_dev *cdev);
int catpt_coredump(struct catpt_dev *cdev);
#include <sound/memalloc.h>
diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c
index b176aebea9d5..e36eea8b5408 100644
--- a/sound/soc/intel/catpt/device.c
+++ b/sound/soc/intel/catpt/device.c
@@ -28,44 +28,17 @@
static int catpt_do_suspend(struct device *dev)
{
struct catpt_dev *cdev = dev_get_drvdata(dev);
- struct dma_chan *chan;
int ret;
- chan = catpt_dma_request_config_chan(cdev);
- if (IS_ERR(chan))
- return PTR_ERR(chan);
-
memset(&cdev->dx_ctx, 0, sizeof(cdev->dx_ctx));
ret = catpt_ipc_enter_dxstate(cdev, CATPT_DX_STATE_D3, &cdev->dx_ctx);
- if (ret) {
- ret = CATPT_IPC_RET(ret);
- goto release_dma_chan;
- }
-
- ret = catpt_dsp_stall(cdev, true);
if (ret)
- goto release_dma_chan;
-
- ret = catpt_store_memdumps(cdev, chan);
- if (ret) {
- dev_err(cdev->dev, "store memdumps failed: %d\n", ret);
- goto release_dma_chan;
- }
+ return CATPT_IPC_RET(ret);
- ret = catpt_store_module_states(cdev, chan);
- if (ret) {
- dev_err(cdev->dev, "store module states failed: %d\n", ret);
- goto release_dma_chan;
- }
-
- ret = catpt_store_streams_context(cdev, chan);
- if (ret)
- dev_err(cdev->dev, "store streams ctx failed: %d\n", ret);
-
-release_dma_chan:
- dma_release_channel(chan);
+ ret = catpt_store_firmware_context(cdev);
if (ret)
return ret;
+
return catpt_dsp_power_down(cdev);
}
diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c
index c577f2e17ddf..e7ba9e1e60ae 100644
--- a/sound/soc/intel/catpt/loader.c
+++ b/sound/soc/intel/catpt/loader.c
@@ -26,7 +26,7 @@ struct catpt_fw_hdr {
u32 reserved[4];
} __packed;
-struct catpt_fw_mod_hdr {
+struct catpt_fw_module_hdr {
char signature[FW_SIGNATURE_SIZE];
u32 mod_size;
u32 blocks;
@@ -81,7 +81,7 @@ catpt_request_region(struct resource *root, resource_size_t size)
return __request_region(root, addr, size, NULL, 0);
}
-int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan)
+static int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan)
{
struct catpt_stream_runtime *stream;
@@ -108,7 +108,7 @@ int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan)
return 0;
}
-int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan)
+static int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan)
{
int i;
@@ -138,7 +138,7 @@ int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan)
return 0;
}
-int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan)
+static int catpt_store_dram_data(struct catpt_dev *cdev, struct dma_chan *chan)
{
int i;
@@ -171,6 +171,39 @@ int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan)
return 0;
}
+int catpt_store_firmware_context(struct catpt_dev *cdev)
+{
+ struct dma_chan *chan;
+ int ret;
+
+ chan = catpt_dma_request_config_chan(cdev);
+ if (IS_ERR(chan))
+ return PTR_ERR(chan);
+
+ ret = catpt_dsp_stall(cdev, true);
+ if (ret)
+ goto exit;
+
+ ret = catpt_store_dram_data(cdev, chan);
+ if (ret) {
+ dev_err(cdev->dev, "store memdumps failed: %d\n", ret);
+ goto exit;
+ }
+
+ ret = catpt_store_module_states(cdev, chan);
+ if (ret) {
+ dev_err(cdev->dev, "store module states failed: %d\n", ret);
+ goto exit;
+ }
+
+ ret = catpt_store_streams_context(cdev, chan);
+ if (ret)
+ dev_err(cdev->dev, "store streams ctx failed: %d\n", ret);
+exit:
+ dma_release_channel(chan);
+ return ret;
+}
+
static int
catpt_restore_streams_context(struct catpt_dev *cdev, struct dma_chan *chan)
{
@@ -199,7 +232,7 @@ catpt_restore_streams_context(struct catpt_dev *cdev, struct dma_chan *chan)
return 0;
}
-static int catpt_restore_memdumps(struct catpt_dev *cdev, struct dma_chan *chan)
+static int catpt_restore_dram_data(struct catpt_dev *cdev, struct dma_chan *chan)
{
int i;
@@ -234,9 +267,9 @@ static int catpt_restore_memdumps(struct catpt_dev *cdev, struct dma_chan *chan)
return 0;
}
-static int catpt_restore_fwimage(struct catpt_dev *cdev,
- struct dma_chan *chan, dma_addr_t paddr,
- struct catpt_fw_block_hdr *blk)
+static int catpt_restore_dram_rodata(struct catpt_dev *cdev,
+ struct dma_chan *chan, dma_addr_t paddr,
+ struct catpt_fw_block_hdr *blk)
{
struct resource r1 = {};
int i;
@@ -324,28 +357,26 @@ static int catpt_load_block(struct catpt_dev *cdev,
static int catpt_restore_basefw(struct catpt_dev *cdev,
struct dma_chan *chan, dma_addr_t paddr,
- struct catpt_fw_mod_hdr *basefw)
+ struct catpt_fw_module_hdr *basefw)
{
- u32 offset = sizeof(*basefw);
+ u32 off = sizeof(*basefw);
int ret, i;
print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
basefw, sizeof(*basefw), false);
- /* restore basefw image */
+ /* Restore IRAM and .rodata for DRAM based on the firmware image. */
for (i = 0; i < basefw->blocks; i++) {
struct catpt_fw_block_hdr *blk;
- blk = (struct catpt_fw_block_hdr *)((u8 *)basefw + offset);
+ blk = (struct catpt_fw_block_hdr *)((u8 *)basefw + off);
switch (blk->ram_type) {
case CATPT_RAM_TYPE_IRAM:
- ret = catpt_load_block(cdev, chan, paddr + offset,
- blk, false);
+ ret = catpt_load_block(cdev, chan, paddr + off, blk, false);
break;
default:
- ret = catpt_restore_fwimage(cdev, chan, paddr + offset,
- blk);
+ ret = catpt_restore_dram_rodata(cdev, chan, paddr + off, blk);
break;
}
@@ -354,11 +385,11 @@ static int catpt_restore_basefw(struct catpt_dev *cdev,
return ret;
}
- offset += sizeof(*blk) + blk->size;
+ off += sizeof(*blk) + blk->size;
}
- /* then proceed with memory dumps */
- ret = catpt_restore_memdumps(cdev, chan);
+ /* Then proceed with DRAM .data saved before D3. */
+ ret = catpt_restore_dram_data(cdev, chan);
if (ret)
dev_err(cdev->dev, "restore memdumps failed: %d\n", ret);
@@ -367,9 +398,9 @@ static int catpt_restore_basefw(struct catpt_dev *cdev,
static int catpt_restore_module(struct catpt_dev *cdev,
struct dma_chan *chan, dma_addr_t paddr,
- struct catpt_fw_mod_hdr *mod)
+ struct catpt_fw_module_hdr *mod)
{
- u32 offset = sizeof(*mod);
+ u32 off = sizeof(*mod);
int i;
print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
@@ -379,7 +410,7 @@ static int catpt_restore_module(struct catpt_dev *cdev,
struct catpt_fw_block_hdr *blk;
int ret;
- blk = (struct catpt_fw_block_hdr *)((u8 *)mod + offset);
+ blk = (struct catpt_fw_block_hdr *)((u8 *)mod + off);
switch (blk->ram_type) {
case CATPT_RAM_TYPE_INSTANCE:
@@ -390,7 +421,7 @@ static int catpt_restore_module(struct catpt_dev *cdev,
ALIGN(blk->size, 4));
break;
default:
- ret = catpt_load_block(cdev, chan, paddr + offset,
+ ret = catpt_load_block(cdev, chan, paddr + off,
blk, false);
break;
}
@@ -400,7 +431,7 @@ static int catpt_restore_module(struct catpt_dev *cdev,
return ret;
}
- offset += sizeof(*blk) + blk->size;
+ off += sizeof(*blk) + blk->size;
}
return 0;
@@ -408,10 +439,10 @@ static int catpt_restore_module(struct catpt_dev *cdev,
static int catpt_load_module(struct catpt_dev *cdev,
struct dma_chan *chan, dma_addr_t paddr,
- struct catpt_fw_mod_hdr *mod)
+ struct catpt_fw_module_hdr *mod)
{
struct catpt_module_type *type;
- u32 offset = sizeof(*mod);
+ u32 off = sizeof(*mod);
int i;
print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
@@ -423,9 +454,9 @@ static int catpt_load_module(struct catpt_dev *cdev,
struct catpt_fw_block_hdr *blk;
int ret;
- blk = (struct catpt_fw_block_hdr *)((u8 *)mod + offset);
+ blk = (struct catpt_fw_block_hdr *)((u8 *)mod + off);
- ret = catpt_load_block(cdev, chan, paddr + offset, blk, true);
+ ret = catpt_load_block(cdev, chan, paddr + off, blk, true);
if (ret) {
dev_err(cdev->dev, "load block failed: %d\n", ret);
return ret;
@@ -440,7 +471,7 @@ static int catpt_load_module(struct catpt_dev *cdev,
type->state_size = blk->size;
}
- offset += sizeof(*blk) + blk->size;
+ off += sizeof(*blk) + blk->size;
}
/* init module type static info */
@@ -457,17 +488,17 @@ static int catpt_restore_firmware(struct catpt_dev *cdev,
struct dma_chan *chan, dma_addr_t paddr,
struct catpt_fw_hdr *fw)
{
- u32 offset = sizeof(*fw);
+ u32 off = sizeof(*fw);
int i;
print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
fw, sizeof(*fw), false);
for (i = 0; i < fw->modules; i++) {
- struct catpt_fw_mod_hdr *mod;
+ struct catpt_fw_module_hdr *mod;
int ret;
- mod = (struct catpt_fw_mod_hdr *)((u8 *)fw + offset);
+ mod = (struct catpt_fw_module_hdr *)((u8 *)fw + off);
if (strncmp(fw->signature, mod->signature,
FW_SIGNATURE_SIZE)) {
dev_err(cdev->dev, "module signature mismatch\n");
@@ -479,12 +510,10 @@ static int catpt_restore_firmware(struct catpt_dev *cdev,
switch (mod->module_id) {
case CATPT_MODID_BASE_FW:
- ret = catpt_restore_basefw(cdev, chan, paddr + offset,
- mod);
+ ret = catpt_restore_basefw(cdev, chan, paddr + off, mod);
break;
default:
- ret = catpt_restore_module(cdev, chan, paddr + offset,
- mod);
+ ret = catpt_restore_module(cdev, chan, paddr + off, mod);
break;
}
@@ -493,7 +522,7 @@ static int catpt_restore_firmware(struct catpt_dev *cdev,
return ret;
}
- offset += sizeof(*mod) + mod->mod_size;
+ off += sizeof(*mod) + mod->mod_size;
}
return 0;
@@ -503,17 +532,17 @@ static int catpt_load_firmware(struct catpt_dev *cdev,
struct dma_chan *chan, dma_addr_t paddr,
struct catpt_fw_hdr *fw)
{
- u32 offset = sizeof(*fw);
+ u32 off = sizeof(*fw);
int i;
print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
fw, sizeof(*fw), false);
for (i = 0; i < fw->modules; i++) {
- struct catpt_fw_mod_hdr *mod;
+ struct catpt_fw_module_hdr *mod;
int ret;
- mod = (struct catpt_fw_mod_hdr *)((u8 *)fw + offset);
+ mod = (struct catpt_fw_module_hdr *)((u8 *)fw + off);
if (strncmp(fw->signature, mod->signature,
FW_SIGNATURE_SIZE)) {
dev_err(cdev->dev, "module signature mismatch\n");
@@ -523,21 +552,20 @@ static int catpt_load_firmware(struct catpt_dev *cdev,
if (mod->module_id > CATPT_MODID_LAST)
return -EINVAL;
- ret = catpt_load_module(cdev, chan, paddr + offset, mod);
+ ret = catpt_load_module(cdev, chan, paddr + off, mod);
if (ret) {
dev_err(cdev->dev, "load module failed: %d\n", ret);
return ret;
}
- offset += sizeof(*mod) + mod->mod_size;
+ off += sizeof(*mod) + mod->mod_size;
}
return 0;
}
-static int catpt_load_image(struct catpt_dev *cdev, struct dma_chan *chan,
- const char *name, const char *signature,
- bool restore)
+static int catpt_request_load_firmware(struct catpt_dev *cdev, struct dma_chan *chan,
+ const char *name, bool restore)
{
struct catpt_fw_hdr *fw;
struct firmware *img;
@@ -550,7 +578,7 @@ static int catpt_load_image(struct catpt_dev *cdev, struct dma_chan *chan,
return ret;
fw = (struct catpt_fw_hdr *)img->data;
- if (strncmp(fw->signature, signature, FW_SIGNATURE_SIZE)) {
+ if (strncmp(fw->signature, FW_SIGNATURE, FW_SIGNATURE_SIZE)) {
dev_err(cdev->dev, "firmware signature mismatch\n");
ret = -EINVAL;
goto release_fw;
@@ -575,7 +603,7 @@ release_fw:
return ret;
}
-static int catpt_load_images(struct catpt_dev *cdev, bool restore)
+static int catpt_request_dma_load_firmware(struct catpt_dev *cdev, bool restore)
{
struct dma_chan *chan;
int ret;
@@ -584,8 +612,7 @@ static int catpt_load_images(struct catpt_dev *cdev, bool restore)
if (IS_ERR(chan))
return PTR_ERR(chan);
- ret = catpt_load_image(cdev, chan, cdev->spec->fw_name,
- FW_SIGNATURE, restore);
+ ret = catpt_request_load_firmware(cdev, chan, cdev->spec->fw_name, restore);
if (ret)
goto release_dma_chan;
@@ -605,7 +632,7 @@ int catpt_boot_firmware(struct catpt_dev *cdev, bool restore)
catpt_dsp_stall(cdev, true);
- ret = catpt_load_images(cdev, restore);
+ ret = catpt_request_dma_load_firmware(cdev, restore);
if (ret) {
dev_err(cdev->dev, "load binaries failed: %d\n", ret);
return ret;
@@ -619,10 +646,10 @@ int catpt_boot_firmware(struct catpt_dev *cdev, bool restore)
if (!ret) {
dev_err(cdev->dev, "firmware ready timeout\n");
return -ETIMEDOUT;
+ }
/* Wake up does not mean FW is ready, an exception could occur. */
- } else if (!cdev->ipc.ready) {
+ if (!cdev->ipc.ready)
return -EREMOTEIO;
- }
/* update sram pg & clock once done booting */
catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask);
diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c
index 8fb0efb67eb1..f23c580ba051 100644
--- a/sound/soc/intel/catpt/pcm.c
+++ b/sound/soc/intel/catpt/pcm.c
@@ -75,8 +75,8 @@ static struct catpt_stream_template *catpt_topology[] = {
static struct catpt_stream_template *
catpt_get_stream_template(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtm, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
enum catpt_stream_type type;
type = cpu_dai->driver->id;
@@ -159,11 +159,11 @@ static void catpt_stream_read_position(struct catpt_dev *cdev,
static void catpt_arrange_page_table(struct snd_pcm_substream *substream,
struct snd_dma_buffer *pgtbl)
{
- struct snd_pcm_runtime *rtm = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dma_buffer *databuf = snd_pcm_get_dma_buf(substream);
int i, pages;
- pages = snd_sgbuf_aligned_pages(rtm->dma_bytes);
+ pages = snd_sgbuf_aligned_pages(runtime->dma_bytes);
for (i = 0; i < pages; i++) {
u32 pfn, offset;
@@ -386,7 +386,7 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_pcm_runtime *rtm = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dma_buffer *dmab;
struct catpt_stream_runtime *stream;
struct catpt_audio_format afmt;
@@ -412,8 +412,8 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
memset(&rinfo, 0, sizeof(rinfo));
rinfo.page_table_addr = stream->pgtbl.addr;
- rinfo.num_pages = DIV_ROUND_UP(rtm->dma_bytes, PAGE_SIZE);
- rinfo.size = rtm->dma_bytes;
+ rinfo.num_pages = DIV_ROUND_UP(runtime->dma_bytes, PAGE_SIZE);
+ rinfo.size = runtime->dma_bytes;
rinfo.offset = 0;
rinfo.ring_first_page_pfn = PFN_DOWN(snd_sgbuf_get_addr(dmab, 0));
@@ -544,11 +544,11 @@ void catpt_stream_update_position(struct catpt_dev *cdev,
struct catpt_notify_position *pos)
{
struct snd_pcm_substream *substream = stream->substream;
- struct snd_pcm_runtime *r = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t dsppos, newpos;
int ret;
- dsppos = bytes_to_frames(r, pos->stream_position);
+ dsppos = bytes_to_frames(runtime, pos->stream_position);
if (!stream->prepared)
goto exit;
@@ -556,8 +556,8 @@ void catpt_stream_update_position(struct catpt_dev *cdev,
if (stream->template->type != CATPT_STRM_TYPE_RENDER)
goto exit;
- if (dsppos >= r->buffer_size / 2)
- newpos = r->buffer_size / 2;
+ if (dsppos >= runtime->buffer_size / 2)
+ newpos = runtime->buffer_size / 2;
else
newpos = 0;
/*
@@ -565,7 +565,7 @@ void catpt_stream_update_position(struct catpt_dev *cdev,
* (buffer half consumed) update wp to allow stream progression.
*/
ret = catpt_ipc_set_write_pos(cdev, stream->info.stream_hw_id,
- frames_to_bytes(r, newpos),
+ frames_to_bytes(runtime, newpos),
false, false);
if (ret) {
dev_err(cdev->dev, "update position for stream %d failed: %d\n",
@@ -600,11 +600,11 @@ static const struct snd_pcm_hardware catpt_pcm_hardware = {
};
static int catpt_component_pcm_new(struct snd_soc_component *component,
- struct snd_soc_pcm_runtime *rtm)
+ struct snd_soc_pcm_runtime *rtd)
{
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
- snd_pcm_set_managed_buffer_all(rtm->pcm, SNDRV_DMA_TYPE_DEV_SG,
+ snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV_SG,
cdev->dev,
catpt_pcm_hardware.buffer_bytes_max,
catpt_pcm_hardware.buffer_bytes_max);
@@ -615,9 +615,9 @@ static int catpt_component_pcm_new(struct snd_soc_component *component,
static int catpt_component_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- if (!rtm->dai_link->no_pcm)
+ if (!rtd->dai_link->no_pcm)
snd_soc_set_runtime_hwparams(substream, &catpt_pcm_hardware);
return 0;
}
@@ -626,13 +626,13 @@ static snd_pcm_uframes_t
catpt_component_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtm, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct catpt_stream_runtime *stream;
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
u32 pos;
- if (rtm->dai_link->no_pcm)
+ if (rtd->dai_link->no_pcm)
return 0;
stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
@@ -650,10 +650,10 @@ static const struct snd_soc_dai_ops catpt_fe_dai_ops = {
.trigger = catpt_dai_trigger,
};
-static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm,
+static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_dai *dai)
{
- struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtm, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct catpt_ssp_device_format devfmt;
struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
int ret;
@@ -871,8 +871,7 @@ static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol)
return CATPT_IPC_RET(ret);
}
-static int catpt_volume_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+static int catpt_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = CATPT_CHANNELS_MAX;
diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c
index 59bfd5248819..1033f2d45c8a 100644
--- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c
@@ -572,6 +572,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
.links = arl_rt711_l0_rt1316_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-arl-rt711-l0-rt1316-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(3),
@@ -600,12 +601,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
.links = arl_rvp,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-arl-rt711.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = 0x1, /* link0 required */
.links = arl_sdca_rvp,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-arl-rt711-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(2),
diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
index 937a74a5d523..3b9758f73238 100644
--- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
@@ -717,24 +717,28 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
.links = lnl_3_in_1_sdca,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-rt711-l0-rt1316-l23-rt714-l1.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(2) | BIT(3),
.links = lnl_cs42l43_l0_cs35l56_l23,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l23.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(1) | BIT(2) | BIT(3),
.links = lnl_cs42l43_l2_cs35l56x6_l13,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-cs42l43-l2-cs35l56x6-l13.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(3),
.links = lnl_cs42l43_l0_cs35l56_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
@@ -748,12 +752,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
.links = lnl_rvp,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-rt711.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(2) | BIT(3),
.links = lnl_712_only,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-rt712-l2-rt1712-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
@@ -766,19 +772,22 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
.link_mask = GENMASK(2, 0),
.links = lnl_sdw_rt1318_l12_rt714_l0,
.drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-lnl-rt1318-l12-rt714-l0.tplg"
+ .sof_tplg_filename = "sof-lnl-rt1318-l12-rt714-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = GENMASK(2, 0),
.links = lnl_sdw_rt1320_l12_rt714_l0,
.drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-lnl-rt1320-l12-rt714-l0.tplg"
+ .sof_tplg_filename = "sof-lnl-rt1320-l12-rt714-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(1),
.links = lnl_sdw_rt713_l0_rt1318_l1,
.drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-lnl-rt713-l0-rt1318-l1.tplg"
+ .sof_tplg_filename = "sof-lnl-rt713-l0-rt1318-l1.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(1) | BIT(2),
diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
index 2e4222456f27..596582053d93 100644
--- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -1321,60 +1321,70 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.links = tac5572_l0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-tac5572.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
.links = tac5672_l0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-tac5672.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
.links = tac5682_l0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-tac5682.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
.links = tas2783_link0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-tas2783.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
.links = tas2883_l0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-tas2883.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = GENMASK(3, 0),
.links = mtl_rt713_l0_rt1316_l12_rt1713_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt713-l0-rt1316-l12-rt1713-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = GENMASK(3, 0),
.links = mtl_rt713_l0_rt1318_l12_rt1713_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt713-l0-rt1318-l12-rt1713-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(1) | BIT(3),
.links = mtl_rt713_l0_rt1318_l1_rt1713_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt713-l0-rt1318-l1-rt1713-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = GENMASK(2, 0),
.links = mtl_rt713_l0_rt1316_l12,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt713-l0-rt1316-l12.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(3) | BIT(0),
.links = mtl_712_l0_1712_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt712-l0-rt1712-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
@@ -1395,7 +1405,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.link_mask = GENMASK(2, 0),
.links = mtl_sdw_rt1318_l12_rt714_l0,
.drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-mtl-rt1318-l12-rt714-l0.tplg"
+ .sof_tplg_filename = "sof-mtl-rt1318-l12-rt714-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(2) | BIT(3),
@@ -1455,12 +1466,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.links = mtl_3_in_1_sdca,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l23-rt714-l1.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = 0x9, /* 2 active links required */
.links = mtl_rt711_l0_rt1316_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
@@ -1474,18 +1487,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.links = mtl_rvp,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt711.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(2),
.links = rt5682_link2_max98373_link0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-sdw-rt5682-l2-max98373-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(2),
.links = cs42l42_link0_max98363_link2,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-sdw-cs42l42-l0-max98363-l2.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{},
};
diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
index f7694b2a2b02..756bbf82a326 100644
--- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
@@ -492,7 +492,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = {
.links = ptl_rt722_l0_rt1320_l23,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-ptl-rt722-l0-rt1320-l23.tplg",
- .get_function_tplg_files = sof_sdw_get_tplg_files,
+ .machine_check = snd_soc_acpi_intel_no_function_topology,
},
{
.link_mask = BIT(1) | BIT(2),
@@ -522,14 +522,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = {
.links = ptl_rvp,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-ptl-rt711.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(3),
.links = ptl_sdw_rt712_vb_l3_rt1320_l3,
.drv_name = "sof_sdw",
- .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
+ .machine_check = snd_soc_acpi_intel_rt712_vb_no_function_topology,
.sof_tplg_filename = "sof-ptl-rt712-l3-rt1320-l3.tplg",
- .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{},
};
diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
index 7caabc501b16..9fdeb6ad96ac 100644
--- a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
+++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
@@ -53,6 +53,14 @@ bool snd_soc_acpi_intel_no_function_topology(void *arg)
}
EXPORT_SYMBOL_NS(snd_soc_acpi_intel_no_function_topology, "SND_SOC_ACPI_INTEL_SDCA_QUIRKS");
+bool snd_soc_acpi_intel_rt712_vb_no_function_topology(void *arg)
+{
+ return snd_soc_acpi_intel_sdca_is_device_rt712_vb(arg) &&
+ snd_soc_acpi_intel_no_function_topology(arg);
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_rt712_vb_no_function_topology,
+ "SND_SOC_ACPI_INTEL_SDCA_QUIRKS");
+
MODULE_DESCRIPTION("ASoC ACPI Intel SDCA quirks");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("SND_SOC_SDCA");
diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
index 2ea0a1881c4b..60b665ab5924 100644
--- a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
+++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
@@ -11,5 +11,6 @@
bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg);
bool snd_soc_acpi_intel_no_function_topology(void *arg);
+bool snd_soc_acpi_intel_rt712_vb_no_function_topology(void *arg);
#endif
diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c
index 7910d5d9ac4f..25cd12eab4b1 100644
--- a/sound/soc/loongson/loongson_card.c
+++ b/sound/soc/loongson/loongson_card.c
@@ -2,24 +2,131 @@
//
// Loongson ASoC Audio Machine driver
//
-// Copyright (C) 2023 Loongson Technology Corporation Limited
+// Copyright (C) 2023-2026 Loongson Technology Corporation Limited
// Author: Yingkun Meng <mengyingkun@loongson.cn>
+// Binbin Zhou <zhoubinbin@loongson.cn>
//
-#include <linux/module.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
#include <linux/pci.h>
+#include <sound/jack.h>
#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
static char codec_name[SND_ACPI_I2C_ID_LEN];
struct loongson_card_data {
struct snd_soc_card snd_card;
unsigned int mclk_fs;
+ struct gpio_desc *gpiod_hp_det;
+ struct gpio_desc *gpiod_hp_ctl;
+ struct gpio_desc *gpiod_spkr_en;
+ const struct loongson_card_config *cfg;
+};
+
+struct loongson_card_config {
+ unsigned int fmt;
+ bool add_hp_jack;
+ bool add_dapm_widgets;
+ bool add_dapm_routes;
+};
+
+static const struct loongson_card_config ls2k1000_card_config = {
+ .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBC_CFC,
+ .add_hp_jack = false,
+ .add_dapm_widgets = false,
+ .add_dapm_routes = false,
+};
+
+static const struct loongson_card_config ls2k0300_forever_pi_card_config = {
+ .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
+ .add_hp_jack = false,
+ .add_dapm_widgets = false,
+ .add_dapm_routes = false,
+};
+
+static const struct loongson_card_config ls2k0300_dl2k0300b_card_config = {
+ .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
+ .add_hp_jack = true,
+ .add_dapm_widgets = true,
+ .add_dapm_routes = true,
+};
+
+static int tegra_machine_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
+ struct loongson_card_data *priv = snd_soc_card_get_drvdata(card);
+
+ if (!snd_soc_dapm_widget_name_cmp(w, "Speaker"))
+ gpiod_set_value_cansleep(priv->gpiod_spkr_en,
+ SND_SOC_DAPM_EVENT_ON(event));
+
+ if (!snd_soc_dapm_widget_name_cmp(w, "Headphone"))
+ gpiod_set_value_cansleep(priv->gpiod_hp_ctl,
+ SND_SOC_DAPM_EVENT_ON(event));
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget loongson_aosc_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", tegra_machine_event),
+ SND_SOC_DAPM_SPK("Speaker", tegra_machine_event),
};
+/* Headphones Jack */
+
+static struct snd_soc_jack loongson_asoc_hp_jack;
+
+static struct snd_soc_jack_pin loongson_asoc_hp_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE
+ },
+ {
+ .pin = "Speaker",
+ .mask = SND_JACK_HEADPHONE,
+ .invert = 1
+ },
+};
+
+static struct snd_soc_jack_gpio loongson_asoc_hp_jack_gpio = {
+ .name = "Headphones detection",
+ .report = SND_JACK_HEADPHONE,
+ .debounce_time = 150,
+};
+
+static int loongson_asoc_machine_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct loongson_card_data *ls_priv = snd_soc_card_get_drvdata(card);
+ int ret = 0;
+
+ if (!ls_priv->cfg->add_hp_jack || !ls_priv->gpiod_hp_det)
+ return 0;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headphones Jack",
+ SND_JACK_HEADPHONE,
+ &loongson_asoc_hp_jack,
+ loongson_asoc_hp_jack_pins,
+ ARRAY_SIZE(loongson_asoc_hp_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "Headphones Jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ loongson_asoc_hp_jack_gpio.desc = ls_priv->gpiod_hp_det;
+
+ ret = snd_soc_jack_add_gpios(&loongson_asoc_hp_jack, 1, &loongson_asoc_hp_jack_gpio);
+ if (ret)
+ dev_err(rtd->dev, "Headphone GPIO not added: %d\n", ret);
+
+ return ret;
+}
+
static int loongson_card_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -45,7 +152,7 @@ static int loongson_card_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- return 0;
+ return snd_soc_runtime_set_dai_fmt(rtd, ls_card->cfg->fmt);
}
static const struct snd_soc_ops loongson_ops = {
@@ -61,8 +168,7 @@ static struct snd_soc_dai_link loongson_dai_links[] = {
{
.name = "Loongson Audio Port",
.stream_name = "Loongson Audio",
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_NF
- | SND_SOC_DAIFMT_CBC_CFC,
+ .init = loongson_asoc_machine_init,
SND_SOC_DAILINK_REG(analog),
.ops = &loongson_ops,
},
@@ -91,7 +197,7 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data)
const char *codec_dai_name;
struct acpi_device *adev;
struct device *phy_dev;
- int i;
+ int i, ret;
/* fixup platform name based on reference node */
adev = loongson_card_acpi_find_device(card, "cpu");
@@ -108,7 +214,9 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data)
return -ENOENT;
snprintf(codec_name, sizeof(codec_name), "i2c-%s", acpi_dev_name(adev));
- device_property_read_string(card->dev, "codec-dai-name", &codec_dai_name);
+ ret = device_property_read_string(card->dev, "codec-dai-name", &codec_dai_name);
+ if (ret)
+ return ret;
for (i = 0; i < card->num_links; i++) {
loongson_dai_links[i].platforms->name = dev_name(phy_dev);
@@ -121,16 +229,35 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data)
static int loongson_card_parse_of(struct loongson_card_data *data)
{
- struct device_node *cpu, *codec;
struct snd_soc_card *card = &data->snd_card;
+ struct device_node *cpu, *codec;
struct device *dev = card->dev;
int ret, i;
+ data->gpiod_hp_det = devm_gpiod_get_optional(dev, "hp-det", GPIOD_IN);
+ if (IS_ERR(data->gpiod_hp_det))
+ return PTR_ERR(data->gpiod_hp_det);
+
+ data->gpiod_hp_ctl = devm_gpiod_get_optional(dev, "hp-ctl", GPIOD_OUT_LOW);
+ if (IS_ERR(data->gpiod_hp_ctl))
+ return PTR_ERR(data->gpiod_hp_ctl);
+
+ data->gpiod_spkr_en = devm_gpiod_get_optional(dev, "spkr-en", GPIOD_OUT_LOW);
+ if (IS_ERR(data->gpiod_spkr_en))
+ return PTR_ERR(data->gpiod_spkr_en);
+
+ if (data->cfg->add_dapm_routes) {
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+ if (ret)
+ return ret;
+ }
+
cpu = of_get_child_by_name(dev->of_node, "cpu");
if (!cpu) {
dev_err(dev, "platform property missing or invalid\n");
return -EINVAL;
}
+
codec = of_get_child_by_name(dev->of_node, "codec");
if (!codec) {
dev_err(dev, "audio-codec property missing or invalid\n");
@@ -175,12 +302,22 @@ static int loongson_asoc_card_probe(struct platform_device *pdev)
if (!ls_priv)
return -ENOMEM;
+ ls_priv->cfg = (const struct loongson_card_config *)device_get_match_data(dev);
+ if (!ls_priv->cfg)
+ return -EINVAL;
+
card = &ls_priv->snd_card;
card->dev = dev;
card->owner = THIS_MODULE;
card->dai_link = loongson_dai_links;
card->num_links = ARRAY_SIZE(loongson_dai_links);
+
+ if (ls_priv->cfg->add_dapm_widgets) {
+ card->dapm_widgets = loongson_aosc_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(loongson_aosc_dapm_widgets);
+ }
+
snd_soc_card_set_drvdata(card, ls_priv);
ret = device_property_read_string(dev, "model", &card->name);
@@ -200,7 +337,19 @@ static int loongson_asoc_card_probe(struct platform_device *pdev)
}
static const struct of_device_id loongson_asoc_dt_ids[] = {
- { .compatible = "loongson,ls-audio-card" },
+ /* Loongson-2K1000/Loongson-2K2000/LS7A */
+ {
+ .compatible = "loongson,ls-audio-card",
+ .data = &ls2k1000_card_config
+ },
+ {
+ .compatible = "loongson,ls2k0300-forever-pi-audio-card",
+ .data = &ls2k0300_forever_pi_card_config
+ },
+ {
+ .compatible = "loongson,ls2k0300-dl2k0300b-audio-card",
+ .data = &ls2k0300_dl2k0300b_card_config
+ },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, loongson_asoc_dt_ids);
diff --git a/sound/soc/loongson/loongson_i2s_plat.c b/sound/soc/loongson/loongson_i2s_plat.c
index ac054b6ce632..82d95c6644ef 100644
--- a/sound/soc/loongson/loongson_i2s_plat.c
+++ b/sound/soc/loongson/loongson_i2s_plat.c
@@ -2,7 +2,7 @@
//
// Loongson I2S controller master mode dirver(platform device)
//
-// Copyright (C) 2023-2024 Loongson Technology Corporation Limited
+// Copyright (C) 2023-2026 Loongson Technology Corporation Limited
//
// Author: Yingkun Meng <mengyingkun@loongson.cn>
// Binbin Zhou <zhoubinbin@loongson.cn>
@@ -21,6 +21,7 @@
#include "loongson_i2s.h"
#include "loongson_dma.h"
+/* Loongson-2K1000 APBDMA routing */
#define LOONGSON_I2S_RX_DMA_OFFSET 21
#define LOONGSON_I2S_TX_DMA_OFFSET 18
@@ -30,6 +31,11 @@
#define LOONGSON_DMA3_CONF 0x3
#define LOONGSON_DMA4_CONF 0x4
+struct loongson_i2s_plat_config {
+ int rev_id;
+ int (*i2s_dma_config)(struct platform_device *pdev);
+};
+
static int loongson_i2s_apbdma_config(struct platform_device *pdev)
{
int val;
@@ -47,8 +53,18 @@ static int loongson_i2s_apbdma_config(struct platform_device *pdev)
return 0;
}
+static const struct loongson_i2s_plat_config ls2k0300_i2s_plat_config = {
+ .rev_id = 1,
+};
+
+static const struct loongson_i2s_plat_config ls2k1000_i2s_plat_config = {
+ .rev_id = 0,
+ .i2s_dma_config = loongson_i2s_apbdma_config,
+};
+
static int loongson_i2s_plat_probe(struct platform_device *pdev)
{
+ const struct loongson_i2s_plat_config *plat_config;
struct device *dev = &pdev->dev;
struct loongson_i2s *i2s;
struct resource *res;
@@ -59,12 +75,17 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev)
if (!i2s)
return -ENOMEM;
- ret = loongson_i2s_apbdma_config(pdev);
- if (ret)
- return ret;
+ plat_config = device_get_match_data(dev);
+ if (!plat_config)
+ return -EINVAL;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- i2s->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (plat_config->i2s_dma_config) {
+ ret = plat_config->i2s_dma_config(pdev);
+ if (ret)
+ return ret;
+ }
+
+ i2s->reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(i2s->reg_base))
return dev_err_probe(dev, PTR_ERR(i2s->reg_base),
"devm_ioremap_resource failed\n");
@@ -87,11 +108,17 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev)
if (IS_ERR(i2s_clk))
return dev_err_probe(dev, PTR_ERR(i2s_clk), "clock property invalid\n");
i2s->clk_rate = clk_get_rate(i2s_clk);
+ i2s->rev_id = plat_config->rev_id;
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
dev_set_name(dev, LS_I2S_DRVNAME);
dev_set_drvdata(dev, i2s);
+ if (i2s->rev_id == 1) {
+ regmap_update_bits(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_RESET, I2S_CTRL_RESET);
+ fsleep(200);
+ }
+
ret = devm_snd_soc_register_component(dev, &loongson_i2s_edma_component,
&loongson_i2s_dai, 1);
if (ret)
@@ -102,7 +129,8 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev)
}
static const struct of_device_id loongson_i2s_ids[] = {
- { .compatible = "loongson,ls2k1000-i2s" },
+ { .compatible = "loongson,ls2k0300-i2s", .data = &ls2k0300_i2s_plat_config },
+ { .compatible = "loongson,ls2k1000-i2s", .data = &ls2k1000_i2s_plat_config },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, loongson_i2s_ids);
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 4af7bbb58010..224746e7664f 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -7,7 +7,7 @@ config SND_SOC_MEDIATEK
config SND_SOC_MT2701
tristate "ASoC support for Mediatek MT2701 chip"
- depends on ARCH_MEDIATEK
+ depends on ARCH_MEDIATEK || COMPILE_TEST
select SND_SOC_MEDIATEK
help
This adds ASoC driver for Mediatek MT2701 boards
diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.c b/sound/soc/mediatek/common/mtk-dsp-sof-common.c
index 17b9ea6be604..adefbed5bbe7 100644
--- a/sound/soc/mediatek/common/mtk-dsp-sof-common.c
+++ b/sound/soc/mediatek/common/mtk-dsp-sof-common.c
@@ -232,6 +232,7 @@ int mtk_sof_dailink_parse_of(struct device *dev, struct snd_soc_card *card,
const char *propname)
{
struct device_node *np = dev->of_node;
+ struct snd_soc_dai_link *dai_link;
struct snd_soc_dai_link *parsed_dai_link;
const char *dai_name = NULL;
int i, j, ret, num_links, parsed_num_links = 0;
@@ -254,9 +255,9 @@ int mtk_sof_dailink_parse_of(struct device *dev, struct snd_soc_card *card,
return ret;
}
dev_dbg(dev, "ASoC: Property get dai_name:%s\n", dai_name);
- for (j = 0; j < card->num_links; j++) {
- if (!strcmp(dai_name, card->dai_link[j].name)) {
- memcpy(&parsed_dai_link[parsed_num_links++], &card->dai_link[j],
+ for_each_card_prelinks(card, j, dai_link) {
+ if (!strcmp(dai_name, dai_link->name)) {
+ memcpy(&parsed_dai_link[parsed_num_links++], dai_link,
sizeof(struct snd_soc_dai_link));
break;
}
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
index 3d6d7bc05b87..8c5096482520 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -315,7 +315,7 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
&mt8173_rt5650_priv.pll_from);
if (ret) {
dev_err(&pdev->dev,
- "%s snd_soc_register_card fail %d\n",
+ "%s device_property_read_u32() fail %d\n",
__func__, ret);
}
}
diff --git a/sound/soc/mediatek/mt8189/mt8189-dai-adda.c b/sound/soc/mediatek/mt8189/mt8189-dai-adda.c
index ad5b9546ff63..5c41a6386204 100644
--- a/sound/soc/mediatek/mt8189/mt8189-dai-adda.c
+++ b/sound/soc/mediatek/mt8189/mt8189-dai-adda.c
@@ -385,8 +385,6 @@ static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w,
if (event == SND_SOC_DAPM_PRE_PMU) {
if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2)
regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB8);
- else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2)
- regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0);
else
regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0);
}
diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
index 91c57765ab57..864b4d7228f5 100644
--- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
+++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
@@ -1019,7 +1019,7 @@ static struct snd_soc_card mt8192_mt6359_rt1015p_rt5682x_card = {
.num_dapm_routes = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682x_routes),
};
-static int mt8192_mt6359_card_set_be_link(struct snd_soc_card *card,
+static int mt8192_mt6359_card_set_be_link(struct device *dev,
struct snd_soc_dai_link *link,
struct device_node *node,
char *link_name)
@@ -1027,9 +1027,9 @@ static int mt8192_mt6359_card_set_be_link(struct snd_soc_card *card,
int ret;
if (node && strcmp(link->name, link_name) == 0) {
- ret = snd_soc_of_get_dai_link_codecs(card->dev, node, link);
+ ret = snd_soc_of_get_dai_link_codecs(dev, node, link);
if (ret < 0) {
- dev_err_probe(card->dev, ret, "get dai link codecs fail\n");
+ dev_err_probe(dev, ret, "get dai link codecs fail\n");
return ret;
}
}
@@ -1065,21 +1065,21 @@ static int mt8192_mt6359_legacy_probe(struct mtk_soc_card_data *soc_card_data)
}
for_each_card_prelinks(card, i, dai_link) {
- ret = mt8192_mt6359_card_set_be_link(card, dai_link, speaker_codec, "I2S3");
+ ret = mt8192_mt6359_card_set_be_link(dev, dai_link, speaker_codec, "I2S3");
if (ret) {
dev_err_probe(dev, ret, "%s set speaker_codec fail\n",
dai_link->name);
break;
}
- ret = mt8192_mt6359_card_set_be_link(card, dai_link, headset_codec, "I2S8");
+ ret = mt8192_mt6359_card_set_be_link(dev, dai_link, headset_codec, "I2S8");
if (ret) {
dev_err_probe(dev, ret, "%s set headset_codec fail\n",
dai_link->name);
break;
}
- ret = mt8192_mt6359_card_set_be_link(card, dai_link, headset_codec, "I2S9");
+ ret = mt8192_mt6359_card_set_be_link(dev, dai_link, headset_codec, "I2S9");
if (ret) {
dev_err_probe(dev, ret, "%s set headset_codec fail\n",
dai_link->name);
diff --git a/sound/soc/mediatek/mt8196/mt8196-nau8825.c b/sound/soc/mediatek/mt8196/mt8196-nau8825.c
index c9424786c53d..8303ab960f80 100644
--- a/sound/soc/mediatek/mt8196/mt8196-nau8825.c
+++ b/sound/soc/mediatek/mt8196/mt8196-nau8825.c
@@ -104,8 +104,6 @@ static const struct snd_kcontrol_new mt8196_nau8825_controls[] = {
#define EXT_SPK_AMP_W_NAME "Ext_Speaker_Amp"
-static struct snd_soc_card mt8196_nau8825_soc_card;
-
static const struct snd_soc_dapm_widget mt8196_nau8825_card_widgets[] = {
/* SOF Uplink */
SND_SOC_DAPM_MIXER("SOF_DMA_UL0", SND_SOC_NOPM, 0, 0, NULL, 0),
diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c
index 90448df6c0b2..dceee837c67d 100644
--- a/sound/soc/mediatek/mt8365/mt8365-mt6357.c
+++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c
@@ -70,7 +70,8 @@ static const struct snd_soc_dapm_route mt8365_mt6357_routes[] = {
static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
+ struct mt8365_mt6357_priv *priv = soc_card_data->mach_priv;
int ret = 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -101,7 +102,8 @@ static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream)
static void mt8365_mt6357_int_adda_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
+ struct mt8365_mt6357_priv *priv = soc_card_data->mach_priv;
int ret = 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -245,7 +247,8 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = {
static int mt8365_mt6357_gpio_probe(struct snd_soc_card *card)
{
- struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(card);
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
+ struct mt8365_mt6357_priv *priv = soc_card_data->mach_priv;
struct device *dev = card->dev;
int ret, i;
@@ -294,7 +297,6 @@ static int mt8365_mt6357_dev_probe(struct mtk_soc_card_data *soc_card_data, bool
struct mt8365_mt6357_priv *mach_priv;
int ret;
- card->dev = dev;
ret = parse_dai_link_info(card);
if (ret)
goto err;
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
index 24078e4396b0..f9ec0ebb01f0 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
@@ -4,6 +4,8 @@ snd-soc-meson-aiu-y := aiu.o
snd-soc-meson-aiu-y += aiu-acodec-ctrl.o
snd-soc-meson-aiu-y += aiu-codec-ctrl.o
snd-soc-meson-aiu-y += aiu-encoder-i2s.o
+snd-soc-meson-aiu-y += gx-formatter.o
+snd-soc-meson-aiu-y += aiu-formatter-i2s.o
snd-soc-meson-aiu-y += aiu-encoder-spdif.o
snd-soc-meson-aiu-y += aiu-fifo.o
snd-soc-meson-aiu-y += aiu-fifo-i2s.o
diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c
index 3b4061508c18..58dce9f08c9d 100644
--- a/sound/soc/meson/aiu-encoder-i2s.c
+++ b/sound/soc/meson/aiu-encoder-i2s.c
@@ -10,14 +10,11 @@
#include <sound/soc-dai.h>
#include "aiu.h"
+#include "gx-formatter.h"
+#include "gx-interface.h"
-#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0)
-#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5)
-#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9)
#define AIU_I2S_SOURCE_DESC_MODE_SPLIT BIT(11)
-#define AIU_RST_SOFT_I2S_FAST BIT(0)
-#define AIU_I2S_DAC_CFG_MSB_FIRST BIT(2)
#define AIU_CLK_CTRL_I2S_DIV_EN BIT(0)
#define AIU_CLK_CTRL_I2S_DIV GENMASK(3, 2)
#define AIU_CLK_CTRL_AOCLK_INVERT BIT(6)
@@ -35,49 +32,6 @@ static void aiu_encoder_i2s_divider_enable(struct snd_soc_component *component,
enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0);
}
-static int aiu_encoder_i2s_setup_desc(struct snd_soc_component *component,
- struct snd_pcm_hw_params *params)
-{
- /* Always operate in split (classic interleaved) mode */
- unsigned int desc = AIU_I2S_SOURCE_DESC_MODE_SPLIT;
-
- /* Reset required to update the pipeline */
- snd_soc_component_write(component, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST);
- snd_soc_component_read(component, AIU_I2S_SYNC);
-
- switch (params_physical_width(params)) {
- case 16: /* Nothing to do */
- break;
-
- case 32:
- desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT |
- AIU_I2S_SOURCE_DESC_MODE_32BIT);
- break;
-
- default:
- return -EINVAL;
- }
-
- switch (params_channels(params)) {
- case 2: /* Nothing to do */
- break;
- case 8:
- desc |= AIU_I2S_SOURCE_DESC_MODE_8CH;
- break;
- default:
- return -EINVAL;
- }
-
- snd_soc_component_update_bits(component, AIU_I2S_SOURCE_DESC,
- AIU_I2S_SOURCE_DESC_MODE_8CH |
- AIU_I2S_SOURCE_DESC_MODE_24BIT |
- AIU_I2S_SOURCE_DESC_MODE_32BIT |
- AIU_I2S_SOURCE_DESC_MODE_SPLIT,
- desc);
-
- return 0;
-}
-
static int aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *component,
struct snd_pcm_hw_params *params,
unsigned int bs)
@@ -108,6 +62,32 @@ static int aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *component,
return 0;
}
+/*
+ * Return true if the given combination of channels and sample width requires
+ * the bs quirk. Return false otherwise.
+ */
+static bool aiu_encoder_is_bs_quirk(unsigned int channels, int width)
+{
+ return (channels == 8) && (width == 16);
+}
+
+static int aiu_encoder_check_bs_quirk(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct gx_stream *other_stream = snd_soc_dai_dma_data_get(dai, !substream->stream);
+
+ /* Nothing to do if the other stream doesn't exist or it's not configured yet. */
+ if (!other_stream || !other_stream->channels)
+ return 0;
+
+ if (aiu_encoder_is_bs_quirk(other_stream->channels, other_stream->width) !=
+ aiu_encoder_is_bs_quirk(params_channels(params), params_width(params)))
+ return -EINVAL;
+
+ return 0;
+}
+
static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component,
struct snd_pcm_hw_params *params,
unsigned int bs)
@@ -119,7 +99,7 @@ static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component,
* increased by 50% to get the correct output rate.
* No idea why !
*/
- if (params_width(params) == 16 && params_channels(params) == 8) {
+ if (aiu_encoder_is_bs_quirk(params_channels(params), params_width(params))) {
if (bs % 2) {
dev_err(component->dev,
"Cannot increase i2s divider by 50%%\n");
@@ -141,25 +121,23 @@ static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component,
return 0;
}
-static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component,
- struct snd_pcm_hw_params *params)
+static int aiu_encoder_i2s_set_clocks(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
{
+ struct snd_soc_component *component = dai->component;
struct aiu *aiu = snd_soc_component_get_drvdata(component);
+ struct gx_iface *iface = &aiu->i2s.iface;
unsigned int srate = params_rate(params);
unsigned int fs, bs;
int ret;
/* Get the oversampling factor */
- fs = DIV_ROUND_CLOSEST(clk_get_rate(aiu->i2s.clks[MCLK].clk), srate);
+ fs = DIV_ROUND_CLOSEST(iface->mclk_rate, srate);
- if (fs % 64)
+ if ((fs % 64) || (fs == 0))
return -EINVAL;
- /* Send data MSB first */
- snd_soc_component_update_bits(component, AIU_I2S_DAC_CFG,
- AIU_I2S_DAC_CFG_MSB_FIRST,
- AIU_I2S_DAC_CFG_MSB_FIRST);
-
/* Set bclk to lrlck ratio */
snd_soc_component_update_bits(component, AIU_CODEC_DAC_LRCLK_CTRL,
AIU_CODEC_DAC_LRCLK_CTRL_DIV,
@@ -168,10 +146,22 @@ static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component,
bs = fs / 64;
- if (aiu->platform->has_clk_ctrl_more_i2s_div)
+ if (aiu->platform->has_clk_ctrl_more_i2s_div) {
+ /*
+ * The hw rules added in startup() make this unreachable in the
+ * sequential case, but both streams may be refined concurrently
+ * before either commits its config, since only ops->hw_params
+ * runs under the card's pcm_mutex. Re-check against the committed
+ * state of the other stream, which is stable under that mutex.
+ */
+ if (aiu_encoder_check_bs_quirk(substream, params, dai)) {
+ dev_err(dai->dev, "bclk requirements incompatible with other stream\n");
+ return -EINVAL;
+ }
ret = aiu_encoder_i2s_set_more_div(component, params, bs);
- else
+ } else {
ret = aiu_encoder_i2s_set_legacy_div(component, params, bs);
+ }
if (ret)
return ret;
@@ -188,23 +178,37 @@ static int aiu_encoder_i2s_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 gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
int ret;
- /* Disable the clock while changing the settings */
- aiu_encoder_i2s_divider_enable(component, false);
-
- ret = aiu_encoder_i2s_setup_desc(component, params);
+ ret = aiu_encoder_i2s_set_clocks(substream, params, dai);
if (ret) {
- dev_err(dai->dev, "setting i2s desc failed\n");
+ dev_err(dai->dev, "setting i2s clocks failed: %d\n", ret);
return ret;
}
- ret = aiu_encoder_i2s_set_clocks(component, params);
- if (ret) {
- dev_err(dai->dev, "setting i2s clocks failed\n");
+ ts->physical_width = params_physical_width(params);
+ ts->width = params_width(params);
+ ts->channels = params_channels(params);
+
+ return 0;
+}
+
+static int aiu_encoder_i2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+ struct snd_soc_component *component = dai->component;
+ int ret;
+
+ if (ts->clk_enabled)
+ return 0;
+
+ ret = clk_prepare_enable(ts->iface->mclk);
+ if (ret)
return ret;
- }
+
+ ts->clk_enabled = true;
aiu_encoder_i2s_divider_enable(component, true);
@@ -214,9 +218,24 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream,
static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
struct snd_soc_component *component = dai->component;
- aiu_encoder_i2s_divider_enable(component, false);
+ /*
+ * If this is the last substream being closed then disable the i2s
+ * clock divider.
+ */
+ if (snd_soc_dai_active(dai) <= 1)
+ aiu_encoder_i2s_divider_enable(component, 0);
+
+ if (ts->clk_enabled) {
+ clk_disable_unprepare(ts->iface->mclk);
+ ts->clk_enabled = false;
+ }
+
+ ts->channels = 0;
+ ts->width = 0;
+ ts->physical_width = 0;
return 0;
}
@@ -224,6 +243,8 @@ static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream,
static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
+ struct aiu *aiu = snd_soc_component_get_drvdata(component);
+ struct gx_iface *iface = &aiu->i2s.iface;
unsigned int inv = fmt & SND_SOC_DAIFMT_INV_MASK;
unsigned int val = 0;
unsigned int skew;
@@ -255,9 +276,12 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
skew = 0;
break;
default:
+ dev_err(dai->dev, "unsupported dai format\n");
return -EINVAL;
}
+ iface->fmt = fmt;
+
val |= FIELD_PREP(AIU_CLK_CTRL_LRCLK_SKEW, skew);
snd_soc_component_update_bits(component, AIU_CLK_CTRL,
AIU_CLK_CTRL_LRCLK_INVERT |
@@ -272,6 +296,7 @@ static int aiu_encoder_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
+ struct gx_iface *iface = &aiu->i2s.iface;
int ret;
if (WARN_ON(clk_id != 0))
@@ -280,11 +305,15 @@ static int aiu_encoder_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
if (dir == SND_SOC_CLOCK_IN)
return 0;
- ret = clk_set_rate(aiu->i2s.clks[MCLK].clk, freq);
- if (ret)
- dev_err(dai->dev, "Failed to set sysclk to %uHz", freq);
+ ret = clk_set_rate(iface->mclk, freq);
+ if (ret) {
+ dev_err(dai->dev, "Failed to set sysclk to %uHz: %d", freq, ret);
+ return ret;
+ }
- return ret;
+ iface->mclk_rate = freq;
+
+ return 0;
}
static const unsigned int hw_channels[] = {2, 8};
@@ -294,10 +323,45 @@ static const struct snd_pcm_hw_constraint_list hw_channel_constraints = {
.mask = 0,
};
+static int aiu_encoder_i2s_pcm_hw_rule(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct gx_stream *other = rule->private;
+ struct snd_interval *ch = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ /*
+ * The quirk is technically based on the significant bits whereas here
+ * we're using the physical width for simplicity. This works because
+ * S16_LE is the only format supported by this encoder that has:
+ * significant bits = physical width = 16-bits
+ */
+ struct snd_interval *phys_width = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
+ struct snd_interval new_i;
+
+ if (other->channels == 0)
+ return 0;
+
+ snd_interval_any(&new_i);
+
+ if (rule->var == SNDRV_PCM_HW_PARAM_CHANNELS) {
+ if (aiu_encoder_is_bs_quirk(other->channels, other->width))
+ new_i.min = new_i.max = 8;
+ else if (snd_interval_single(phys_width) && phys_width->min == 16)
+ new_i.max = 2; /* Force 2ch */
+ } else { /* SNDRV_PCM_HW_PARAM_SAMPLE_BITS */
+ if (aiu_encoder_is_bs_quirk(other->channels, other->width))
+ new_i.min = new_i.max = 16;
+ else if (snd_interval_single(ch) && ch->min == 8)
+ new_i.min = 17; /* Request physical width > 16 bits */
+ }
+
+ return snd_interval_refine(hw_param_interval(params, rule->var), &new_i);
+}
+
static int aiu_encoder_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
+ struct gx_stream *other_stream = snd_soc_dai_dma_data_get(dai, !substream->stream);
int ret;
/* Make sure the encoder gets either 2 or 8 channels */
@@ -305,15 +369,79 @@ static int aiu_encoder_i2s_startup(struct snd_pcm_substream *substream,
SNDRV_PCM_HW_PARAM_CHANNELS,
&hw_channel_constraints);
if (ret) {
- dev_err(dai->dev, "adding channels constraints failed\n");
+ dev_err(dai->dev, "adding channels constraints failed: %d\n", ret);
return ret;
}
- ret = clk_bulk_prepare_enable(aiu->i2s.clk_num, aiu->i2s.clks);
- if (ret)
- dev_err(dai->dev, "failed to enable i2s clocks\n");
+ /*
+ * If DAI supports both playback and capture streams ensure the bs-quirk is
+ * handled correctly.
+ * This is only valid for GX platforms (has_clk_ctrl_more_i2s_div=true).
+ */
+ if (aiu->platform->has_clk_ctrl_more_i2s_div && other_stream) {
+ ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ aiu_encoder_i2s_pcm_hw_rule,
+ other_stream,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
+ if (ret)
+ return ret;
+
+ ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ aiu_encoder_i2s_pcm_hw_rule,
+ other_stream,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
+ if (ret)
+ return ret;
+ }
- return ret;
+ /*
+ * Enable only clocks which are required for the interface internal
+ * logic. MCLK is enabled/disabled from the formatter and the I2S
+ * divider is enabled/disabled in "hw_params"/"hw_free", respectively.
+ */
+ ret = clk_prepare_enable(aiu->i2s.clks[PCLK].clk);
+ if (ret) {
+ dev_err(dai->dev, "failed to enable PCLK: %d\n", ret);
+ return ret;
+ }
+ ret = clk_prepare_enable(aiu->i2s.clks[MIXER].clk);
+ if (ret) {
+ dev_err(dai->dev, "failed to enable MIXER: %d\n", ret);
+ clk_disable_unprepare(aiu->i2s.clks[PCLK].clk);
+ return ret;
+ }
+ ret = clk_prepare_enable(aiu->i2s.clks[AOCLK].clk);
+ if (ret) {
+ dev_err(dai->dev, "failed to enable AOCLK: %d\n", ret);
+ clk_disable_unprepare(aiu->i2s.clks[MIXER].clk);
+ clk_disable_unprepare(aiu->i2s.clks[PCLK].clk);
+ return ret;
+ }
+
+ /*
+ * We're always operating in split mode for the playback stream.
+ *
+ * This setting arguably belong to the 'aiu-formatter', but it's kept
+ * here for backward compatibility reason. At reset the I2S encoder
+ * operates in normal mode which would only support 8ch, but by default
+ * only 2ch are enabled. If a playback stream is started without
+ * changing to split mode, then the I2S encoder doesn't consume audio
+ * samples and the playback fails.
+ * Moving this to 'aiu-formatter' would cause the split mode to be set
+ * only when the formatter is enabled, which doesn't happen at boot as
+ * the default value for "HDMI CTRL SRC" is "DISABLED".
+ */
+ ret = snd_soc_component_update_bits(dai->component, AIU_I2S_SOURCE_DESC,
+ AIU_I2S_SOURCE_DESC_MODE_SPLIT,
+ AIU_I2S_SOURCE_DESC_MODE_SPLIT);
+ if (ret < 0)
+ dev_err(dai->dev, "failed to update AIU_I2S_SOURCE_DESC: %d", ret);
+
+ return 0;
}
static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream,
@@ -321,14 +449,89 @@ static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream,
{
struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
- clk_bulk_disable_unprepare(aiu->i2s.clk_num, aiu->i2s.clks);
+ clk_disable_unprepare(aiu->i2s.clks[AOCLK].clk);
+ clk_disable_unprepare(aiu->i2s.clks[MIXER].clk);
+ clk_disable_unprepare(aiu->i2s.clks[PCLK].clk);
+}
+
+static int aiu_encoder_i2s_trigger(struct snd_pcm_substream *substream,
+ int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+ int ret;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ret = gx_stream_start(ts);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ gx_stream_stop(ts);
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int aiu_encoder_i2s_remove_dai(struct snd_soc_dai *dai)
+{
+ int stream;
+
+ for_each_pcm_streams(stream) {
+ struct gx_stream *ts;
+
+ ts = snd_soc_dai_dma_data_get(dai, stream);
+ if (ts)
+ gx_stream_free(ts);
+
+ snd_soc_dai_dma_data_set(dai, stream, NULL);
+ }
+
+ return 0;
+}
+
+static int aiu_encoder_i2s_probe_dai(struct snd_soc_dai *dai)
+{
+ struct aiu *aiu = snd_soc_dai_get_drvdata(dai);
+ struct gx_iface *iface = &aiu->i2s.iface;
+ int stream;
+
+ for_each_pcm_streams(stream) {
+ struct gx_stream *ts;
+
+ if (!snd_soc_dai_get_widget(dai, stream))
+ continue;
+
+ ts = gx_stream_alloc(iface);
+ if (!ts) {
+ aiu_encoder_i2s_remove_dai(dai);
+ return -ENOMEM;
+ }
+ snd_soc_dai_dma_data_set(dai, stream, ts);
+ }
+
+ iface->mclk = aiu->i2s.clks[MCLK].clk;
+ iface->mclk_rate = clk_get_rate(iface->mclk);
+
+ return 0;
}
const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops = {
+ .probe = aiu_encoder_i2s_probe_dai,
+ .remove = aiu_encoder_i2s_remove_dai,
.hw_params = aiu_encoder_i2s_hw_params,
+ .prepare = aiu_encoder_i2s_prepare,
.hw_free = aiu_encoder_i2s_hw_free,
.set_fmt = aiu_encoder_i2s_set_fmt,
.set_sysclk = aiu_encoder_i2s_set_sysclk,
.startup = aiu_encoder_i2s_startup,
.shutdown = aiu_encoder_i2s_shutdown,
+ .trigger = aiu_encoder_i2s_trigger,
};
diff --git a/sound/soc/meson/aiu-formatter-i2s.c b/sound/soc/meson/aiu-formatter-i2s.c
new file mode 100644
index 000000000000..cb554c2e7ce4
--- /dev/null
+++ b/sound/soc/meson/aiu-formatter-i2s.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2026 BayLibre, SAS.
+// Author: Valerio Setti <vsetti@baylibre.com>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "aiu.h"
+#include "gx-formatter.h"
+
+#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0)
+#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5)
+#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9)
+
+#define AIU_I2S_DAC_CFG_MSB_FIRST BIT(2)
+
+static struct snd_soc_dai *
+aiu_formatter_i2s_get_be(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_path *p;
+ struct snd_soc_dai *be;
+
+ snd_soc_dapm_widget_for_each_sink_path(w, p) {
+ if (!p->connect)
+ continue;
+
+ if (p->sink->id == snd_soc_dapm_dai_in)
+ return (struct snd_soc_dai *)p->sink->priv;
+
+ be = aiu_formatter_i2s_get_be(p->sink);
+ if (be)
+ return be;
+ }
+
+ return NULL;
+}
+
+static struct gx_stream *
+aiu_formatter_i2s_get_stream(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dai *be = aiu_formatter_i2s_get_be(w);
+
+ if (!be)
+ return NULL;
+
+ return snd_soc_dai_dma_data_get_playback(be);
+}
+
+static int aiu_formatter_i2s_prepare(struct regmap *map,
+ const struct gx_formatter_hw *quirks,
+ struct gx_stream *ts)
+{
+ /* Always operate in split (classic interleaved) mode */
+ unsigned int desc = 0;
+
+ /*
+ * Pipeline reset is already implemented in aiu_fifo_i2s_trigger() at
+ * trigger time.
+ */
+
+ switch (ts->physical_width) {
+ case 16: /* Nothing to do */
+ break;
+
+ case 32:
+ desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT |
+ AIU_I2S_SOURCE_DESC_MODE_32BIT);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch (ts->channels) {
+ case 2: /* Nothing to do */
+ break;
+ case 8:
+ desc |= AIU_I2S_SOURCE_DESC_MODE_8CH;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(map, AIU_I2S_SOURCE_DESC,
+ AIU_I2S_SOURCE_DESC_MODE_8CH |
+ AIU_I2S_SOURCE_DESC_MODE_24BIT |
+ AIU_I2S_SOURCE_DESC_MODE_32BIT,
+ desc);
+
+ /* Send data MSB first */
+ regmap_update_bits(map, AIU_I2S_DAC_CFG,
+ AIU_I2S_DAC_CFG_MSB_FIRST,
+ AIU_I2S_DAC_CFG_MSB_FIRST);
+
+ return 0;
+}
+
+const struct gx_formatter_ops aiu_formatter_i2s_ops = {
+ .get_stream = aiu_formatter_i2s_get_stream,
+ .prepare = aiu_formatter_i2s_prepare,
+};
diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c
index f2890111c1d2..2668646e3597 100644
--- a/sound/soc/meson/aiu.c
+++ b/sound/soc/meson/aiu.c
@@ -29,13 +29,22 @@ static SOC_ENUM_SINGLE_DECL(aiu_spdif_encode_sel_enum, AIU_I2S_MISC,
static const struct snd_kcontrol_new aiu_spdif_encode_mux =
SOC_DAPM_ENUM("SPDIF Buffer Src", aiu_spdif_encode_sel_enum);
-static const struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] = {
- SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0,
- &aiu_spdif_encode_mux),
+#define AIU_WIDGET_SPDIF_SRC_SEL 0
+#define AIU_WIDGET_I2S_FORMATTER 1
+
+static struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] = {
+ [AIU_WIDGET_SPDIF_SRC_SEL] =
+ SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0,
+ &aiu_spdif_encode_mux),
+ [AIU_WIDGET_I2S_FORMATTER] =
+ SND_SOC_DAPM_PGA_E("I2S Formatter", SND_SOC_NOPM, 0, 0, NULL, 0,
+ gx_formatter_event,
+ (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)),
};
static const struct snd_soc_dapm_route aiu_cpu_dapm_routes[] = {
- { "I2S Encoder Playback", NULL, "I2S FIFO Playback" },
+ { "I2S Formatter", NULL, "I2S FIFO Playback" },
+ { "I2S Encoder Playback", NULL, "I2S Formatter" },
{ "SPDIF SRC SEL", "SPDIF", "SPDIF FIFO Playback" },
{ "SPDIF SRC SEL", "I2S", "I2S FIFO Playback" },
{ "SPDIF Encoder Playback", NULL, "SPDIF SRC SEL" },
@@ -145,6 +154,7 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = {
.formats = AIU_FORMATS,
},
.ops = &aiu_encoder_i2s_dai_ops,
+ .symmetric_rate = 1,
},
[CPU_SPDIF_ENCODER] = {
.name = "SPDIF Encoder",
@@ -172,6 +182,11 @@ static const struct regmap_config aiu_regmap_cfg = {
.max_register = 0x2ac,
};
+const struct gx_formatter_driver aiu_formatter_i2s_drv = {
+ .regmap_cfg = &aiu_regmap_cfg,
+ .ops = &aiu_formatter_i2s_ops,
+};
+
static int aiu_clk_bulk_get(struct device *dev,
const char * const *ids,
unsigned int num,
@@ -282,6 +297,14 @@ static int aiu_probe(struct platform_device *pdev)
if (ret)
return ret;
+ /* Allocate the aiu-formatter into its widget */
+ ret = gx_formatter_create(dev, &aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER],
+ &aiu_formatter_i2s_drv, map);
+ if (ret) {
+ dev_err(dev, "Failed to allocate aiu formatter\n");
+ goto err;
+ }
+
/* Register the cpu component of the aiu */
ret = snd_soc_register_component(dev, &aiu_cpu_component,
aiu_cpu_dai_drv,
@@ -310,12 +333,14 @@ static int aiu_probe(struct platform_device *pdev)
return 0;
err:
+ gx_formatter_free(&aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER]);
snd_soc_unregister_component(dev);
return ret;
}
static void aiu_remove(struct platform_device *pdev)
{
+ gx_formatter_free(&aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER]);
snd_soc_unregister_component(&pdev->dev);
}
diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h
index 0f94c8bf6081..7d0b98c1f351 100644
--- a/sound/soc/meson/aiu.h
+++ b/sound/soc/meson/aiu.h
@@ -7,6 +7,8 @@
#ifndef _MESON_AIU_H
#define _MESON_AIU_H
+#include "gx-formatter.h"
+
struct clk;
struct clk_bulk_data;
struct device;
@@ -25,6 +27,7 @@ struct aiu_interface {
struct clk_bulk_data *clks;
unsigned int clk_num;
int irq;
+ struct gx_iface iface;
};
struct aiu_platform_data {
@@ -58,6 +61,7 @@ extern const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops;
extern const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops;
extern const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops;
extern const struct snd_soc_dai_ops aiu_encoder_spdif_dai_ops;
+extern const struct gx_formatter_ops aiu_formatter_i2s_ops;
#define AIU_IEC958_BPF 0x000
#define AIU_958_MISC 0x010
diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c
index b4dca80e15e4..c36f727af4ba 100644
--- a/sound/soc/meson/axg-card.c
+++ b/sound/soc/meson/axg-card.c
@@ -107,6 +107,7 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card,
struct snd_soc_dai_link *pad;
struct snd_soc_dai_link *lb;
struct snd_soc_dai_link_component *dlc;
+ struct device *dev = card->dev;
int ret;
/* extend links */
@@ -117,11 +118,11 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card,
pad = &card->dai_link[*index];
lb = &card->dai_link[*index + 1];
- lb->name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-lb", pad->name);
+ lb->name = devm_kasprintf(dev, GFP_KERNEL, "%s-lb", pad->name);
if (!lb->name)
return -ENOMEM;
- dlc = devm_kzalloc(card->dev, sizeof(*dlc), GFP_KERNEL);
+ dlc = devm_kzalloc(dev, sizeof(*dlc), GFP_KERNEL);
if (!dlc)
return -ENOMEM;
@@ -158,13 +159,14 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card,
struct device_node *node,
struct axg_dai_link_tdm_data *be)
{
+ struct device *dev = card->dev;
char propname[32];
u32 tx, rx;
int i;
- be->tx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES,
+ be->tx_mask = devm_kcalloc(dev, AXG_TDM_NUM_LANES,
sizeof(*be->tx_mask), GFP_KERNEL);
- be->rx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES,
+ be->rx_mask = devm_kcalloc(dev, AXG_TDM_NUM_LANES,
sizeof(*be->rx_mask), GFP_KERNEL);
if (!be->tx_mask || !be->rx_mask)
return -ENOMEM;
@@ -191,7 +193,7 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card,
/* ... but the interface should at least have one direction */
if (!tx && !rx) {
- dev_err(card->dev, "tdm link has no cpu slots\n");
+ dev_err(dev, "tdm link has no cpu slots\n");
return -EINVAL;
}
@@ -207,7 +209,7 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card,
* Error if the slots can't accommodate the largest mask or
* if it is just too big
*/
- dev_err(card->dev, "bad slot number\n");
+ dev_err(dev, "bad slot number\n");
return -EINVAL;
}
@@ -222,8 +224,9 @@ static int axg_card_parse_codecs_masks(struct snd_soc_card *card,
struct axg_dai_link_tdm_data *be)
{
struct axg_dai_link_tdm_mask *codec_mask;
+ struct device *dev = card->dev;
- codec_mask = devm_kcalloc(card->dev, link->num_codecs,
+ codec_mask = devm_kcalloc(dev, link->num_codecs,
sizeof(*codec_mask), GFP_KERNEL);
if (!codec_mask)
return -ENOMEM;
@@ -249,10 +252,11 @@ static int axg_card_parse_tdm(struct snd_soc_card *card,
struct meson_card *priv = snd_soc_card_get_drvdata(card);
struct snd_soc_dai_link *link = &card->dai_link[*index];
struct axg_dai_link_tdm_data *be;
+ struct device *dev = card->dev;
int ret;
/* Allocate tdm link parameters */
- be = devm_kzalloc(card->dev, sizeof(*be), GFP_KERNEL);
+ be = devm_kzalloc(dev, sizeof(*be), GFP_KERNEL);
if (!be)
return -ENOMEM;
priv->link_data[*index] = be;
@@ -266,7 +270,7 @@ static int axg_card_parse_tdm(struct snd_soc_card *card,
ret = axg_card_parse_cpu_tdm_slots(card, link, node, be);
if (ret) {
- dev_err(card->dev, "error parsing tdm link slots\n");
+ dev_err(dev, "error parsing tdm link slots\n");
return ret;
}
@@ -310,9 +314,10 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
{
struct snd_soc_dai_link *dai_link = &card->dai_link[*index];
struct snd_soc_dai_link_component *cpu;
+ struct device *dev = card->dev;
int ret;
- cpu = devm_kzalloc(card->dev, sizeof(*cpu), GFP_KERNEL);
+ cpu = devm_kzalloc(dev, sizeof(*cpu), GFP_KERNEL);
if (!cpu)
return -ENOMEM;
diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c
index a95375b53f0a..21941ee552c5 100644
--- a/sound/soc/meson/g12a-toacodec.c
+++ b/sound/soc/meson/g12a-toacodec.c
@@ -312,7 +312,7 @@ static int g12a_toacodec_probe(struct platform_device *pdev)
ret = device_reset(dev);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret, "failed to reset device\n");
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c
index d541ca4acfaf..967109ca2b57 100644
--- a/sound/soc/meson/g12a-tohdmitx.c
+++ b/sound/soc/meson/g12a-tohdmitx.c
@@ -251,7 +251,7 @@ static int g12a_tohdmitx_probe(struct platform_device *pdev)
ret = device_reset(dev);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret, "failed to reset device\n");
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
diff --git a/sound/soc/meson/gx-card.c b/sound/soc/meson/gx-card.c
index b408cc2bbc91..932be0a09306 100644
--- a/sound/soc/meson/gx-card.c
+++ b/sound/soc/meson/gx-card.c
@@ -48,9 +48,10 @@ static int gx_card_parse_i2s(struct snd_soc_card *card,
struct meson_card *priv = snd_soc_card_get_drvdata(card);
struct snd_soc_dai_link *link = &card->dai_link[*index];
struct gx_dai_link_i2s_data *be;
+ struct device *dev = card->dev;
/* Allocate i2s link parameters */
- be = devm_kzalloc(card->dev, sizeof(*be), GFP_KERNEL);
+ be = devm_kzalloc(dev, sizeof(*be), GFP_KERNEL);
if (!be)
return -ENOMEM;
priv->link_data[*index] = be;
@@ -81,9 +82,10 @@ static int gx_card_add_link(struct snd_soc_card *card, struct device_node *np,
{
struct snd_soc_dai_link *dai_link = &card->dai_link[*index];
struct snd_soc_dai_link_component *cpu;
+ struct device *dev = card->dev;
int ret;
- cpu = devm_kzalloc(card->dev, sizeof(*cpu), GFP_KERNEL);
+ cpu = devm_kzalloc(dev, sizeof(*cpu), GFP_KERNEL);
if (!cpu)
return -ENOMEM;
diff --git a/sound/soc/meson/gx-formatter.c b/sound/soc/meson/gx-formatter.c
new file mode 100644
index 000000000000..311e63affb23
--- /dev/null
+++ b/sound/soc/meson/gx-formatter.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2026 BayLibre, SAS.
+// Author: Valerio Setti <vsetti@baylibre.com>
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "gx-formatter.h"
+
+struct gx_formatter {
+ struct list_head list;
+ struct gx_stream *stream;
+ const struct gx_formatter_driver *drv;
+ bool enabled;
+ struct regmap *map;
+};
+
+static int gx_formatter_enable(struct gx_formatter *formatter)
+{
+ int ret;
+
+ /* Do nothing if the formatter is already enabled */
+ if (formatter->enabled)
+ return 0;
+
+ /* Setup the stream parameter in the formatter */
+ if (formatter->drv->ops->prepare) {
+ ret = formatter->drv->ops->prepare(formatter->map,
+ formatter->drv->quirks,
+ formatter->stream);
+ if (ret)
+ return ret;
+ }
+
+ /* Finally, actually enable the formatter */
+ if (formatter->drv->ops->enable)
+ formatter->drv->ops->enable(formatter->map);
+
+ formatter->enabled = true;
+
+ return 0;
+}
+
+static void gx_formatter_disable(struct gx_formatter *formatter)
+{
+ /* Do nothing if the formatter is already disabled */
+ if (!formatter->enabled)
+ return;
+
+ if (formatter->drv->ops->disable)
+ formatter->drv->ops->disable(formatter->map);
+
+ formatter->enabled = false;
+}
+
+static int gx_formatter_attach(struct gx_formatter *formatter)
+{
+ struct gx_stream *ts = formatter->stream;
+ int ret = 0;
+
+ mutex_lock(&ts->lock);
+
+ /* Catch up if the stream is already running when we attach */
+ if (ts->ready) {
+ ret = gx_formatter_enable(formatter);
+ if (ret) {
+ pr_err("failed to enable formatter\n");
+ goto out;
+ }
+ }
+
+ list_add_tail(&formatter->list, &ts->formatter_list);
+out:
+ mutex_unlock(&ts->lock);
+ return ret;
+}
+
+static void gx_formatter_detach(struct gx_formatter *formatter)
+{
+ struct gx_stream *ts = formatter->stream;
+
+ if (!ts)
+ return;
+
+ mutex_lock(&ts->lock);
+ list_del(&formatter->list);
+ mutex_unlock(&ts->lock);
+
+ gx_formatter_disable(formatter);
+}
+
+static int gx_formatter_power_up(struct gx_formatter *formatter,
+ struct snd_soc_dapm_widget *w)
+{
+ struct gx_stream *ts = formatter->drv->ops->get_stream(w);
+ int ret;
+
+ /*
+ * If we don't get a stream at this stage, it would mean that the
+ * widget is powering up but is not attached to any backend DAI.
+ * It should not happen, ever !
+ */
+ if (WARN_ON(!ts))
+ return -ENODEV;
+
+ formatter->stream = ts;
+ INIT_LIST_HEAD(&formatter->list);
+ ret = gx_formatter_attach(formatter);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void gx_formatter_power_down(struct gx_formatter *formatter)
+{
+ gx_formatter_detach(formatter);
+ formatter->stream = NULL;
+}
+
+int gx_formatter_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *control,
+ int event)
+{
+ struct snd_soc_component *c;
+ struct gx_formatter *formatter;
+ int ret = 0;
+
+ c = snd_soc_dapm_to_component(w->dapm);
+
+ if (w->priv)
+ formatter = w->priv;
+ else
+ formatter = snd_soc_component_get_drvdata(c);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = gx_formatter_power_up(formatter, w);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ gx_formatter_power_down(formatter);
+ break;
+
+ default:
+ dev_err(c->dev, "Unexpected event %d\n", event);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gx_formatter_event);
+
+int gx_formatter_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct gx_formatter_driver *drv;
+ struct gx_formatter *formatter;
+ void __iomem *regs;
+
+ drv = of_device_get_match_data(dev);
+ if (!drv) {
+ dev_err(dev, "failed to match device\n");
+ return -ENODEV;
+ }
+
+ formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
+ if (!formatter)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, formatter);
+ formatter->drv = drv;
+
+ regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ formatter->map = devm_regmap_init_mmio(dev, regs, drv->regmap_cfg);
+ if (IS_ERR(formatter->map)) {
+ dev_err(dev, "failed to init regmap: %ld\n",
+ PTR_ERR(formatter->map));
+ return PTR_ERR(formatter->map);
+ }
+
+ return devm_snd_soc_register_component(dev, drv->component_drv,
+ NULL, 0);
+}
+EXPORT_SYMBOL_GPL(gx_formatter_probe);
+
+int gx_formatter_create(struct device *dev,
+ struct snd_soc_dapm_widget *w,
+ const struct gx_formatter_driver *drv,
+ struct regmap *regmap)
+{
+ struct gx_formatter *formatter;
+
+ formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
+ if (!formatter)
+ return -ENOMEM;
+
+ formatter->drv = drv;
+ formatter->map = regmap;
+
+ w->priv = formatter;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gx_formatter_create);
+
+int gx_stream_start(struct gx_stream *ts)
+{
+ struct gx_formatter *formatter;
+ int ret = 0;
+
+ mutex_lock(&ts->lock);
+
+ /* Start all the formatters attached to the stream */
+ list_for_each_entry(formatter, &ts->formatter_list, list) {
+ ret = gx_formatter_enable(formatter);
+ if (ret) {
+ pr_err("failed to enable formatter\n");
+ goto out;
+ }
+ }
+
+ ts->ready = true;
+
+out:
+ mutex_unlock(&ts->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gx_stream_start);
+
+void gx_stream_stop(struct gx_stream *ts)
+{
+ struct gx_formatter *formatter;
+
+ mutex_lock(&ts->lock);
+ ts->ready = false;
+
+ /* Stop all the formatters attached to the stream */
+ list_for_each_entry(formatter, &ts->formatter_list, list) {
+ gx_formatter_disable(formatter);
+ }
+
+ mutex_unlock(&ts->lock);
+}
+EXPORT_SYMBOL_GPL(gx_stream_stop);
+
+struct gx_stream *gx_stream_alloc(struct gx_iface *iface)
+{
+ struct gx_stream *ts;
+
+ ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+ if (ts) {
+ INIT_LIST_HEAD(&ts->formatter_list);
+ mutex_init(&ts->lock);
+ ts->iface = iface;
+ }
+
+ return ts;
+}
+EXPORT_SYMBOL_GPL(gx_stream_alloc);
+
+void gx_stream_free(struct gx_stream *ts)
+{
+ /*
+ * If the list is not empty, it would mean that one of the formatter
+ * widget is still powered and attached to the interface while we
+ * are removing the TDM DAI. It should not be possible
+ */
+ WARN_ON(!list_empty(&ts->formatter_list));
+ mutex_destroy(&ts->lock);
+ kfree(ts);
+}
+EXPORT_SYMBOL_GPL(gx_stream_free);
+
+MODULE_DESCRIPTION("Amlogic GX formatter driver");
+MODULE_AUTHOR("Valerio Setti <vsetti@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/meson/gx-formatter.h b/sound/soc/meson/gx-formatter.h
new file mode 100644
index 000000000000..b90b1814d79b
--- /dev/null
+++ b/sound/soc/meson/gx-formatter.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Copyright (c) 2026 Baylibre SAS.
+ * Author: Valerio Setti <vsetti@baylibre.com>
+ */
+
+#ifndef _MESON_GX_FORMATTER_H
+#define _MESON_GX_FORMATTER_H
+
+#include "gx-interface.h"
+
+struct platform_device;
+struct regmap;
+struct snd_soc_dapm_widget;
+struct snd_kcontrol;
+
+struct gx_formatter_hw {
+ unsigned int skew_offset;
+};
+
+struct gx_formatter_ops {
+ struct gx_stream *(*get_stream)(struct snd_soc_dapm_widget *w);
+ void (*enable)(struct regmap *map);
+ void (*disable)(struct regmap *map);
+ int (*prepare)(struct regmap *map,
+ const struct gx_formatter_hw *quirks,
+ struct gx_stream *ts);
+};
+
+struct gx_formatter_driver {
+ const struct snd_soc_component_driver *component_drv;
+ const struct regmap_config *regmap_cfg;
+ const struct gx_formatter_ops *ops;
+ const struct gx_formatter_hw *quirks;
+};
+
+int gx_formatter_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *control,
+ int event);
+int gx_formatter_probe(struct platform_device *pdev);
+
+int gx_formatter_create(struct device *dev,
+ struct snd_soc_dapm_widget *w,
+ const struct gx_formatter_driver *drv,
+ struct regmap *regmap);
+
+/*
+ * Formatter data is already freed when the associated device is removed,
+ * so we just need to remove the pointer from the widget.
+ */
+static inline void gx_formatter_free(struct snd_soc_dapm_widget *w)
+{
+ w->priv = NULL;
+}
+
+#endif /* _MESON_GX_FORMATTER_H */
diff --git a/sound/soc/meson/gx-interface.h b/sound/soc/meson/gx-interface.h
new file mode 100644
index 000000000000..2a6207e393e8
--- /dev/null
+++ b/sound/soc/meson/gx-interface.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Copyright (c) 2026 Baylibre SAS.
+ * Author: Valerio Setti <vsetti@baylibre.com>
+ */
+
+#ifndef _MESON_GX_INTERFACE_H
+#define _MESON_GX_INTERFACE_H
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+struct gx_iface {
+ struct clk *mclk;
+ unsigned long mclk_rate;
+
+ /* format is common to all the DAIs of the iface */
+ unsigned int fmt;
+};
+
+struct gx_stream {
+ struct gx_iface *iface;
+ struct list_head formatter_list;
+ struct mutex lock;
+ unsigned int channels;
+ unsigned int width;
+ unsigned int physical_width;
+ bool ready;
+
+ /* For continuous clock tracking */
+ bool clk_enabled;
+};
+
+struct gx_stream *gx_stream_alloc(struct gx_iface *iface);
+void gx_stream_free(struct gx_stream *ts);
+int gx_stream_start(struct gx_stream *ts);
+void gx_stream_stop(struct gx_stream *ts);
+
+#endif /* _MESON_GX_INTERFACE_H */
diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c
index cdb759b466ad..f2796dc84fa5 100644
--- a/sound/soc/meson/meson-card-utils.c
+++ b/sound/soc/meson/meson-card-utils.c
@@ -50,25 +50,20 @@ int meson_card_reallocate_links(struct snd_soc_card *card,
num_links * sizeof(*priv->card.dai_link),
GFP_KERNEL | __GFP_ZERO);
if (!links)
- goto err_links;
+ return -ENOMEM;
+
+ priv->card.dai_link = links;
+ priv->card.num_links = num_links;
ldata = krealloc(priv->link_data,
num_links * sizeof(*priv->link_data),
GFP_KERNEL | __GFP_ZERO);
+ /* meson_card_clean_references() will free the links on this error path */
if (!ldata)
- goto err_ldata;
+ return -ENOMEM;
- priv->card.dai_link = links;
priv->link_data = ldata;
- priv->card.num_links = num_links;
return 0;
-
-err_ldata:
- kfree(links);
-err_links:
- dev_err(priv->card.dev, "failed to allocate links\n");
- return -ENOMEM;
-
}
EXPORT_SYMBOL_GPL(meson_card_reallocate_links);
@@ -76,6 +71,7 @@ int meson_card_parse_dai(struct snd_soc_card *card,
struct device_node *node,
struct snd_soc_dai_link_component *dlc)
{
+ struct device *dev = card->dev;
int ret;
if (!dlc || !node)
@@ -83,7 +79,7 @@ int meson_card_parse_dai(struct snd_soc_card *card,
ret = snd_soc_of_get_dlc(node, NULL, dlc, 0);
if (ret)
- return dev_err_probe(card->dev, ret, "can't parse dai\n");
+ return dev_err_probe(dev, ret, "can't parse dai\n");
return ret;
}
@@ -94,7 +90,8 @@ static int meson_card_set_link_name(struct snd_soc_card *card,
struct device_node *node,
const char *prefix)
{
- char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s",
+ struct device *dev = card->dev;
+ char *name = devm_kasprintf(dev, GFP_KERNEL, "%s.%s",
prefix, node->full_name);
if (!name)
return -ENOMEM;
@@ -137,16 +134,17 @@ int meson_card_set_be_link(struct snd_soc_card *card,
struct device_node *node)
{
struct snd_soc_dai_link_component *codec;
+ struct device *dev = card->dev;
int ret, num_codecs;
num_codecs = of_get_child_count(node);
if (!num_codecs) {
- dev_err(card->dev, "be link %s has no codec\n",
+ dev_err(dev, "be link %s has no codec\n",
node->full_name);
return -EINVAL;
}
- codec = devm_kcalloc(card->dev, num_codecs, sizeof(*codec), GFP_KERNEL);
+ codec = devm_kcalloc(dev, num_codecs, sizeof(*codec), GFP_KERNEL);
if (!codec)
return -ENOMEM;
@@ -163,7 +161,7 @@ int meson_card_set_be_link(struct snd_soc_card *card,
ret = meson_card_set_link_name(card, link, node, "be");
if (ret)
- dev_err(card->dev, "error setting %pOFn link name\n", node);
+ dev_err(dev, "error setting %pOFn link name\n", node);
return ret;
}
@@ -194,12 +192,13 @@ EXPORT_SYMBOL_GPL(meson_card_set_fe_link);
static int meson_card_add_links(struct snd_soc_card *card)
{
struct meson_card *priv = snd_soc_card_get_drvdata(card);
- struct device_node *node = card->dev->of_node;
+ struct device *dev = card->dev;
+ struct device_node *node = dev->of_node;
int num, i, ret;
num = of_get_child_count(node);
if (!num) {
- dev_err(card->dev, "card has no links\n");
+ dev_err(dev, "card has no links\n");
return -EINVAL;
}
@@ -224,8 +223,10 @@ static int meson_card_parse_of_optional(struct snd_soc_card *card,
int (*func)(struct snd_soc_card *c,
const char *p))
{
+ struct device *dev = card->dev;
+
/* If property is not provided, don't fail ... */
- if (!of_property_present(card->dev->of_node, propname))
+ if (!of_property_present(dev->of_node, propname))
return 0;
/* ... but do fail if it is provided and the parsing fails */
diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c
index da1a93946d67..68b5323ca9c8 100644
--- a/sound/soc/meson/t9015.c
+++ b/sound/soc/meson/t9015.c
@@ -78,8 +78,14 @@ static int t9015_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
+static const u64 t9015_dai_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
static const struct snd_soc_dai_ops t9015_dai_ops = {
.set_fmt = t9015_dai_set_fmt,
+ .auto_selectable_formats = &t9015_dai_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver t9015_dai = {
@@ -265,10 +271,8 @@ static int t9015_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(priv->avdd), "failed to AVDD\n");
ret = device_reset(dev);
- if (ret) {
- dev_err(dev, "reset failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to reset device\n");
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs)) {
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index edc4611691f7..f8782e5cfaae 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -91,7 +91,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
ret = of_property_read_string(np, "link-name", &link->name);
if (ret) {
- dev_err(card->dev, "error getting codec dai_link name\n");
+ dev_err(dev, "error getting codec dai_link name\n");
return ret;
}
@@ -109,7 +109,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
ret = snd_soc_of_get_dlc(cpu, &args, link->cpus, 0);
if (ret) {
- dev_err_probe(card->dev, ret,
+ dev_err_probe(dev, ret,
"%s: error getting cpu dai name\n", link->name);
return ret;
}
@@ -126,7 +126,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
"sound-dai",
0);
if (!link->platforms->of_node) {
- dev_err(card->dev, "%s: platform dai not found\n", link->name);
+ dev_err(dev, "%s: platform dai not found\n", link->name);
return -EINVAL;
}
} else {
@@ -136,7 +136,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
if (codec) {
ret = snd_soc_of_get_dai_link_codecs(dev, codec, link);
if (ret < 0) {
- dev_err_probe(card->dev, ret,
+ dev_err_probe(dev, ret,
"%s: codec dai not found\n", link->name);
return ret;
}
@@ -215,6 +215,7 @@ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
}
switch (cpu_dai->id) {
+ case LPI_MI2S_RX_0:
case TX_CODEC_DMA_TX_0:
case TX_CODEC_DMA_TX_1:
case TX_CODEC_DMA_TX_2:
diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h
index ee6662885593..48b114eb46a5 100644
--- a/sound/soc/qcom/common.h
+++ b/sound/soc/qcom/common.h
@@ -7,7 +7,7 @@
#include <dt-bindings/sound/qcom,q6afe.h>
#include <sound/soc.h>
-#define LPASS_MAX_PORT (SENARY_MI2S_TX + 1)
+#define LPASS_MAX_PORT (LPI_MI2S_TX_6 + 1)
int qcom_snd_parse_of(struct snd_soc_card *card);
int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c
index e6e9eb2e85aa..0cc840aca69d 100644
--- a/sound/soc/qcom/qdsp6/audioreach.c
+++ b/sound/soc/qcom/qdsp6/audioreach.c
@@ -703,6 +703,7 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph,
int pm_sz = APM_HW_EP_PMODE_CFG_PSIZE;
int size = ic_sz + ep_sz + fs_sz + pm_sz;
void *p;
+ int i;
struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0);
if (IS_ERR(pkt))
@@ -741,7 +742,12 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph,
intf_cfg->cfg.lpaif_type = module->hw_interface_type;
intf_cfg->cfg.intf_index = module->hw_interface_idx;
- intf_cfg->cfg.active_channels_mask = (1 << cfg->num_channels) - 1;
+ intf_cfg->cfg.active_channels_mask = 0;
+ /* Convert the physical channel mapping into a bit field */
+ for (i = 0; i < AR_PCM_MAX_NUM_CHANNEL; i++)
+ if (cfg->channel_map[i])
+ intf_cfg->cfg.active_channels_mask |= BIT(i);
+
p += ic_sz;
pm_cfg = p;
@@ -840,7 +846,7 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph,
uint32_t num_channels = cfg->num_channels;
int payload_size = APM_MFC_CFG_PSIZE(media_format, num_channels) +
APM_MODULE_PARAM_DATA_SIZE;
- int i;
+ int i, j;
void *p;
struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
@@ -860,8 +866,12 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph,
media_format->sample_rate = cfg->sample_rate;
media_format->bit_width = cfg->bit_width;
media_format->num_channels = cfg->num_channels;
- for (i = 0; i < num_channels; i++)
- media_format->channel_mapping[i] = cfg->channel_map[i];
+ /* Convert the physical mapping to a logical mapping of the channels */
+ for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < cfg->num_channels; i++) {
+ if (!cfg->channel_map[i])
+ continue;
+ media_format->channel_mapping[j++] = cfg->channel_map[i];
+ }
return q6apm_send_cmd_sync(graph->apm, pkt, 0);
}
@@ -1080,6 +1090,7 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph,
struct apm_pcm_module_media_fmt_cmd *cfg;
struct apm_module_param_data *param_data;
int payload_size;
+ int i, j;
if (num_channels > 4) {
dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels);
@@ -1113,7 +1124,12 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph,
media_cfg->num_channels = mcfg->num_channels;
media_cfg->q_factor = mcfg->bit_width - 1;
media_cfg->bits_per_sample = mcfg->bit_width;
- memcpy(media_cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels);
+ /* Convert the physical mapping to a logical mapping of the channels */
+ for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < mcfg->num_channels; i++) {
+ if (!mcfg->channel_map[i])
+ continue;
+ media_cfg->channel_mapping[j++] = mcfg->channel_map[i];
+ }
return q6apm_send_cmd_sync(graph->apm, pkt, 0);
}
@@ -1163,6 +1179,7 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph,
struct payload_media_fmt_pcm *cfg;
struct media_format *header;
int rc, payload_size;
+ int i, j;
void *p;
if (num_channels > 4) {
@@ -1202,7 +1219,12 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph,
cfg->q_factor = mcfg->bit_width - 1;
cfg->endianness = PCM_LITTLE_ENDIAN;
cfg->num_channels = mcfg->num_channels;
- memcpy(cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels);
+ /* Convert the physical mapping to a logical mapping of the channels */
+ for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < cfg->num_channels; i++) {
+ if (!mcfg->channel_map[i])
+ continue;
+ cfg->channel_mapping[j++] = mcfg->channel_map[i];
+ }
} else {
rc = audioreach_set_compr_media_format(header, p, mcfg);
if (rc)
@@ -1279,7 +1301,7 @@ static int audioreach_speaker_protection_vi(struct q6apm_graph *graph,
struct apm_module_sp_vi_ex_mode_cfg *ex_cfg;
int op_sz, cm_sz, ex_sz;
struct apm_module_param_data *param_data;
- int rc, i, payload_size;
+ int rc, i, payload_size, j;
struct gpr_pkt *pkt;
void *p;
@@ -1320,14 +1342,19 @@ static int audioreach_speaker_protection_vi(struct q6apm_graph *graph,
param_data->param_size = cm_sz - APM_MODULE_PARAM_DATA_SIZE;
cm_cfg->cfg.num_channels = num_channels * 2;
- for (i = 0; i < num_channels; i++) {
+ /* Convert the physical mapping to a logical mapping of the channels */
+ for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < num_channels; i++) {
+ if (!mcfg->channel_map[i])
+ continue;
/*
* Map speakers into Vsense and then Isense of each channel.
* E.g. for PCM_CHANNEL_FL and PCM_CHANNEL_FR to:
* [1, 2, 3, 4]
*/
- cm_cfg->cfg.channel_mapping[2 * i] = (mcfg->channel_map[i] - 1) * 2 + 1;
- cm_cfg->cfg.channel_mapping[2 * i + 1] = (mcfg->channel_map[i] - 1) * 2 + 2;
+ cm_cfg->cfg.channel_mapping[2 * j] = (mcfg->channel_map[i] - 1) * 2 + 1;
+ cm_cfg->cfg.channel_mapping[2 * j + 1] = (mcfg->channel_map[i] - 1) * 2 + 2;
+
+ ++j;
}
p += cm_sz;
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c
index a0d21034a626..920345609d2c 100644
--- a/sound/soc/qcom/qdsp6/q6afe-dai.c
+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c
@@ -412,6 +412,8 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
case SENARY_MI2S_RX ... SENARY_MI2S_TX:
case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
+ case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4:
+ case LPI_MI2S_RX_5 ... LPI_MI2S_TX_6:
rc = q6afe_i2s_port_prepare(dai_data->port[dai->id],
&dai_data->port_config[dai->id].i2s_cfg);
if (rc < 0) {
@@ -665,6 +667,21 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
/* USB playback AFE port receives data for playback, hence use the RX port */
{"USB Playback", NULL, "USB_RX"},
+
+ {"LPI RX0 MI2S Playback", NULL, "LPI_MI2S_RX_0"},
+ {"LPI_MI2S_TX_0", NULL, "LPI TX0 MI2S Capture"},
+ {"LPI RX1 MI2S Playback", NULL, "LPI_MI2S_RX_1"},
+ {"LPI_MI2S_TX_1", NULL, "LPI TX1 MI2S Capture"},
+ {"LPI RX2 MI2S Playback", NULL, "LPI_MI2S_RX_2"},
+ {"LPI_MI2S_TX_2", NULL, "LPI TX2 MI2S Capture"},
+ {"LPI RX3 MI2S Playback", NULL, "LPI_MI2S_RX_3"},
+ {"LPI_MI2S_TX_3", NULL, "LPI TX3 MI2S Capture"},
+ {"LPI RX4 MI2S Playback", NULL, "LPI_MI2S_RX_4"},
+ {"LPI_MI2S_TX_4", NULL, "LPI TX4 MI2S Capture"},
+ {"LPI RX5 MI2S Playback", NULL, "LPI_MI2S_RX_5"},
+ {"LPI_MI2S_TX_5", NULL, "LPI TX5 MI2S Capture"},
+ {"LPI RX6 MI2S Playback", NULL, "LPI_MI2S_RX_6"},
+ {"LPI_MI2S_TX_6", NULL, "LPI TX6 MI2S Capture"},
};
static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
@@ -1011,6 +1028,35 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("USB_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_0", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_0", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_1", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_1", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_2", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_2", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_3", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_3", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_4", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_4", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_5", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_5", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_6", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_6", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
};
static const struct snd_soc_component_driver q6afe_dai_component = {
@@ -1045,6 +1091,8 @@ static void of_q6afe_parse_dai_data(struct device *dev,
case SENARY_MI2S_RX ... SENARY_MI2S_TX:
case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
+ case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4:
+ case LPI_MI2S_RX_5 ... LPI_MI2S_TX_6:
priv = &data->priv[id];
ret = of_property_read_variable_u32_array(node,
"qcom,sd-lines",
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
index 40237267fda0..1d68a80e8e0c 100644
--- a/sound/soc/qcom/qdsp6/q6afe.c
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -132,6 +132,20 @@
#define AFE_PORT_ID_QUINARY_MI2S_TX 0x1017
#define AFE_PORT_ID_SENARY_MI2S_RX 0x1018
#define AFE_PORT_ID_SENARY_MI2S_TX 0x1019
+#define AFE_PORT_ID_INT0_MI2S_RX 0x102e
+#define AFE_PORT_ID_INT0_MI2S_TX 0x102f
+#define AFE_PORT_ID_INT1_MI2S_RX 0x1030
+#define AFE_PORT_ID_INT1_MI2S_TX 0x1031
+#define AFE_PORT_ID_INT2_MI2S_RX 0x1032
+#define AFE_PORT_ID_INT2_MI2S_TX 0x1033
+#define AFE_PORT_ID_INT3_MI2S_RX 0x1034
+#define AFE_PORT_ID_INT3_MI2S_TX 0x1035
+#define AFE_PORT_ID_INT4_MI2S_RX 0x1036
+#define AFE_PORT_ID_INT4_MI2S_TX 0x1037
+#define AFE_PORT_ID_INT5_MI2S_RX 0x1038
+#define AFE_PORT_ID_INT5_MI2S_TX 0x1039
+#define AFE_PORT_ID_INT6_MI2S_RX 0x103a
+#define AFE_PORT_ID_INT6_MI2S_TX 0x103b
/* Start of the range of port IDs for TDM devices. */
#define AFE_PORT_ID_TDM_PORT_RANGE_START 0x9000
@@ -931,6 +945,34 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = {
[RX_CODEC_DMA_RX_7] = { AFE_PORT_ID_RX_CODEC_DMA_RX_7,
RX_CODEC_DMA_RX_7, 1, 1},
[USB_RX] = { AFE_PORT_ID_USB_RX, USB_RX, 1, 1},
+ [LPI_MI2S_RX_0] = { AFE_PORT_ID_INT0_MI2S_RX,
+ LPI_MI2S_RX_0, 1, 1},
+ [LPI_MI2S_TX_0] = { AFE_PORT_ID_INT0_MI2S_TX,
+ LPI_MI2S_TX_0, 0, 1},
+ [LPI_MI2S_RX_1] = { AFE_PORT_ID_INT1_MI2S_RX,
+ LPI_MI2S_RX_1, 1, 1},
+ [LPI_MI2S_TX_1] = { AFE_PORT_ID_INT1_MI2S_TX,
+ LPI_MI2S_TX_1, 0, 1},
+ [LPI_MI2S_RX_2] = { AFE_PORT_ID_INT2_MI2S_RX,
+ LPI_MI2S_RX_2, 1, 1},
+ [LPI_MI2S_TX_2] = { AFE_PORT_ID_INT2_MI2S_TX,
+ LPI_MI2S_TX_2, 0, 1},
+ [LPI_MI2S_RX_3] = { AFE_PORT_ID_INT3_MI2S_RX,
+ LPI_MI2S_RX_3, 1, 1},
+ [LPI_MI2S_TX_3] = { AFE_PORT_ID_INT3_MI2S_TX,
+ LPI_MI2S_TX_3, 0, 1},
+ [LPI_MI2S_RX_4] = { AFE_PORT_ID_INT4_MI2S_RX,
+ LPI_MI2S_RX_4, 1, 1},
+ [LPI_MI2S_TX_4] = { AFE_PORT_ID_INT4_MI2S_TX,
+ LPI_MI2S_TX_4, 0, 1},
+ [LPI_MI2S_RX_5] = { AFE_PORT_ID_INT5_MI2S_RX,
+ LPI_MI2S_RX_5, 1, 1},
+ [LPI_MI2S_TX_5] = { AFE_PORT_ID_INT5_MI2S_TX,
+ LPI_MI2S_TX_5, 0, 1},
+ [LPI_MI2S_RX_6] = { AFE_PORT_ID_INT6_MI2S_RX,
+ LPI_MI2S_RX_6, 1, 1},
+ [LPI_MI2S_TX_6] = { AFE_PORT_ID_INT6_MI2S_TX,
+ LPI_MI2S_TX_6, 0, 1},
};
static void q6afe_port_free(struct kref *ref)
@@ -1785,6 +1827,20 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
case AFE_PORT_ID_QUINARY_MI2S_TX:
case AFE_PORT_ID_SENARY_MI2S_RX:
case AFE_PORT_ID_SENARY_MI2S_TX:
+ case AFE_PORT_ID_INT0_MI2S_RX:
+ case AFE_PORT_ID_INT0_MI2S_TX:
+ case AFE_PORT_ID_INT1_MI2S_RX:
+ case AFE_PORT_ID_INT1_MI2S_TX:
+ case AFE_PORT_ID_INT2_MI2S_RX:
+ case AFE_PORT_ID_INT2_MI2S_TX:
+ case AFE_PORT_ID_INT3_MI2S_RX:
+ case AFE_PORT_ID_INT3_MI2S_TX:
+ case AFE_PORT_ID_INT4_MI2S_RX:
+ case AFE_PORT_ID_INT4_MI2S_TX:
+ case AFE_PORT_ID_INT5_MI2S_RX:
+ case AFE_PORT_ID_INT5_MI2S_TX:
+ case AFE_PORT_ID_INT6_MI2S_RX:
+ case AFE_PORT_ID_INT6_MI2S_TX:
cfg_type = AFE_PARAM_ID_I2S_CONFIG;
break;
case AFE_PORT_ID_PRIMARY_TDM_RX ... AFE_PORT_ID_QUINARY_TDM_TX_7:
diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
index 006b283484d9..e68e8b000e07 100644
--- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
+++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
@@ -2,10 +2,12 @@
// Copyright (c) 2021, Linaro Limited
#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/pcm.h>
@@ -15,15 +17,54 @@
#include "q6dsp-common.h"
#include "audioreach.h"
#include "q6apm.h"
+#include "q6prm.h"
#define AUDIOREACH_BE_PCM_BASE 16
+struct q6apm_dai_priv_data {
+ struct clk *mclk;
+ struct clk *bclk;
+ bool mclk_enabled, bclk_enabled;
+};
+
struct q6apm_lpass_dai_data {
struct q6apm_graph *graph[APM_PORT_MAX];
bool is_port_started[APM_PORT_MAX];
struct audioreach_module_config module_config[APM_PORT_MAX];
+ struct q6apm_dai_priv_data priv[APM_PORT_MAX];
};
+static void q6apm_lpass_dai_disable_clocks(struct q6apm_lpass_dai_data *dai_data, int id)
+{
+ if (dai_data->priv[id].mclk_enabled) {
+ clk_disable_unprepare(dai_data->priv[id].mclk);
+ dai_data->priv[id].mclk_enabled = false;
+ }
+
+ if (dai_data->priv[id].bclk_enabled) {
+ clk_disable_unprepare(dai_data->priv[id].bclk);
+ dai_data->priv[id].bclk_enabled = false;
+ }
+}
+
+static void q6apm_lpass_dai_put_clocks(struct q6apm_lpass_dai_data *dai_data)
+{
+ int i;
+
+ for (i = 0; i < APM_PORT_MAX; i++) {
+ q6apm_lpass_dai_disable_clocks(dai_data, i);
+
+ if (dai_data->priv[i].mclk) {
+ clk_put(dai_data->priv[i].mclk);
+ dai_data->priv[i].mclk = NULL;
+ }
+ if (dai_data->priv[i].bclk) {
+ clk_put(dai_data->priv[i].bclk);
+ dai_data->priv[i].bclk = NULL;
+ }
+ }
+}
+
static int q6dma_set_channel_map(struct snd_soc_dai *dai,
unsigned int tx_num,
const unsigned int *tx_ch_mask,
@@ -251,6 +292,62 @@ static int q6apm_lpass_dai_startup(struct snd_pcm_substream *substream, struct s
return 0;
}
+static int q6i2s_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ return q6apm_lpass_dai_startup(substream, dai);
+}
+
+static void q6i2s_lpass_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ q6apm_lpass_dai_shutdown(substream, dai);
+ q6apm_lpass_dai_disable_clocks(dai_data, dai->id);
+}
+
+static int q6i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir)
+{
+ struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ struct clk *sysclk = NULL;
+ bool *enabled = NULL;
+ int ret = 0;
+
+ switch (clk_id) {
+ case LPAIF_MI2S_MCLK:
+ sysclk = dai_data->priv[dai->id].mclk;
+ enabled = &dai_data->priv[dai->id].mclk_enabled;
+ break;
+ case LPAIF_MI2S_BCLK:
+ sysclk = dai_data->priv[dai->id].bclk;
+ enabled = &dai_data->priv[dai->id].bclk_enabled;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (sysclk) {
+ ret = clk_set_rate(sysclk, freq);
+ if (ret) {
+ dev_err(dai->dev, "Error, Unable to set rate (%d) for sysclk %d\n",
+ freq, clk_id);
+ return ret;
+ }
+
+ if (*enabled)
+ return 0;
+
+ ret = clk_prepare_enable(sysclk);
+ if (ret) {
+ dev_err(dai->dev, "Error, Unable to prepare (%d) sysclk\n", clk_id);
+ return ret;
+ }
+
+ *enabled = true;
+ }
+
+ return ret;
+}
+
static int q6i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
@@ -272,11 +369,12 @@ static const struct snd_soc_dai_ops q6dma_ops = {
static const struct snd_soc_dai_ops q6i2s_ops = {
.prepare = q6apm_lpass_dai_prepare,
- .startup = q6apm_lpass_dai_startup,
- .shutdown = q6apm_lpass_dai_shutdown,
+ .startup = q6i2s_dai_startup,
+ .shutdown = q6i2s_lpass_dai_shutdown,
.set_channel_map = q6dma_set_channel_map,
.hw_params = q6dma_hw_params,
.set_fmt = q6i2s_set_fmt,
+ .set_sysclk = q6i2s_set_sysclk,
.trigger = q6apm_lpass_dai_trigger,
};
@@ -297,6 +395,64 @@ static const struct snd_soc_component_driver q6apm_lpass_dai_component = {
.remove_order = SND_SOC_COMP_ORDER_FIRST,
};
+static int of_q6apm_parse_dai_data(struct device *dev,
+ struct q6apm_lpass_dai_data *data)
+{
+ int ret;
+
+ for_each_child_of_node_scoped(dev->of_node, node) {
+ struct q6apm_dai_priv_data *priv;
+ int id;
+
+ ret = of_property_read_u32(node, "reg", &id);
+ if (ret || id < 0 || id >= APM_PORT_MAX) {
+ dev_err(dev, "valid dai id not found:%d\n", ret);
+ continue;
+ }
+
+ switch (id) {
+ /* MI2S specific properties */
+ case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
+ case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
+ case SENARY_MI2S_RX ... SENARY_MI2S_TX:
+ priv = &data->priv[id];
+ priv->mclk = of_clk_get_by_name(node, "mclk");
+ if (IS_ERR(priv->mclk)) {
+ int err = PTR_ERR(priv->mclk);
+
+ priv->mclk = NULL;
+ if (err == -EPROBE_DEFER) {
+ q6apm_lpass_dai_put_clocks(data);
+ return dev_err_probe(dev, err,
+ "unable to get mi2s mclk\n");
+ }
+ }
+
+ priv->bclk = of_clk_get_by_name(node, "bclk");
+ if (IS_ERR(priv->bclk)) {
+ int err = PTR_ERR(priv->bclk);
+
+ priv->bclk = NULL;
+ if (err == -EPROBE_DEFER) {
+ q6apm_lpass_dai_put_clocks(data);
+ return dev_err_probe(dev, err,
+ "unable to get mi2s bclk\n");
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void q6apm_lpass_dai_clocks_action(void *data)
+{
+ q6apm_lpass_dai_put_clocks(data);
+}
+
static int q6apm_lpass_dai_dev_probe(struct platform_device *pdev)
{
struct q6dsp_audio_port_dai_driver_config cfg;
@@ -304,12 +460,20 @@ static int q6apm_lpass_dai_dev_probe(struct platform_device *pdev)
struct snd_soc_dai_driver *dais;
struct device *dev = &pdev->dev;
int num_dais;
+ int ret;
dai_data = devm_kzalloc(dev, sizeof(*dai_data), GFP_KERNEL);
if (!dai_data)
return -ENOMEM;
dev_set_drvdata(dev, dai_data);
+ ret = of_q6apm_parse_dai_data(dev, dai_data);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, q6apm_lpass_dai_clocks_action, dai_data);
+ if (ret)
+ return ret;
memset(&cfg, 0, sizeof(cfg));
cfg.q6i2s_ops = &q6i2s_ops;
diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c
index 03838582aead..ab7d20580638 100644
--- a/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c
+++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c
@@ -12,7 +12,7 @@
#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
#include "q6dsp-lpass-clocks.h"
-#define Q6DSP_MAX_CLK_ID 104
+#define Q6DSP_MAX_CLK_ID 105
#define Q6DSP_LPASS_CLK_ROOT_DEFAULT 0
diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
index e5cd82f77b55..c3d8116ad503 100644
--- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
+++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
@@ -553,11 +553,15 @@ static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = {
Q6AFE_MI2S_RX_DAI("LPI RX2", LPI_MI2S_RX_2),
Q6AFE_MI2S_RX_DAI("LPI RX3", LPI_MI2S_RX_3),
Q6AFE_MI2S_RX_DAI("LPI RX4", LPI_MI2S_RX_4),
+ Q6AFE_MI2S_RX_DAI("LPI RX5", LPI_MI2S_RX_5),
+ Q6AFE_MI2S_RX_DAI("LPI RX6", LPI_MI2S_RX_6),
Q6AFE_MI2S_TX_DAI("LPI TX0", LPI_MI2S_TX_0),
Q6AFE_MI2S_TX_DAI("LPI TX1", LPI_MI2S_TX_1),
Q6AFE_MI2S_TX_DAI("LPI TX2", LPI_MI2S_TX_2),
Q6AFE_MI2S_TX_DAI("LPI TX3", LPI_MI2S_TX_3),
Q6AFE_MI2S_TX_DAI("LPI TX4", LPI_MI2S_TX_4),
+ Q6AFE_MI2S_TX_DAI("LPI TX5", LPI_MI2S_TX_5),
+ Q6AFE_MI2S_TX_DAI("LPI TX6", LPI_MI2S_TX_6),
Q6AFE_TDM_PB_DAI("Primary", 0, PRIMARY_TDM_RX_0),
Q6AFE_TDM_PB_DAI("Primary", 1, PRIMARY_TDM_RX_1),
Q6AFE_TDM_PB_DAI("Primary", 2, PRIMARY_TDM_RX_2),
@@ -712,6 +716,7 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev,
case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4:
+ case LPI_MI2S_RX_5 ... LPI_MI2S_TX_6:
q6dsp_audio_fe_dais[i].ops = cfg->q6i2s_ops;
break;
case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
diff --git a/sound/soc/qcom/qdsp6/q6prm-clocks.c b/sound/soc/qcom/qdsp6/q6prm-clocks.c
index 4c574b48ab00..02dad9ee9804 100644
--- a/sound/soc/qcom/qdsp6/q6prm-clocks.c
+++ b/sound/soc/qcom/qdsp6/q6prm-clocks.c
@@ -42,6 +42,11 @@ static const struct q6dsp_clk_init q6prm_clks[] = {
Q6PRM_CLK(LPASS_CLK_ID_INT5_MI2S_IBIT),
Q6PRM_CLK(LPASS_CLK_ID_INT6_MI2S_IBIT),
Q6PRM_CLK(LPASS_CLK_ID_QUI_MI2S_OSR),
+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_1),
+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_2),
+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_3),
+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_4),
+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_5),
Q6PRM_CLK(LPASS_CLK_ID_WSA_CORE_MCLK),
Q6PRM_CLK(LPASS_CLK_ID_WSA_CORE_NPL_MCLK),
Q6PRM_CLK(LPASS_CLK_ID_VA_CORE_MCLK),
@@ -63,6 +68,8 @@ static const struct q6dsp_clk_init q6prm_clks[] = {
"LPASS_HW_MACRO"),
Q6DSP_VOTE_CLK(LPASS_HW_DCODEC_VOTE, Q6PRM_HW_CORE_ID_DCODEC,
"LPASS_HW_DCODEC"),
+ Q6DSP_VOTE_CLK(LPASS_HW_LPR_VOTE, Q6PRM_HW_LPR_VOTE,
+ "LPASS_HW_LPR_VOTE"),
};
static const struct q6dsp_clk_desc q6dsp_clk_q6prm __maybe_unused = {
diff --git a/sound/soc/qcom/qdsp6/q6prm.c b/sound/soc/qcom/qdsp6/q6prm.c
index 04892fb4423f..1f3ce4cc0837 100644
--- a/sound/soc/qcom/qdsp6/q6prm.c
+++ b/sound/soc/qcom/qdsp6/q6prm.c
@@ -31,10 +31,16 @@ struct q6prm {
#define PARAM_ID_RSC_HW_CORE 0x08001032
#define PARAM_ID_RSC_LPASS_CORE 0x0800102B
#define PARAM_ID_RSC_AUDIO_HW_CLK 0x0800102C
+#define PARAM_ID_RSC_CPU_LPR 0x08001A6E
+
+#define LPR_CPU_SS_SLEEP_DISABLE 0x1
struct prm_cmd_request_hw_core {
struct apm_module_param_data param_data;
- uint32_t hw_clk_id;
+ union {
+ u32 hw_clk_id;
+ u32 lpr_state;
+ };
} __packed;
struct prm_cmd_request_rsc {
@@ -62,6 +68,7 @@ static int q6prm_set_hw_core_req(struct device *dev, uint32_t hw_block_id, bool
struct prm_cmd_request_hw_core *req;
gpr_device_t *gdev = prm->gdev;
uint32_t opcode, rsp_opcode;
+ bool lpr_req = (hw_block_id == Q6PRM_HW_LPR_VOTE);
if (enable) {
opcode = PRM_CMD_REQUEST_HW_RSC;
@@ -82,10 +89,13 @@ static int q6prm_set_hw_core_req(struct device *dev, uint32_t hw_block_id, bool
param_data->module_instance_id = GPR_PRM_MODULE_IID;
param_data->error_code = 0;
- param_data->param_id = PARAM_ID_RSC_HW_CORE;
+ param_data->param_id = lpr_req ? PARAM_ID_RSC_CPU_LPR : PARAM_ID_RSC_HW_CORE;
param_data->param_size = sizeof(*req) - APM_MODULE_PARAM_DATA_SIZE;
- req->hw_clk_id = hw_block_id;
+ if (lpr_req)
+ req->lpr_state = LPR_CPU_SS_SLEEP_DISABLE;
+ else
+ req->hw_clk_id = hw_block_id;
return q6prm_send_cmd_sync(prm, pkt, rsp_opcode);
}
diff --git a/sound/soc/qcom/qdsp6/q6prm.h b/sound/soc/qcom/qdsp6/q6prm.h
index a988a32086fe..938b1bfce287 100644
--- a/sound/soc/qcom/qdsp6/q6prm.h
+++ b/sound/soc/qcom/qdsp6/q6prm.h
@@ -3,6 +3,9 @@
#ifndef __Q6PRM_H__
#define __Q6PRM_H__
+#define LPAIF_MI2S_MCLK 1
+#define LPAIF_MI2S_BCLK 2
+
/* Clock ID for Primary I2S IBIT */
#define Q6PRM_LPASS_CLK_ID_PRI_MI2S_IBIT 0x100
/* Clock ID for Primary I2S EBIT */
@@ -52,6 +55,17 @@
/* Clock ID for QUINARY MI2S OSR CLK */
#define Q6PRM_LPASS_CLK_ID_QUI_MI2S_OSR 0x116
+/* Clock ID for MCLK1 */
+#define Q6PRM_LPASS_CLK_ID_MCLK_1 0x300
+/* Clock ID for MCLK2 */
+#define Q6PRM_LPASS_CLK_ID_MCLK_2 0x301
+/* Clock ID for MCLK3 */
+#define Q6PRM_LPASS_CLK_ID_MCLK_3 0x302
+/* Clock ID for MCLK4 */
+#define Q6PRM_LPASS_CLK_ID_MCLK_4 0x303
+/* Clock ID for MCLK5 */
+#define Q6PRM_LPASS_CLK_ID_MCLK_5 0x304
+
#define Q6PRM_LPASS_CLK_ID_WSA_CORE_MCLK 0x305
#define Q6PRM_LPASS_CLK_ID_WSA_CORE_NPL_MCLK 0x306
@@ -87,6 +101,7 @@
#define Q6PRM_LPASS_CLK_ROOT_DEFAULT 0
#define Q6PRM_HW_CORE_ID_LPASS 1
#define Q6PRM_HW_CORE_ID_DCODEC 2
+#define Q6PRM_HW_LPR_VOTE 3
int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr,
int clk_root, unsigned int freq);
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
index 7386226046fa..d076c99f197f 100644
--- a/sound/soc/qcom/qdsp6/q6routing.c
+++ b/sound/soc/qcom/qdsp6/q6routing.c
@@ -127,7 +127,14 @@
{ mix_name, "TX_CODEC_DMA_TX_2", "TX_CODEC_DMA_TX_2"}, \
{ mix_name, "TX_CODEC_DMA_TX_3", "TX_CODEC_DMA_TX_3"}, \
{ mix_name, "TX_CODEC_DMA_TX_4", "TX_CODEC_DMA_TX_4"}, \
- { mix_name, "TX_CODEC_DMA_TX_5", "TX_CODEC_DMA_TX_5"}
+ { mix_name, "TX_CODEC_DMA_TX_5", "TX_CODEC_DMA_TX_5"}, \
+ { mix_name, "LPI_MI2S_TX_0", "LPI_MI2S_TX_0" }, \
+ { mix_name, "LPI_MI2S_TX_1", "LPI_MI2S_TX_1" }, \
+ { mix_name, "LPI_MI2S_TX_2", "LPI_MI2S_TX_2" }, \
+ { mix_name, "LPI_MI2S_TX_3", "LPI_MI2S_TX_3" }, \
+ { mix_name, "LPI_MI2S_TX_4", "LPI_MI2S_TX_4" }, \
+ { mix_name, "LPI_MI2S_TX_5", "LPI_MI2S_TX_5" }, \
+ { mix_name, "LPI_MI2S_TX_6", "LPI_MI2S_TX_6" }
#define Q6ROUTING_TX_MIXERS(id) \
SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, \
@@ -321,6 +328,27 @@
msm_routing_put_audio_mixer), \
SOC_SINGLE_EXT("TX_CODEC_DMA_TX_5", TX_CODEC_DMA_TX_5, \
id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("LPI_MI2S_TX_0", LPI_MI2S_TX_0, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("LPI_MI2S_TX_1", LPI_MI2S_TX_1, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("LPI_MI2S_TX_2", LPI_MI2S_TX_2, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("LPI_MI2S_TX_3", LPI_MI2S_TX_3, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("LPI_MI2S_TX_4", LPI_MI2S_TX_4, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("LPI_MI2S_TX_5", LPI_MI2S_TX_5, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("LPI_MI2S_TX_6", LPI_MI2S_TX_6, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
msm_routing_put_audio_mixer),
struct session_data {
@@ -709,6 +737,26 @@ static const struct snd_kcontrol_new rxcodec_dma_rx_6_mixer_controls[] = {
static const struct snd_kcontrol_new rx_codec_dma_rx_7_mixer_controls[] = {
Q6ROUTING_RX_MIXERS(RX_CODEC_DMA_RX_7) };
+static const struct snd_kcontrol_new lpi_mi2s_rx_0_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_0) };
+
+static const struct snd_kcontrol_new lpi_mi2s_rx_1_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_1) };
+
+static const struct snd_kcontrol_new lpi_mi2s_rx_2_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_2) };
+
+static const struct snd_kcontrol_new lpi_mi2s_rx_3_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_3) };
+
+static const struct snd_kcontrol_new lpi_mi2s_rx_4_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_4) };
+
+static const struct snd_kcontrol_new lpi_mi2s_rx_5_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_5) };
+
+static const struct snd_kcontrol_new lpi_mi2s_rx_6_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_6) };
static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA1) };
@@ -938,6 +986,27 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_MIXER("USB_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
usb_rx_mixer_controls,
ARRAY_SIZE(usb_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ lpi_mi2s_rx_0_mixer_controls,
+ ARRAY_SIZE(lpi_mi2s_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ lpi_mi2s_rx_1_mixer_controls,
+ ARRAY_SIZE(lpi_mi2s_rx_1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ lpi_mi2s_rx_2_mixer_controls,
+ ARRAY_SIZE(lpi_mi2s_rx_2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ lpi_mi2s_rx_3_mixer_controls,
+ ARRAY_SIZE(lpi_mi2s_rx_3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ lpi_mi2s_rx_4_mixer_controls,
+ ARRAY_SIZE(lpi_mi2s_rx_4_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ lpi_mi2s_rx_5_mixer_controls,
+ ARRAY_SIZE(lpi_mi2s_rx_5_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ lpi_mi2s_rx_6_mixer_controls,
+ ARRAY_SIZE(lpi_mi2s_rx_6_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0,
mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
@@ -1031,6 +1100,13 @@ static const struct snd_soc_dapm_route intercon[] = {
Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_6 Audio Mixer", "RX_CODEC_DMA_RX_6"),
Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_7 Audio Mixer", "RX_CODEC_DMA_RX_7"),
Q6ROUTING_RX_DAPM_ROUTE("USB_RX Audio Mixer", "USB_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_0 Audio Mixer", "LPI_MI2S_RX_0"),
+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_1 Audio Mixer", "LPI_MI2S_RX_1"),
+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_2 Audio Mixer", "LPI_MI2S_RX_2"),
+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_3 Audio Mixer", "LPI_MI2S_RX_3"),
+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_4 Audio Mixer", "LPI_MI2S_RX_4"),
+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_5 Audio Mixer", "LPI_MI2S_RX_5"),
+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_6 Audio Mixer", "LPI_MI2S_RX_6"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia1 Mixer"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia2 Mixer"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia3 Mixer"),
diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c
index 98b15a527e37..c3ce3e05b260 100644
--- a/sound/soc/qcom/sc8280xp.c
+++ b/sound/soc/qcom/sc8280xp.c
@@ -12,17 +12,100 @@
#include <sound/jack.h>
#include <linux/input-event-codes.h>
#include "qdsp6/q6afe.h"
+#include "qdsp6/q6apm.h"
+#include "qdsp6/q6prm.h"
+#include "qdsp6/q6dsp-common.h"
#include "common.h"
#include "sdw.h"
+#define I2S_MCLKFS 256
+
+#define I2S_MCLK_RATE(rate) \
+ ((rate) * (I2S_MCLKFS))
+#define I2S_BIT_RATE(rate, channels, format) \
+ ((rate) * (channels) * (format))
+
+static struct snd_soc_dapm_widget sc8280xp_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("DP0 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP1 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP2 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP3 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP4 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP5 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP6 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP7 Jack", NULL),
+};
+
+static const struct snd_kcontrol_new max98090_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headset Mic12"),
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic56"),
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Receiver"),
+ SOC_DAPM_PIN_SWITCH("Int Mic"),
+};
+
+static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic12", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic56", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_SPK("Receiver", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+struct qcom_snd_soc_common {
+ const char *driver_name;
+ const struct snd_soc_dapm_widget *dapm_widgets;
+ int num_dapm_widgets;
+ const struct snd_soc_dapm_route *dapm_routes;
+ int num_dapm_routes;
+ const struct snd_kcontrol_new *controls;
+ int num_controls;
+ unsigned int codec_dai_fmt;
+ bool codec_sysclk_set;
+ bool mi2s_mclk_enable;
+ bool mi2s_bclk_enable;
+ bool wcd_jack;
+ int (*snd_prepare)(struct snd_pcm_substream *substream);
+};
+
struct sc8280xp_snd_data {
bool stream_prepared[AFE_PORT_MAX];
struct snd_soc_card *card;
struct snd_soc_jack jack;
struct snd_soc_jack dp_jack[8];
+ const struct qcom_snd_soc_common *priv;
bool jack_setup;
};
+static inline int sc8280xp_get_mclk_freq(struct snd_pcm_hw_params *params)
+{
+ int rate = params_rate(params);
+
+ switch (rate) {
+ case 11025:
+ case 44100:
+ case 88200:
+ return I2S_MCLK_RATE(44100);
+ default:
+ break;
+ }
+
+ return I2S_MCLK_RATE(rate);
+}
+
+static inline int sc8280xp_get_bclk_freq(struct snd_pcm_hw_params *params)
+{
+ return I2S_BIT_RATE(params_rate(params),
+ params_channels(params),
+ snd_pcm_format_width(params_format(params)));
+}
+
static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
{
struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
@@ -32,10 +115,6 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
int dp_pcm_id = 0;
switch (cpu_dai->id) {
- case PRIMARY_MI2S_RX...QUATERNARY_MI2S_TX:
- case QUINARY_MI2S_RX...QUINARY_MI2S_TX:
- snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP);
- break;
case WSA_CODEC_DMA_RX_0:
case WSA_CODEC_DMA_RX_1:
/*
@@ -64,7 +143,10 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
if (dp_jack)
return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id);
- return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
+ if (data->priv->wcd_jack)
+ return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
+
+ return 0;
}
static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -96,12 +178,116 @@ static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
+static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+ int mclk_freq = sc8280xp_get_mclk_freq(params);
+ int bclk_freq = sc8280xp_get_bclk_freq(params);
+ int ret;
+
+ switch (cpu_dai->id) {
+ case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
+ case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
+ case SENARY_MI2S_RX ... SENARY_MI2S_TX:
+ case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4:
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+
+ if (data->priv->codec_dai_fmt) {
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ data->priv->codec_dai_fmt);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+ }
+
+ if (data->priv->mi2s_mclk_enable) {
+ ret = snd_soc_dai_set_sysclk(cpu_dai,
+ LPAIF_MI2S_MCLK, mclk_freq,
+ SND_SOC_CLOCK_OUT);
+ if (ret)
+ return ret;
+ }
+
+ if (data->priv->mi2s_bclk_enable) {
+ ret = snd_soc_dai_set_sysclk(cpu_dai,
+ LPAIF_MI2S_BCLK, bclk_freq,
+ SND_SOC_CLOCK_OUT);
+ if (ret)
+ return ret;
+ }
+
+ if (data->priv->codec_sysclk_set) {
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ 0, mclk_freq,
+ SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * WSA and WSA2 are handled as a single interface with the
+ * following channels mask:
+ * __________________________________________________
+ * | Bits | 3 | 2 | 1 | 0 |
+ * ---------------------------------------------------
+ * | Line | WSA2 Ch2 | WSA2 Ch1 | WSA Ch2 | WSA Ch1 |
+ * ---------------------------------------------------
+ *
+ * The Ayaneo Pocket S2 speakers are connected only to
+ * the WSA2 interface and the WSA interface is not enabled.
+ *
+ * Set the channel mapping on the WSA2 channels only.
+ */
+static const unsigned int ayaneo_ps2_channels_mapping[] = {
+ 0, /* WSA Ch1 */
+ 0, /* WSA Ch2 */
+ PCM_CHANNEL_FL, /* WSA2 Ch1 */
+ PCM_CHANNEL_FR /* WSA2 Ch2 */
+};
+
+static int ayaneo_ps2_snd_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ unsigned int channels = substream->runtime->channels;
+
+ if (cpu_dai->id != WSA_CODEC_DMA_RX_0)
+ return 0;
+
+ if (channels != 2)
+ return -EINVAL;
+
+ return snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
+ ARRAY_SIZE(ayaneo_ps2_channels_mapping),
+ ayaneo_ps2_channels_mapping);
+}
+
static int sc8280xp_snd_prepare(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+ if (data->priv->snd_prepare) {
+ int ret;
+
+ ret = data->priv->snd_prepare(substream);
+ if (ret)
+ return ret;
+ }
+
return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]);
}
@@ -117,6 +303,7 @@ static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream)
static const struct snd_soc_ops sc8280xp_be_ops = {
.startup = qcom_snd_sdw_startup,
.shutdown = qcom_snd_sdw_shutdown,
+ .hw_params = sc8280xp_snd_hw_params,
.hw_free = sc8280xp_snd_hw_free,
.prepare = sc8280xp_snd_prepare,
};
@@ -145,38 +332,180 @@ static int sc8280xp_platform_probe(struct platform_device *pdev)
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
if (!card)
return -ENOMEM;
- card->owner = THIS_MODULE;
+
/* Allocate the private data */
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
+ data->priv = of_device_get_match_data(dev);
+ if (!data->priv)
+ return -ENODEV;
+
+ card->owner = THIS_MODULE;
card->dev = dev;
dev_set_drvdata(dev, card);
snd_soc_card_set_drvdata(card, data);
+ card->dapm_widgets = data->priv->dapm_widgets;
+ card->num_dapm_widgets = data->priv->num_dapm_widgets;
+ card->dapm_routes = data->priv->dapm_routes;
+ card->num_dapm_routes = data->priv->num_dapm_routes;
+ card->controls = data->priv->controls;
+ card->num_controls = data->priv->num_controls;
+
ret = qcom_snd_parse_of(card);
if (ret)
return ret;
- card->driver_name = of_device_get_match_data(dev);
+ card->driver_name = data->priv->driver_name;
sc8280xp_add_be_ops(card);
return devm_snd_soc_register_card(dev, card);
}
+static struct qcom_snd_soc_common ayaneo_ps2_priv_data = {
+ .driver_name = "ayaneo-ps2",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .snd_prepare = ayaneo_ps2_snd_prepare,
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common eliza_priv_data = {
+ .driver_name = "eliza",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common hawi_priv_data = {
+ .driver_name = "hawi",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .codec_sysclk_set = true,
+ .mi2s_bclk_enable = true,
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common kaanapali_priv_data = {
+ .driver_name = "kaanapali",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common qcs9100_priv_data = {
+ .driver_name = "sa8775p",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+};
+
+static const struct qcom_snd_soc_common qcs615_priv_data = {
+ .driver_name = "qcs615",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+};
+
+static const struct qcom_snd_soc_common qcm6490_priv_data = {
+ .driver_name = "qcm6490",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common qcs6490_priv_data = {
+ .driver_name = "qcs6490",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common qcs8275_priv_data = {
+ .driver_name = "qcs8300",
+ .dapm_widgets = max98090_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(max98090_dapm_widgets),
+ .controls = max98090_controls,
+ .num_controls = ARRAY_SIZE(max98090_controls),
+ .codec_sysclk_set = true,
+ .codec_dai_fmt = SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BC_FC,
+};
+
+static const struct qcom_snd_soc_common sc8280xp_priv_data = {
+ .driver_name = "sc8280xp",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common sm8450_priv_data = {
+ .driver_name = "sm8450",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+ /* I2S Connected to HDMI */
+ .mi2s_mclk_enable = true,
+ .mi2s_bclk_enable = true,
+ .codec_dai_fmt = SND_SOC_DAIFMT_BC_FC |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_I2S,
+};
+
+static const struct qcom_snd_soc_common sm8475_priv_data = {
+ .driver_name = "sm8475",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common sm8550_priv_data = {
+ .driver_name = "sm8550",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+ /* I2S Connected to HDMI */
+ .mi2s_mclk_enable = true,
+ .mi2s_bclk_enable = true,
+ .codec_dai_fmt = SND_SOC_DAIFMT_BC_FC |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_I2S,
+};
+
+static const struct qcom_snd_soc_common sm8650_priv_data = {
+ .driver_name = "sm8650",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+ /* I2S Connected to HDMI */
+ .mi2s_mclk_enable = true,
+ .mi2s_bclk_enable = true,
+ .codec_dai_fmt = SND_SOC_DAIFMT_BC_FC |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_I2S,
+};
+
+static const struct qcom_snd_soc_common sm8750_priv_data = {
+ .driver_name = "sm8750",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+};
+
static const struct of_device_id snd_sc8280xp_dt_match[] = {
- {.compatible = "qcom,eliza-sndcard", "eliza"},
- {.compatible = "qcom,kaanapali-sndcard", "kaanapali"},
- {.compatible = "qcom,qcm6490-idp-sndcard", "qcm6490"},
- {.compatible = "qcom,qcs615-sndcard", "qcs615"},
- {.compatible = "qcom,qcs6490-rb3gen2-sndcard", "qcs6490"},
- {.compatible = "qcom,qcs8275-sndcard", "qcs8300"},
- {.compatible = "qcom,qcs9075-sndcard", "sa8775p"},
- {.compatible = "qcom,qcs9100-sndcard", "sa8775p"},
- {.compatible = "qcom,sc8280xp-sndcard", "sc8280xp"},
- {.compatible = "qcom,sm8450-sndcard", "sm8450"},
- {.compatible = "qcom,sm8550-sndcard", "sm8550"},
- {.compatible = "qcom,sm8650-sndcard", "sm8650"},
- {.compatible = "qcom,sm8750-sndcard", "sm8750"},
+ { .compatible = "ayaneo,pocket-s2-sndcard", .data = &ayaneo_ps2_priv_data },
+ { .compatible = "qcom,eliza-sndcard", .data = &eliza_priv_data },
+ { .compatible = "qcom,hawi-sndcard", .data = &hawi_priv_data },
+ { .compatible = "qcom,kaanapali-sndcard", .data = &kaanapali_priv_data },
+ { .compatible = "qcom,qcm6490-idp-sndcard", .data = &qcm6490_priv_data },
+ { .compatible = "qcom,qcs615-sndcard", .data = &qcs615_priv_data },
+ { .compatible = "qcom,qcs6490-rb3gen2-sndcard", .data = &qcs6490_priv_data },
+ { .compatible = "qcom,qcs8275-sndcard", .data = &qcs8275_priv_data },
+ { .compatible = "qcom,qcs9075-sndcard", .data = &qcs9100_priv_data },
+ { .compatible = "qcom,qcs9100-sndcard", .data = &qcs9100_priv_data },
+ { .compatible = "qcom,sc8280xp-sndcard", .data = &sc8280xp_priv_data },
+ { .compatible = "qcom,sm8450-sndcard", .data = &sm8450_priv_data },
+ { .compatible = "qcom,sm8475-sndcard", .data = &sm8475_priv_data },
+ { .compatible = "qcom,sm8550-sndcard", .data = &sm8550_priv_data },
+ { .compatible = "qcom,sm8650-sndcard", .data = &sm8650_priv_data },
+ { .compatible = "qcom,sm8750-sndcard", .data = &sm8750_priv_data },
{}
};
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
index 0ce9dff4dc52..6843ab8ba017 100644
--- a/sound/soc/qcom/sdm845.c
+++ b/sound/soc/qcom/sdm845.c
@@ -36,7 +36,6 @@ struct sdm845_snd_data {
bool jack_setup;
bool slim_port_setup;
bool stream_prepared[AFE_PORT_MAX];
- struct snd_soc_card *card;
uint32_t pri_mi2s_clk_count;
uint32_t sec_mi2s_clk_count;
uint32_t quat_tdm_clk_count;
@@ -564,7 +563,6 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev)
if (ret)
return ret;
- data->card = card;
snd_soc_card_set_drvdata(card, data);
sdm845_add_ops(card);
diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c
index f193d0ba63d0..76dc3a3f4a31 100644
--- a/sound/soc/qcom/sm8250.c
+++ b/sound/soc/qcom/sm8250.c
@@ -112,6 +112,22 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream)
snd_soc_dai_set_fmt(cpu_dai, fmt);
snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
break;
+ case LPI_MI2S_RX_0:
+ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_INT0_MI2S_IBIT,
+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ snd_soc_dai_set_fmt(cpu_dai, fmt);
+ snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+ break;
+ case LPI_MI2S_TX_3:
+ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_INT3_MI2S_IBIT,
+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE);
+ snd_soc_dai_set_fmt(cpu_dai, fmt);
+ snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+ break;
default:
break;
}
@@ -194,6 +210,7 @@ static const struct of_device_id snd_sm8250_dt_match[] = {
{ .compatible = "qcom,qrb2210-sndcard", .data = "qcm2290" },
{ .compatible = "qcom,qrb4210-rb2-sndcard", .data = "sm4250" },
{ .compatible = "qcom,qrb5165-rb5-sndcard", .data = "sm8250" },
+ { .compatible = "qcom,sdm660-sndcard", .data = "sdm660" },
{ .compatible = "qcom,sm8250-sndcard", .data = "sm8250" },
{}
};
diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c
index 1e0eda8c24c4..6b42fbfd27ca 100644
--- a/sound/soc/qcom/storm.c
+++ b/sound/soc/qcom/storm.c
@@ -64,21 +64,21 @@ static struct snd_soc_dai_link storm_dai_link = {
SND_SOC_DAILINK_REG(hifi),
};
-static int storm_parse_of(struct snd_soc_card *card)
+static int storm_parse_of(struct device *dev)
{
- struct snd_soc_dai_link *dai_link = card->dai_link;
- struct device_node *np = card->dev->of_node;
+ struct snd_soc_dai_link *dai_link = &storm_dai_link;
+ struct device_node *np = dev->of_node;
dai_link->cpus->of_node = of_parse_phandle(np, "cpu", 0);
if (!dai_link->cpus->of_node) {
- dev_err(card->dev, "error getting cpu phandle\n");
+ dev_err(dev, "error getting cpu phandle\n");
return -EINVAL;
}
dai_link->platforms->of_node = dai_link->cpus->of_node;
dai_link->codecs->of_node = of_parse_phandle(np, "codec", 0);
if (!dai_link->codecs->of_node) {
- dev_err(card->dev, "error getting codec phandle\n");
+ dev_err(dev, "error getting codec phandle\n");
return -EINVAL;
}
@@ -106,7 +106,7 @@ static int storm_platform_probe(struct platform_device *pdev)
card->dai_link = &storm_dai_link;
card->num_links = 1;
- ret = storm_parse_of(card);
+ ret = storm_parse_of(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "error resolving dai links: %d\n", ret);
return ret;
diff --git a/sound/soc/renesas/fsi.c b/sound/soc/renesas/fsi.c
index ae86014c3819..23b7e63596d3 100644
--- a/sound/soc/renesas/fsi.c
+++ b/sound/soc/renesas/fsi.c
@@ -1979,8 +1979,8 @@ static const struct of_device_id fsi_of_match[] = {
MODULE_DEVICE_TABLE(of, fsi_of_match);
static const struct platform_device_id fsi_id_table[] = {
- { "sh_fsi", (kernel_ulong_t)&fsi1_core },
- {},
+ /* an array with no valid entry prevents matching on driver name */
+ { }
};
MODULE_DEVICE_TABLE(platform, fsi_id_table);
@@ -1992,7 +1992,7 @@ static int fsi_probe(struct platform_device *pdev)
const struct fsi_core *core;
struct fsi_priv *fsi;
struct resource *res;
- unsigned int irq;
+ int irq;
int ret;
memset(&info, 0, sizeof(info));
@@ -2007,12 +2007,15 @@ static int fsi_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!res || (int)irq <= 0) {
+ if (!res) {
dev_err(&pdev->dev, "Not enough FSI platform resources.\n");
return -ENODEV;
}
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
if (!master)
return -ENOMEM;
diff --git a/sound/soc/renesas/rcar/adg.c b/sound/soc/renesas/rcar/adg.c
index 53efd1be5139..2a74d89ba39d 100644
--- a/sound/soc/renesas/rcar/adg.c
+++ b/sound/soc/renesas/rcar/adg.c
@@ -565,7 +565,7 @@ static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv,
struct clk *clk;
clk = clk_register_fixed_rate(dev, name, parent, 0, 0);
- if (IS_ERR_OR_NULL(clk)) {
+ if (IS_ERR(clk)) {
dev_err(dev, "create null clk error\n");
return ERR_CAST(clk);
}
@@ -618,7 +618,7 @@ static int rsnd_adg_get_clkin(struct rsnd_priv *priv)
* No "adg" is not error
*/
clk = devm_clk_get(dev, "adg");
- if (IS_ERR_OR_NULL(clk))
+ if (IS_ERR(clk))
clk = rsnd_adg_null_clk_get(priv);
adg->adg = clk;
@@ -626,9 +626,9 @@ static int rsnd_adg_get_clkin(struct rsnd_priv *priv)
for (i = 0; i < clkin_size; i++) {
clk = devm_clk_get(dev, clkin_name[i]);
- if (IS_ERR_OR_NULL(clk))
+ if (IS_ERR(clk))
clk = rsnd_adg_null_clk_get(priv);
- if (IS_ERR_OR_NULL(clk))
+ if (IS_ERR(clk))
goto err;
adg->clkin[i] = clk;
diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c
index 48ccc1d1854b..6db91b73f25c 100644
--- a/sound/soc/samsung/aries_wm8994.c
+++ b/sound/soc/samsung/aries_wm8994.c
@@ -658,6 +658,7 @@ static int aries_audio_probe(struct platform_device *pdev)
goto out;
}
+ of_node_get(aries_dai[0].cpus->of_node);
aries_dai[0].platforms->of_node = aries_dai[0].cpus->of_node;
/* Set CPU of_node for BT DAI */
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index f80f697a5d55..81d5dd36a246 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -8,6 +8,7 @@
#include <dt-bindings/sound/samsung-i2s.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
@@ -512,7 +513,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
u32 mod, mask, val = 0;
int ret = 0;
- pm_runtime_get_sync(dai->dev);
+ guard(pm_runtime_active)(dai->dev);
scoped_guard(spinlock_irqsave, &priv->lock)
mod = readl(priv->addr + I2SMOD);
@@ -537,8 +538,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
&& (mod & cdcon_mask))))) {
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
- ret = -EAGAIN;
- goto err;
+ return -EAGAIN;
}
if (dir == SND_SOC_CLOCK_IN)
@@ -566,7 +566,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
} else {
priv->rclk_srcrate =
clk_get_rate(priv->op_clk);
- goto done;
+ return 0;
}
}
@@ -580,14 +580,14 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
if (WARN_ON(IS_ERR(priv->op_clk))) {
ret = PTR_ERR(priv->op_clk);
priv->op_clk = NULL;
- goto err;
+ return ret;
}
ret = clk_prepare_enable(priv->op_clk);
if (ret) {
clk_put(priv->op_clk);
priv->op_clk = NULL;
- goto err;
+ return ret;
}
priv->rclk_srcrate = clk_get_rate(priv->op_clk);
@@ -595,11 +595,10 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
|| (clk_id && !(mod & rsrc_mask))) {
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
- ret = -EAGAIN;
- goto err;
+ return -EAGAIN;
} else {
/* Call can't be on the active DAI */
- goto done;
+ return 0;
}
if (clk_id == 1)
@@ -607,8 +606,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
break;
default:
dev_err(&i2s->pdev->dev, "We don't serve that!\n");
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
scoped_guard(spinlock_irqsave, &priv->lock) {
@@ -616,13 +614,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
mod = (mod & ~mask) | val;
writel(mod, priv->addr + I2SMOD);
}
-done:
- pm_runtime_put(dai->dev);
return 0;
-err:
- pm_runtime_put(dai->dev);
- return ret;
}
static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
@@ -1448,10 +1441,10 @@ static int samsung_i2s_probe(struct platform_device *pdev)
regs_base = res->start;
priv->clk = devm_clk_get(&pdev->dev, "iis");
- if (IS_ERR(priv->clk)) {
- dev_err(&pdev->dev, "Failed to get iis clock\n");
- return PTR_ERR(priv->clk);
- }
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk),
+ "Failed to get iis clock\n");
+
ret = clk_prepare_enable(priv->clk);
if (ret != 0) {
@@ -1682,7 +1675,7 @@ static const struct platform_device_id samsung_i2s_driver_ids[] = {
.name = "samsung-i2s",
.driver_data = (kernel_ulong_t)&i2sv3_dai_type,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids);
diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c
index 2474eb619882..515e4dfc1432 100644
--- a/sound/soc/samsung/smdk_spdif.c
+++ b/sound/soc/samsung/smdk_spdif.c
@@ -130,12 +130,8 @@ static int smdk_hw_params(struct snd_pcm_substream *substream,
return ret;
/* Set S/PDIF uses internal source clock */
- ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
- rclk_rate, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- return ret;
+ return snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
+ rclk_rate, SND_SOC_CLOCK_IN);
}
static const struct snd_soc_ops smdk_spdif_ops = {
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 7fc46d55c522..53eaabaf8956 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -380,8 +380,8 @@ static int spdif_probe(struct platform_device *pdev)
spdif->pclk = devm_clk_get(&pdev->dev, "spdif");
if (IS_ERR(spdif->pclk)) {
- dev_err(&pdev->dev, "failed to get peri-clock\n");
- ret = -ENOENT;
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(spdif->pclk),
+ "failed to get peri-clock\n");
goto err0;
}
ret = clk_prepare_enable(spdif->pclk);
@@ -390,8 +390,8 @@ static int spdif_probe(struct platform_device *pdev)
spdif->sclk = devm_clk_get(&pdev->dev, "sclk_spdif");
if (IS_ERR(spdif->sclk)) {
- dev_err(&pdev->dev, "failed to get internal source clock\n");
- ret = -ENOENT;
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(spdif->sclk),
+ "failed to get internal source clock\n");
goto err1;
}
ret = clk_prepare_enable(spdif->sclk);
diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c
index b4dedba719dc..9a6c0036b7be 100644
--- a/sound/soc/sdca/sdca_asoc.c
+++ b/sound/soc/sdca/sdca_asoc.c
@@ -1231,7 +1231,7 @@ static u64 width_find_mask(unsigned int bits)
}
}
-static int populate_rate_format(struct device *dev,
+int sdca_asoc_populate_rate_format(struct device *dev,
struct sdca_function_data *function,
struct sdca_entity *entity,
struct snd_soc_pcm_stream *stream)
@@ -1292,6 +1292,7 @@ static int populate_rate_format(struct device *dev,
return 0;
}
+EXPORT_SYMBOL_NS(sdca_asoc_populate_rate_format, "SND_SOC_SDCA");
/**
* sdca_asoc_populate_dais - fill in an array of DAI drivers for a Function
@@ -1344,7 +1345,7 @@ int sdca_asoc_populate_dais(struct device *dev, struct sdca_function_data *funct
stream->channels_min = 1;
stream->channels_max = SDCA_MAX_CHANNEL_COUNT;
- ret = populate_rate_format(dev, function, entity, stream);
+ ret = sdca_asoc_populate_rate_format(dev, function, entity, stream);
if (ret)
return ret;
diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c
index 7a7a9f1a4938..cdf1e68d60ac 100644
--- a/sound/soc/sdca/sdca_functions.c
+++ b/sound/soc/sdca/sdca_functions.c
@@ -1619,7 +1619,7 @@ static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw,
return 0;
}
-static struct sdca_entity *find_sdca_entity_by_label(struct sdca_function_data *function,
+struct sdca_entity *sdca_find_entity_by_label(struct sdca_function_data *function,
const char *entity_label)
{
struct sdca_entity *entity = NULL;
@@ -1648,6 +1648,7 @@ static struct sdca_entity *find_sdca_entity_by_label(struct sdca_function_data *
return NULL;
}
+EXPORT_SYMBOL_NS(sdca_find_entity_by_label, "SND_SOC_SDCA");
static struct sdca_entity *find_sdca_entity_by_id(struct sdca_function_data *function,
const int id)
@@ -1688,7 +1689,7 @@ static int find_sdca_entity_connection_iot(struct device *dev,
return ret;
}
- clock_entity = find_sdca_entity_by_label(function, clock_label);
+ clock_entity = sdca_find_entity_by_label(function, clock_label);
if (!clock_entity) {
dev_err(dev, "%s: failed to find clock with label %s\n",
entity->label, clock_label);
@@ -1873,7 +1874,7 @@ static int find_sdca_entity_connection(struct device *dev,
return ret;
}
- connected_entity = find_sdca_entity_by_label(function, connected_label);
+ connected_entity = sdca_find_entity_by_label(function, connected_label);
if (!connected_entity) {
dev_err(dev, "%s: failed to find entity with label %s\n",
entity->label, connected_label);
diff --git a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
index e0e32a279787..129a437ae397 100644
--- a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
+++ b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
@@ -99,11 +99,9 @@ static const struct snd_soc_dai_link bridge_dai_template = {
SND_SOC_DAILINK_REG(asoc_sdw_bridge_dai),
};
-int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card,
+int asoc_sdw_bridge_cs35l56_count_sidecar(struct asoc_sdw_mc_private *ctx,
int *num_dais, int *num_devs)
{
- struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
-
if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) {
(*num_dais)++;
(*num_devs) += ARRAY_SIZE(bridge_cs35l56_name_prefixes);
diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c
index d8db8fc5313e..d4074309fa81 100644
--- a/sound/soc/sdw_utils/soc_sdw_utils.c
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -836,6 +836,35 @@ struct asoc_sdw_codec_info codec_info_list[] = {
},
{
.vendor_id = 0x01fa,
+ .part_id = 0x3562,
+ .name_prefix = "AMP",
+ .is_amp = true,
+ .dais = {
+ {
+ .direction = {true, false},
+ .dai_name = "cs35l56-sdw1",
+ .component_name = "cs35l56",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .init = asoc_sdw_cs_amp_init,
+ .rtd_init = asoc_sdw_cs_spk_rtd_init,
+ .controls = generic_spk_controls,
+ .num_controls = ARRAY_SIZE(generic_spk_controls),
+ .widgets = generic_spk_widgets,
+ .num_widgets = ARRAY_SIZE(generic_spk_widgets),
+ },
+ {
+ .direction = {false, true},
+ .dai_name = "cs35l56-sdw1c",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
+ .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
+ },
+ },
+ .dai_num = 2,
+ },
+ {
+ .vendor_id = 0x01fa,
.part_id = 0x3563,
.name_prefix = "AMP",
.is_amp = true,
@@ -1976,14 +2005,13 @@ put_device:
return ret;
}
-int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
+int asoc_sdw_parse_sdw_endpoints(struct device *dev,
+ struct asoc_sdw_mc_private *ctx,
struct snd_soc_aux_dev *soc_aux,
struct asoc_sdw_dailink *soc_dais,
struct asoc_sdw_endpoint *soc_ends,
int *num_devs)
{
- struct device *dev = card->dev;
- struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
const struct snd_soc_acpi_link_adr *adr_link;
@@ -2045,7 +2073,7 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic;
if (codec_info->count_sidecar && codec_info->add_sidecar) {
- ret = codec_info->count_sidecar(card, &num_dais, num_devs);
+ ret = codec_info->count_sidecar(ctx, &num_dais, num_devs);
if (ret)
return ret;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 4ad126bd4f70..c98e917cc911 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1203,6 +1203,8 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
case snd_soc_dapm_pga:
case snd_soc_dapm_effect:
case snd_soc_dapm_out_drv:
+ case snd_soc_dapm_encoder:
+ case snd_soc_dapm_decoder:
wname_in_long_name = true;
kcname_in_long_name = true;
break;
@@ -2785,6 +2787,8 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *component,
case snd_soc_dapm_pga:
case snd_soc_dapm_effect:
case snd_soc_dapm_out_drv:
+ case snd_soc_dapm_encoder:
+ case snd_soc_dapm_decoder:
case snd_soc_dapm_mixer:
case snd_soc_dapm_mixer_named_ctl:
case snd_soc_dapm_supply:
@@ -3367,6 +3371,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
case snd_soc_dapm_pga:
case snd_soc_dapm_effect:
case snd_soc_dapm_out_drv:
+ case snd_soc_dapm_encoder:
+ case snd_soc_dapm_decoder:
dapm_new_pga(w);
break;
case snd_soc_dapm_dai_link:
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index 467426d2b5e4..98ba9a836936 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -3,6 +3,7 @@
// Copyright (C) 2013, Analog Devices Inc.
// Author: Lars-Peter Clausen <lars@metafoo.de>
+#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/dmaengine.h>
@@ -395,6 +396,27 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm,
*/
if (PTR_ERR(chan) == -EPROBE_DEFER)
return -EPROBE_DEFER;
+
+ bool has_fw_node = dev->of_node || is_acpi_device_node(dev->fwnode);
+ bool name_exists_in_fw = false;
+
+ if (has_fw_node)
+ name_exists_in_fw = device_property_match_string(dev,
+ "dma-names",
+ name) >= 0;
+
+ if (has_fw_node && name_exists_in_fw)
+ dev_warn(dev, "DTS/ACPI DMA channel '%s' request failed (%ld)\n",
+ name, PTR_ERR(chan));
+
+ if (has_fw_node && !name_exists_in_fw)
+ dev_warn(dev, "DTS/ACPI name '%s' not found, legacy failed (%ld)\n",
+ name, PTR_ERR(chan));
+
+ if (!has_fw_node)
+ dev_warn(dev, "Legacy DMA channel '%s' request failed (%ld)\n",
+ name, PTR_ERR(chan));
+
pcm->chan[i] = NULL;
} else {
pcm->chan[i] = chan;
@@ -406,6 +428,12 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm,
if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
pcm->chan[1] = pcm->chan[0];
+ if (!pcm->chan[0] &&
+ !pcm->chan[1]) {
+ dev_err(dev, "no DMA channel found for either playback or capture\n");
+ return -ENODEV;
+ }
+
return 0;
}
diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig
index 05faf1c6d6fc..903e7ec3b3ba 100644
--- a/sound/soc/sof/amd/Kconfig
+++ b/sound/soc/sof/amd/Kconfig
@@ -104,4 +104,15 @@ config SND_SOC_SOF_AMD_ACP70
AMD ACP7.0/ACP7.1 version based platforms.
Say Y if you want to enable SOF on ACP7.0/ACP7.1 based platforms.
+config SND_SOC_SOF_AMD_ACP7X
+ tristate "SOF support for ACP7.B/7.F platforms"
+ depends on SND_SOC_SOF_PCI
+ depends on AMD_NODE
+ select SND_SOC_SOF_AMD_COMMON
+ help
+ Select this option for SOF support on AMD ACP7.B and ACP7.F PCI
+ revision based platforms.
+ Say Y if you want to enable SOF on ACP7.B/7.F based platforms.
+ If unsure select "N".
+
endif
diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile
index 6ae39fd5a836..bb1c0ddef69d 100644
--- a/sound/soc/sof/amd/Makefile
+++ b/sound/soc/sof/amd/Makefile
@@ -11,6 +11,7 @@ snd-sof-amd-rembrandt-y := pci-rmb.o rembrandt.o
snd-sof-amd-vangogh-y := pci-vangogh.o vangogh.o
snd-sof-amd-acp63-y := pci-acp63.o acp63.o
snd-sof-amd-acp70-y := pci-acp70.o acp70.o
+snd-sof-amd-acp7x-y := pci-acp7x.o acp7x.o
obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o
obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) += snd-sof-amd-renoir.o
@@ -18,3 +19,4 @@ obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) += snd-sof-amd-rembrandt.o
obj-$(CONFIG_SND_SOC_SOF_AMD_VANGOGH) += snd-sof-amd-vangogh.o
obj-$(CONFIG_SND_SOC_SOF_AMD_ACP63) += snd-sof-amd-acp63.o
obj-$(CONFIG_SND_SOC_SOF_AMD_ACP70) += snd-sof-amd-acp70.o
+obj-$(CONFIG_SND_SOC_SOF_AMD_ACP7X) += snd-sof-amd-acp7x.o
diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h
index 08583a91afbc..bea1bd3afa70 100644
--- a/sound/soc/sof/amd/acp-dsp-offset.h
+++ b/sound/soc/sof/amd/acp-dsp-offset.h
@@ -68,12 +68,14 @@
#define ACP5X_PGFSM_BASE 0x1424
#define ACP6X_PGFSM_BASE 0x1024
#define ACP70_PGFSM_BASE ACP6X_PGFSM_BASE
+#define ACP7X_PGFSM_BASE ACP6X_PGFSM_BASE
#define PGFSM_CONTROL_OFFSET 0x0
#define PGFSM_STATUS_OFFSET 0x4
#define ACP3X_CLKMUX_SEL 0x1424
#define ACP5X_CLKMUX_SEL 0x142C
#define ACP6X_CLKMUX_SEL 0x102C
#define ACP70_CLKMUX_SEL ACP6X_CLKMUX_SEL
+#define ACP7X_CLKMUX_SEL ACP6X_CLKMUX_SEL
/* Registers from ACP_INTR block */
#define ACP3X_EXT_INTR_STAT 0x1808
@@ -86,21 +88,31 @@
#define ACP70_EXTERNAL_INTR_CNTL ACP6X_EXTERNAL_INTR_CNTL
#define ACP70_EXT_INTR_STAT ACP6X_EXT_INTR_STAT
#define ACP70_EXT_INTR_STAT1 ACP6X_EXT_INTR_STAT1
+#define ACP7X_EXTERNAL_INTR_ENB ACP6X_EXTERNAL_INTR_ENB
+#define ACP7X_EXTERNAL_INTR_CNTL 0x1A04
+#define ACP7X_EXT_INTR_STAT 0x1A1C
+#define ACP7X_EXTERNAL_INTR_CNTL1 0x1A08
+#define ACP7X_EXT_INTR_STAT1 0x1A20
#define ACP3X_DSP_SW_INTR_BASE 0x1814
#define ACP5X_DSP_SW_INTR_BASE 0x1814
#define ACP6X_DSP_SW_INTR_BASE 0x1808
#define ACP70_DSP_SW_INTR_BASE ACP6X_DSP_SW_INTR_BASE
+#define ACP7X_DSP_SW_INTR_BASE 0x1860
#define DSP_SW_INTR_CNTL_OFFSET 0x0
#define DSP_SW_INTR_STAT_OFFSET 0x4
+#define ACP7X_DSP_SW_INTR_STAT (ACP7X_DSP_SW_INTR_BASE + DSP_SW_INTR_STAT_OFFSET)
#define DSP_SW_INTR_TRIG_OFFSET 0x8
+#define ACP7X_DSP_SW_INTR_TRIG_OFFSET 0x30
#define ACP3X_ERROR_STATUS 0x18C4
#define ACP6X_ERROR_STATUS 0x1A4C
#define ACP70_ERROR_STATUS ACP6X_ERROR_STATUS
+#define ACP7X_ERROR_STATUS 0x1A88
#define ACP3X_AXI2DAGB_SEM_0 0x1880
#define ACP5X_AXI2DAGB_SEM_0 0x1884
#define ACP6X_AXI2DAGB_SEM_0 0x1874
#define ACP70_AXI2DAGB_SEM_0 ACP6X_AXI2DAGB_SEM_0
+#define ACP7X_AXI2DAGB_SEM_0 0x18F4
/* ACP common registers to report errors related to I2S & SoundWire interfaces */
#define ACP3X_SW_I2S_ERROR_REASON 0x18C8
@@ -123,6 +135,7 @@
#define ACP_SCRATCH_REG_0 0x10000
#define ACP6X_DSP_FUSION_RUNSTALL 0x0644
#define ACP70_DSP_FUSION_RUNSTALL ACP6X_DSP_FUSION_RUNSTALL
+#define ACP7X_DSP_FUSION_RUNSTALL ACP6X_DSP_FUSION_RUNSTALL
/* Cache window registers */
#define ACP_DSP0_CACHE_OFFSET0 0x0420
@@ -139,5 +152,9 @@
#define ACP70_SDW1_HOST_WAKE_STAT BIT(25)
#define ACP70_SDW0_PME_STAT BIT(26)
#define ACP70_SDW1_PME_STAT BIT(27)
+#define ACP7X_DSP0_IDMA_ERROR_MASK 0x4B0
+#define ACP7X_IDMA_ERROR_MASK 0x1FF9FF
+#define ACP7X_ZSC_DSP_CTRL 0x001014
+#define ACP7X_PME_EN ACP70_PME_EN
#endif
diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c
index 94025bc799ea..494f9cb0c06f 100644
--- a/sound/soc/sof/amd/acp-ipc.c
+++ b/sound/soc/sof/amd/acp-ipc.c
@@ -32,11 +32,20 @@ static void acpbus_trigger_host_to_dsp_swintr(struct acp_dev_data *adata)
struct snd_sof_dev *sdev = adata->dev;
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
u32 swintr_trigger;
-
+ unsigned int swintr_trigger_reg_offset;
+
+ switch (adata->pci_rev) {
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
+ swintr_trigger_reg_offset = ACP7X_DSP_SW_INTR_TRIG_OFFSET;
+ break;
+ default:
+ swintr_trigger_reg_offset = DSP_SW_INTR_TRIG_OFFSET;
+ }
swintr_trigger = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->dsp_intr_base +
- DSP_SW_INTR_TRIG_OFFSET);
+ swintr_trigger_reg_offset);
swintr_trigger |= 0x01;
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->dsp_intr_base + DSP_SW_INTR_TRIG_OFFSET,
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->dsp_intr_base + swintr_trigger_reg_offset,
swintr_trigger);
}
diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c
index 98324bbade15..f1ec85694323 100644
--- a/sound/soc/sof/amd/acp-loader.c
+++ b/sound/soc/sof/amd/acp-loader.c
@@ -14,6 +14,7 @@
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/unaligned.h>
#include "../ops.h"
#include "acp-dsp-offset.h"
@@ -173,10 +174,31 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
adata = sdev->pdata->hw_pdata;
- if (adata->quirks && adata->quirks->signed_fw_image)
+ if (adata->pci_rev >= ACP7B_PCI_ID) {
+ if (adata->acp_sof_signed_firmware_image) {
+ if (adata->fw_bin_size <= ACP_IMAGE_HEADER_SIZE) {
+ dev_err(sdev->dev, "Invalid signed firmware size %u\n",
+ adata->fw_bin_size);
+ return -EINVAL;
+ }
+ size_fw = get_unaligned_le32(adata->bin_buf +
+ ACP_IMAGE_HDR_SIZE_FW_SIGNED_OFF);
+ if (!size_fw ||
+ size_fw > adata->fw_bin_size - ACP_IMAGE_HEADER_SIZE) {
+ dev_err(sdev->dev,
+ "Invalid signed firmware payload size %u (max %u)\n",
+ size_fw, adata->fw_bin_size - ACP_IMAGE_HEADER_SIZE);
+ return -EINVAL;
+ }
+ size_fw += ACP_IMAGE_HEADER_SIZE;
+ } else {
+ size_fw = adata->fw_bin_size;
+ }
+ } else if (adata->quirks && adata->quirks->signed_fw_image) {
size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE;
- else
+ } else {
size_fw = adata->fw_bin_size;
+ }
page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT;
adata->fw_bin_page_count = page_count;
@@ -312,9 +334,14 @@ int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev)
}
kfree(fw_filename);
- ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0,
- (void *)adata->fw_dbin->data,
- adata->fw_dbin->size);
+ if (adata->pci_rev >= ACP7B_PCI_ID)
+ ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_SRAM, 0,
+ (void *)adata->fw_dbin->data,
+ adata->fw_dbin->size);
+ else
+ ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0,
+ (void *)adata->fw_dbin->data,
+ adata->fw_dbin->size);
return ret;
}
EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, "SND_SOC_SOF_AMD_COMMON");
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index e6af8927baa0..f89ad86260b4 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -12,6 +12,7 @@
* Hardware interface for generic AMD ACP processor
*/
+#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -60,6 +61,8 @@ static void init_dma_descriptor(struct acp_dev_data *adata)
case ACP70_PCI_ID:
case ACP71_PCI_ID:
case ACP72_PCI_ID:
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
acp_dma_desc_base_addr = ACP70_DMA_DESC_BASE_ADDR;
acp_dma_desc_max_num_dscr = ACP70_DMA_DESC_MAX_NUM_DSCR;
break;
@@ -101,6 +104,8 @@ static int config_dma_channel(struct acp_dev_data *adata, unsigned int ch,
case ACP70_PCI_ID:
case ACP71_PCI_ID:
case ACP72_PCI_ID:
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
acp_dma_cntl_0 = ACP70_DMA_CNTL_0;
acp_dma_ch_rst_sts = ACP70_DMA_CH_RST_STS;
acp_dma_dscr_err_sts_0 = ACP70_DMA_ERR_STS_0;
@@ -283,7 +288,8 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
}
}
- if (adata->quirks && adata->quirks->signed_fw_image)
+ if ((adata->quirks && adata->quirks->signed_fw_image) ||
+ adata->acp_sof_signed_firmware_image)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER);
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr);
@@ -342,6 +348,8 @@ int acp_dma_status(struct acp_dev_data *adata, unsigned char ch)
case ACP70_PCI_ID:
case ACP71_PCI_ID:
case ACP72_PCI_ID:
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
acp_dma_ch_sts = ACP70_DMA_CH_STS;
break;
default:
@@ -534,8 +542,17 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK);
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_sw0_i2s_err_reason, 0);
/* ACP_SW1_I2S_ERROR_REASON is newly added register from rmb platform onwards */
- if (adata->pci_rev >= ACP_RMB_PCI_ID)
+ switch (adata->pci_rev) {
+ case ACP_RMB_PCI_ID:
+ case ACP63_PCI_ID:
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW1_I2S_ERROR_REASON, 0);
+ break;
+ default:
+ break;
+ }
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0);
irq_flag = 1;
}
@@ -564,6 +581,35 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)
return IRQ_NONE;
}
+static irqreturn_t acp7x_irq_handler(int irq, void *dev_id)
+{
+ struct snd_sof_dev *sdev = dev_id;
+ const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+ unsigned int base = desc->dsp_intr_base;
+ unsigned int val;
+ unsigned int ext_intr_stat;
+ int irq_flag = 0;
+
+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);
+ if (val & ACP_DSP_TO_HOST_IRQ) {
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET,
+ ACP_DSP_TO_HOST_IRQ);
+ return IRQ_WAKE_THREAD;
+ }
+
+ ext_intr_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat);
+ if (ext_intr_stat & ACP_ERROR_IRQ_MASK) {
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0);
+ irq_flag = 1;
+ }
+
+ if (irq_flag)
+ return IRQ_HANDLED;
+
+ return IRQ_NONE;
+}
+
static int acp_power_on(struct snd_sof_dev *sdev)
{
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
@@ -571,6 +617,7 @@ static int acp_power_on(struct snd_sof_dev *sdev)
unsigned int base = desc->pgfsm_base;
unsigned int val;
unsigned int acp_pgfsm_status_mask, acp_pgfsm_cntl_mask;
+ bool use_masked_status = false;
int ret;
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET);
@@ -595,6 +642,12 @@ static int acp_power_on(struct snd_sof_dev *sdev)
acp_pgfsm_status_mask = ACP70_PGFSM_STATUS_MASK;
acp_pgfsm_cntl_mask = ACP70_PGFSM_CNTL_POWER_ON_MASK;
break;
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
+ acp_pgfsm_status_mask = ACP7X_PGFSM_STATUS_MASK;
+ acp_pgfsm_cntl_mask = ACP7X_PGFSM_CNTL_POWER_ON_MASK;
+ use_masked_status = true;
+ break;
default:
return -EINVAL;
}
@@ -603,8 +656,17 @@ static int acp_power_on(struct snd_sof_dev *sdev)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + PGFSM_CONTROL_OFFSET,
acp_pgfsm_cntl_mask);
- ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET, val,
- !val, ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US);
+ if (use_masked_status)
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR,
+ base + PGFSM_STATUS_OFFSET, val,
+ !(val & acp_pgfsm_status_mask),
+ ACP_REG_POLL_INTERVAL,
+ ACP_REG_POLL_TIMEOUT_US);
+ else
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR,
+ base + PGFSM_STATUS_OFFSET, val,
+ !val, ACP_REG_POLL_INTERVAL,
+ ACP_REG_POLL_TIMEOUT_US);
if (ret < 0)
dev_err(sdev->dev, "timeout in ACP_PGFSM_STATUS read\n");
@@ -703,6 +765,13 @@ static int acp_init(struct snd_sof_dev *sdev)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP70_PME_EN, 1);
break;
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 0);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_DSP0_IDMA_ERROR_MASK,
+ ACP7X_IDMA_ERROR_MASK);
+ break;
}
return 0;
}
@@ -749,6 +818,8 @@ int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state)
case ACP72_PCI_ID:
enable = true;
break;
+ default:
+ break;
}
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable);
@@ -990,6 +1061,194 @@ void amd_sof_acp_remove(struct snd_sof_dev *sdev)
}
EXPORT_SYMBOL_NS(amd_sof_acp_remove, "SND_SOC_SOF_AMD_COMMON");
+int amd_sof_acp7x_probe(struct snd_sof_dev *sdev)
+{
+ struct pci_dev *pci = to_pci_dev(sdev->dev);
+ struct acp_dev_data *adata;
+ const struct sof_amd_acp_desc *chip;
+ const union acpi_object *obj;
+ struct acpi_device *adev;
+ unsigned int addr;
+ unsigned int irqflags;
+ int ret;
+
+ chip = get_chip_info(sdev->pdata);
+ if (!chip) {
+ dev_err(sdev->dev, "no such device supported, chip id:%x\n", pci->device);
+ return -EIO;
+ }
+ adata = devm_kzalloc(sdev->dev, sizeof(struct acp_dev_data), GFP_KERNEL);
+ if (!adata)
+ return -ENOMEM;
+
+ adata->dev = sdev;
+ adata->dmic_dev = platform_device_register_data(sdev->dev, "dmic-codec",
+ PLATFORM_DEVID_NONE, NULL, 0);
+ if (IS_ERR(adata->dmic_dev)) {
+ dev_err(sdev->dev, "failed to register platform for dmic codec\n");
+ return PTR_ERR(adata->dmic_dev);
+ }
+
+ addr = pci_resource_start(pci, ACP_DSP_BAR);
+ sdev->bar[ACP_DSP_BAR] = devm_ioremap(sdev->dev, addr, pci_resource_len(pci, ACP_DSP_BAR));
+ if (!sdev->bar[ACP_DSP_BAR]) {
+ dev_err(sdev->dev, "ioremap error\n");
+ ret = -ENXIO;
+ goto unregister_dev;
+ }
+
+ pci_set_master(pci);
+ adata->addr = addr;
+ adata->reg_range = chip->reg_end_addr - chip->reg_start_addr;
+ adata->pci_rev = pci->revision;
+ mutex_init(&adata->acp_lock);
+ sdev->pdata->hw_pdata = adata;
+
+ ret = acp_init(sdev);
+ if (ret < 0)
+ goto unregister_dev;
+
+ adev = ACPI_COMPANION(&pci->dev);
+
+ sdev->ipc_irq = pci->irq;
+ irqflags = IRQF_SHARED;
+
+ ret = request_threaded_irq(pci->irq, acp7x_irq_handler, acp_irq_thread,
+ irqflags, "AudioDSP", sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to register IRQ %d\n", sdev->ipc_irq);
+ goto unregister_dev;
+ }
+
+ if (adev) {
+ if (!acpi_dev_get_property(adev, "acp-sof-signed-firmware-image",
+ ACPI_TYPE_INTEGER, &obj))
+ adata->acp_sof_signed_firmware_image = obj->integer.value;
+ }
+
+ sdev->dsp_box.offset = 0;
+ sdev->dsp_box.size = BOX_SIZE_512;
+
+ sdev->host_box.offset = sdev->dsp_box.offset + sdev->dsp_box.size;
+ sdev->host_box.size = BOX_SIZE_512;
+
+ sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size;
+ sdev->debug_box.size = BOX_SIZE_1024;
+
+ if (adata->acp_sof_signed_firmware_image) {
+ adata->fw_code_bin = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "sof-%s-code.bin", chip->name);
+ if (!adata->fw_code_bin) {
+ ret = -ENOMEM;
+ goto free_ipc_irq;
+ }
+ adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "sof-%s-data.bin", chip->name);
+ if (!adata->fw_data_bin) {
+ ret = -ENOMEM;
+ goto free_ipc_irq;
+ }
+ }
+
+ adata->enable_fw_debug = enable_fw_debug;
+ acp_memory_init(sdev);
+ acp_dsp_stream_init(sdev);
+
+ return 0;
+
+free_ipc_irq:
+ free_irq(sdev->ipc_irq, sdev);
+unregister_dev:
+ platform_device_unregister(adata->dmic_dev);
+ return ret;
+}
+EXPORT_SYMBOL_NS(amd_sof_acp7x_probe, "SND_SOC_SOF_AMD_COMMON");
+
+void amd_sof_acp7x_remove(struct snd_sof_dev *sdev)
+{
+ struct acp_dev_data *adata = sdev->pdata->hw_pdata;
+
+ if (sdev->ipc_irq)
+ free_irq(sdev->ipc_irq, sdev);
+
+ if (adata->dmic_dev)
+ platform_device_unregister(adata->dmic_dev);
+
+ acp_reset(sdev);
+}
+EXPORT_SYMBOL_NS(amd_sof_acp7x_remove, "SND_SOC_SOF_AMD_COMMON");
+
+int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state)
+{
+ struct acp_dev_data *acp_data;
+ int ret;
+ bool enable = false;
+
+ acp_data = sdev->pdata->hw_pdata;
+
+ ret = acp_reset(sdev);
+ if (ret) {
+ dev_err(sdev->dev, "ACP Reset failed\n");
+ return ret;
+ }
+ switch (acp_data->pci_rev) {
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
+ enable = true;
+ break;
+ default:
+ break;
+ }
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 1);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend, "SND_SOC_SOF_AMD_COMMON");
+
+int amd_sof_acp7x_resume(struct snd_sof_dev *sdev)
+{
+ struct acp_dev_data *acp_data;
+ int ret;
+
+ acp_data = sdev->pdata->hw_pdata;
+
+ ret = acp_init(sdev);
+ if (ret) {
+ dev_err(sdev->dev, "ACP Init failed\n");
+ return ret;
+ }
+ ret = acp_memory_init(sdev);
+ if (ret) {
+ dev_err(sdev->dev, "ACP Memory init failed\n");
+ return ret;
+ }
+
+ switch (acp_data->pci_rev) {
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(amd_sof_acp7x_resume, "SND_SOC_SOF_AMD_COMMON");
+
+int amd_sof_acp7x_suspend_runtime(struct snd_sof_dev *sdev)
+{
+ return amd_sof_acp7x_suspend(sdev, 0);
+}
+EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend_runtime, "SND_SOC_SOF_AMD_COMMON");
+
+int amd_sof_acp7x_resume_runtime(struct snd_sof_dev *sdev)
+{
+ return amd_sof_acp7x_resume(sdev);
+}
+EXPORT_SYMBOL_NS(amd_sof_acp7x_resume_runtime, "SND_SOC_SOF_AMD_COMMON");
+
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("AMD ACP sof driver");
MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT");
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h
index 7bcb76676a98..16d66b2eaa70 100644
--- a/sound/soc/sof/amd/acp.h
+++ b/sound/soc/sof/amd/acp.h
@@ -76,6 +76,12 @@
#define ACP70_PCI_ID 0x70
#define ACP71_PCI_ID 0x71
#define ACP72_PCI_ID 0x72
+#define ACP7B_PCI_ID 0x7B
+#define ACP7F_PCI_ID 0x7F
+
+#define ACP7X_PGFSM_CNTL_POWER_ON_MASK 0x7F
+#define ACP7X_PGFSM_STATUS_MASK 0xFFF
+#define ACP7X_SRAM_PTE_OFFSET ACP6X_SRAM_PTE_OFFSET
#define HOST_BRIDGE_CZN 0x1630
#define HOST_BRIDGE_VGH 0x1645
@@ -107,6 +113,9 @@
#define PROBE_STATUS_BIT BIT(31)
#define ACP_FIRMWARE_SIGNATURE 0x100
+#define ACP_IMAGE_HEADER_SIZE ACP_FIRMWARE_SIGNATURE
+#define ACP_IMAGE_HDR_SIZE_FW_SIGNED_OFF 0x14
+
#define ACP_ERROR_IRQ_MASK BIT(29)
#define ACP_SDW0_IRQ_MASK BIT(21)
#define ACP_SDW1_IRQ_MASK BIT(2)
@@ -271,6 +280,7 @@ struct acp_dev_data {
/* acp70_sdw1_wake_event flag set to true when wake irq asserted for SW1 instance */
bool acp70_sdw1_wake_event;
unsigned int pci_rev;
+ int acp_sof_signed_firmware_image;
};
void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes);
@@ -344,6 +354,16 @@ int sof_acp63_ops_init(struct snd_sof_dev *sdev);
extern struct snd_sof_dsp_ops sof_acp70_ops;
int sof_acp70_ops_init(struct snd_sof_dev *sdev);
+extern struct snd_sof_dsp_ops sof_acp7x_ops;
+int sof_acp7x_ops_init(struct snd_sof_dev *sdev);
+
+int amd_sof_acp7x_probe(struct snd_sof_dev *sdev);
+void amd_sof_acp7x_remove(struct snd_sof_dev *sdev);
+int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state);
+int amd_sof_acp7x_resume(struct snd_sof_dev *sdev);
+int amd_sof_acp7x_suspend_runtime(struct snd_sof_dev *sdev);
+int amd_sof_acp7x_resume_runtime(struct snd_sof_dev *sdev);
+
struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev);
/* Machine configuration */
int snd_amd_acp_find_config(struct pci_dev *pci);
diff --git a/sound/soc/sof/amd/acp7x.c b/sound/soc/sof/amd/acp7x.c
new file mode 100644
index 000000000000..b6722d11168c
--- /dev/null
+++ b/sound/soc/sof/amd/acp7x.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2025 Advanced Micro Devices, Inc.
+//
+// Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+
+/*
+ * Hardware interface for Audio DSP on ACP7.B/7.F platforms
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <sound/soc-acpi.h>
+
+#include "../ops.h"
+#include "../sof-audio.h"
+#include "acp.h"
+#include "acp-dsp-offset.h"
+
+#define I2S_TDM0_INSTANCE 0
+#define I2S_TDM1_INSTANCE 1
+#define I2S_TDM2_INSTANCE 2
+#define PDM0_DMIC_INSTANCE 3
+#define PDM1_DMIC_INSTANCE 4
+
+static struct snd_soc_dai_driver acp7x_sof_dai[] = {
+ [I2S_TDM0_INSTANCE] = {
+ .id = I2S_TDM0_INSTANCE,
+ .name = "acp-sof-i2s0",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S HS controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_TDM1_INSTANCE] = {
+ .id = I2S_TDM1_INSTANCE,
+ .name = "acp-sof-i2s1",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S BT controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_TDM2_INSTANCE] = {
+ .id = I2S_TDM2_INSTANCE,
+ .name = "acp-sof-i2s2",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S SP controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [PDM0_DMIC_INSTANCE] = {
+ .id = PDM0_DMIC_INSTANCE,
+ .name = "acp-sof-dmic0",
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 4,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [PDM1_DMIC_INSTANCE] = {
+ .id = PDM1_DMIC_INSTANCE,
+ .name = "acp-sof-dmic1",
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 4,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ },
+};
+
+static int sof_acp7x_post_fw_run_delay(struct snd_sof_dev *sdev)
+{
+ /*
+ * Resuming from suspend in some cases may cause the DSP firmware
+ * to enter an unrecoverable faulty state. Delaying a bit any host
+ * to DSP transmission right after firmware boot completion seems
+ * to resolve the issue.
+ */
+ if (!sdev->first_boot)
+ usleep_range(100, 150);
+
+ return 0;
+}
+
+struct snd_sof_dsp_ops sof_acp7x_ops;
+EXPORT_SYMBOL_NS(sof_acp7x_ops, "SND_SOC_SOF_AMD_COMMON");
+
+int sof_acp7x_ops_init(struct snd_sof_dev *sdev)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&to_pci_dev(sdev->dev)->dev);
+ const union acpi_object *obj;
+ int acp_sof_signed_firmware_image = 0;
+ int acp_sof_post_fw_run_delay = 0;
+
+ /* common defaults */
+ memcpy(&sof_acp7x_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops));
+
+ sof_acp7x_ops.drv = acp7x_sof_dai;
+ sof_acp7x_ops.num_drv = ARRAY_SIZE(acp7x_sof_dai);
+ sof_acp7x_ops.probe = amd_sof_acp7x_probe;
+ sof_acp7x_ops.remove = amd_sof_acp7x_remove;
+
+ if (adev) {
+ if (!acpi_dev_get_property(adev, "acp-sof-signed-firmware-image",
+ ACPI_TYPE_INTEGER, &obj))
+ acp_sof_signed_firmware_image = obj->integer.value;
+
+ if (!acpi_dev_get_property(adev, "acp-sof-post_fw_run_delay",
+ ACPI_TYPE_INTEGER, &obj))
+ acp_sof_post_fw_run_delay = obj->integer.value;
+ }
+
+ if (acp_sof_signed_firmware_image)
+ sof_acp7x_ops.load_firmware = acp_sof_load_signed_firmware;
+
+ if (acp_sof_post_fw_run_delay)
+ sof_acp7x_ops.post_fw_run = sof_acp7x_post_fw_run_delay;
+
+ sof_acp7x_ops.suspend = amd_sof_acp7x_suspend;
+ sof_acp7x_ops.resume = amd_sof_acp7x_resume;
+ sof_acp7x_ops.runtime_suspend = amd_sof_acp7x_suspend_runtime;
+ sof_acp7x_ops.runtime_resume = amd_sof_acp7x_resume_runtime;
+
+ return 0;
+}
diff --git a/sound/soc/sof/amd/pci-acp7x.c b/sound/soc/sof/amd/pci-acp7x.c
new file mode 100644
index 000000000000..532e15313795
--- /dev/null
+++ b/sound/soc/sof/amd/pci-acp7x.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2025 Advanced Micro Devices, Inc. All rights reserved.
+//
+// Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+
+/*
+ * PCI interface for ACP7.B/7.F devices
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <sound/sof.h>
+#include <sound/soc-acpi.h>
+
+#include "../ops.h"
+#include "../sof-pci-dev.h"
+#include "../../amd/mach-config.h"
+#include "acp.h"
+#include "acp-dsp-offset.h"
+
+#define ACP7X_FUTURE_REG_ACLK_0 0x18e0
+#define ACP7X_REG_START 0x1240000
+#define ACP7X_REG_END 0x125C000
+
+static const struct sof_amd_acp_desc acp7x_chip_info = {
+ .name = "acp7x",
+ .pgfsm_base = ACP7X_PGFSM_BASE,
+ .ext_intr_enb = ACP6X_EXTERNAL_INTR_ENB,
+ .ext_intr_cntl = ACP7X_EXTERNAL_INTR_CNTL,
+ .ext_intr_stat = ACP7X_EXT_INTR_STAT,
+ .ext_intr_stat1 = ACP7X_EXT_INTR_STAT1,
+ .dsp_intr_base = ACP7X_DSP_SW_INTR_BASE,
+ .acp_error_stat = ACP7X_ERROR_STATUS,
+ .sram_pte_offset = ACP7X_SRAM_PTE_OFFSET,
+ .hw_semaphore_offset = ACP7X_AXI2DAGB_SEM_0,
+ .fusion_dsp_offset = ACP7X_DSP_FUSION_RUNSTALL,
+ .probe_reg_offset = ACP7X_FUTURE_REG_ACLK_0,
+ .reg_start_addr = ACP7X_REG_START,
+ .reg_end_addr = ACP7X_REG_END,
+};
+
+static const struct sof_dev_desc acp7x_desc = {
+ .machines = snd_soc_acpi_amd_acp7x_sof_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &acp7x_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
+ .ipc_default = SOF_IPC_TYPE_3,
+ .default_fw_path = {
+ [SOF_IPC_TYPE_3] = "amd/sof",
+ },
+ .default_tplg_path = {
+ [SOF_IPC_TYPE_3] = "amd/sof-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC_TYPE_3] = "sof-acp7x.ri",
+ },
+ .nocodec_tplg_filename = "sof-acp.tplg",
+ .ops = &sof_acp7x_ops,
+ .ops_init = sof_acp7x_ops_init,
+};
+
+static int acp7x_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+ unsigned int flag;
+
+ switch (pci->revision) {
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ flag = snd_amd_acp_find_config(pci);
+ if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC)
+ return -ENODEV;
+
+ return sof_pci_probe(pci, pci_id);
+}
+
+static void acp7x_pci_remove(struct pci_dev *pci)
+{
+ sof_pci_remove(pci);
+}
+
+/* PCI IDs */
+static const struct pci_device_id acp7x_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID),
+ .driver_data = (unsigned long)&acp7x_desc},
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, acp7x_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_amd_acp7x_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = acp7x_pci_ids,
+ .probe = acp7x_pci_probe,
+ .remove = acp7x_pci_remove,
+ .driver = {
+ .pm = pm_ptr(&sof_pci_pm),
+ },
+};
+module_pci_driver(snd_sof_pci_amd_acp7x_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("ACP7X SOF Driver");
+MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c
index 8332d4bda558..aeb34310eebd 100644
--- a/sound/soc/sof/intel/hda-ctrl.c
+++ b/sound/soc/sof/intel/hda-ctrl.c
@@ -186,6 +186,7 @@ EXPORT_SYMBOL_NS(hda_dsp_ctrl_clock_power_gating, "SND_SOC_SOF_INTEL_HDA_COMMON"
int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec)
{
struct hdac_bus *bus = sof_to_bus(sdev);
+ struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus);
struct hdac_stream *stream;
int sd_offset, ret = 0;
u32 gctl;
@@ -193,6 +194,16 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec)
if (bus->chip_init)
return 0;
+ /*
+ * The controller reset clears the ACE2+ link DMA stream allocation
+ * constraints; reset the masks to reflect this.
+ */
+ memset(sof_hda->link_dma_active_sdw_mask, 0,
+ sizeof(sof_hda->link_dma_active_sdw_mask));
+ memset(sof_hda->link_dma_active_multi_mask, 0,
+ sizeof(sof_hda->link_dma_active_multi_mask));
+ sof_hda->link_dma_out_hda_used_mask = 0;
+
hda_codec_set_codec_wakeup(sdev, true);
hda_dsp_ctrl_misc_clock_gating(sdev, false);
@@ -223,6 +234,14 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec)
/* Accept unsolicited responses */
snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
+ /* Perform a one-time enumeration of the Multi-Link capability */
+ ret = hda_bus_ml_init(bus);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: failed to enumerate multi-links\n",
+ __func__);
+ goto err;
+ }
+
if (detect_codec)
hda_codec_detect_mask(sdev);
diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c
index b2c559559962..f0be42048db3 100644
--- a/sound/soc/sof/intel/hda-dai-ops.c
+++ b/sound/soc/sof/intel/hda-dai-ops.c
@@ -20,7 +20,7 @@
/* These ops are only applicable for the HDA DAI's in their current form */
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
/*
- * This function checks if the host dma channel corresponding
+ * This function checks if the host DMA stream corresponding
* to the link DMA stream_tag argument is assigned to one
* of the FEs connected to the BE DAI.
*/
@@ -42,23 +42,53 @@ static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
}
static struct hdac_ext_stream *
-hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream)
+hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream,
+ enum hda_bus_ml_link_type link_type)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus);
struct sof_intel_hda_stream *hda_stream;
const struct sof_intel_dsp_desc *chip;
struct snd_sof_dev *sdev;
struct hdac_ext_stream *res = NULL;
struct hdac_stream *hstream = NULL;
-
int stream_dir = substream->stream;
+ bool is_multi = link_type == HDA_BUS_ML_LINK_HDA || link_type == HDA_BUS_ML_LINK_UAOL;
+ bool is_play = stream_dir == SNDRV_PCM_STREAM_PLAYBACK;
+ bool is_sdw = link_type == HDA_BUS_ML_LINK_SDW;
+ bool is_hda = link_type == HDA_BUS_ML_LINK_HDA;
+ u32 concur_block_mask = 0;
+ u32 seq_block_mask = 0;
+ unsigned int stream_idx;
if (!bus->ppcap) {
dev_err(bus->dev, "stream type not supported\n");
return NULL;
}
+ /*
+ * On ACE2+ the link DMA stream allocator must avoid two HW errata,
+ * see the comment on struct sof_intel_hda_dev.
+ *
+ * - Concurrent cross-direction: SoundWire conflicts with HDA, iDisp
+ * and UAOL on the same physical stream index; SSP and DMIC are safe.
+ * - Sequential playback: a stream index previously used by an HDA/iDisp
+ * link cannot drive any non-HDA/iDisp link in the same direction
+ * until the next controller reset.
+ *
+ * The masks are protected by bus->reg_lock; sample them inside the
+ * lock together with the stream walk to keep the decision atomic
+ * with concurrent allocations and releases.
+ */
guard(spinlock_irq)(&bus->reg_lock);
+
+ if (is_sdw)
+ concur_block_mask = sof_hda->link_dma_active_multi_mask[!stream_dir];
+ else if (is_multi)
+ concur_block_mask = sof_hda->link_dma_active_sdw_mask[!stream_dir];
+ if (is_play && !is_hda)
+ seq_block_mask = sof_hda->link_dma_out_hda_used_mask;
+
list_for_each_entry(hstream, &bus->stream_list, list) {
struct hdac_ext_stream *hext_stream =
stream_to_hdac_ext_stream(hstream);
@@ -69,6 +99,12 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream
sdev = hda_stream->sdev;
chip = get_chip_info(sdev->pdata);
+ stream_idx = hstream->stream_tag - 1;
+
+ /* skip streams blocked by the ACE2+ allocator constraints */
+ if ((concur_block_mask | seq_block_mask) & BIT(stream_idx))
+ continue;
+
/* check if link is available */
if (!hext_stream->link_locked) {
/*
@@ -95,7 +131,7 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream
/*
* This must be a hostless stream.
- * So reserve the host DMA channel.
+ * So reserve the host DMA stream.
*/
hda_stream->host_reserved = 1;
break;
@@ -109,6 +145,16 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream
res->link_locked = 1;
res->link_substream = substream;
+
+ stream_idx = res->hstream.stream_tag - 1;
+ if (is_sdw)
+ sof_hda->link_dma_active_sdw_mask[stream_dir] |= BIT(stream_idx);
+ else if (is_multi)
+ sof_hda->link_dma_active_multi_mask[stream_dir] |= BIT(stream_idx);
+
+ /* persistent OUT HDA/iDisp shadow, cleared only on CRST# */
+ if (is_hda && is_play)
+ sof_hda->link_dma_out_hda_used_mask |= BIT(stream_idx);
}
return res;
@@ -143,11 +189,13 @@ static struct hdac_ext_stream *hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev
static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev,
struct snd_soc_dai *cpu_dai,
- struct snd_pcm_substream *substream)
+ struct snd_pcm_substream *substream,
+ struct hdac_ext_link *hlink)
{
struct hdac_ext_stream *hext_stream;
+ enum hda_bus_ml_link_type link_type = hda_bus_ml_link_get_type(hlink);
- hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
+ hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream, link_type);
if (!hext_stream)
return NULL;
@@ -160,6 +208,22 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai
struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
+ struct sof_intel_hda_dev *sof_hda = sdev->pdata->hw_pdata;
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ int dir = substream->stream;
+ unsigned int stream_idx = hext_stream->hstream.stream_tag - 1;
+
+ /*
+ * Drop the stream index from the per-direction active concurrency masks.
+ * The two masks are mutually exclusive for a given stream/direction
+ * (and a stream of the SSP/DMIC kind appears in neither), so a blind
+ * clear of both is safe and lets us avoid having to remember the
+ * link type at allocation time.
+ */
+ scoped_guard(spinlock_irq, &bus->reg_lock) {
+ sof_hda->link_dma_active_sdw_mask[dir] &= ~BIT(stream_idx);
+ sof_hda->link_dma_active_multi_mask[dir] &= ~BIT(stream_idx);
+ }
snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 15faedeec16d..bb44d4f8a4da 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -188,7 +188,7 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
if (!hext_stream) {
if (ops->assign_hext_stream)
- hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream);
+ hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream, hlink);
}
if (!hext_stream)
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index e9f092f082a1..b9b2bdff4ccb 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -1114,11 +1114,7 @@ static int hda_dsp_s5_quirk(struct snd_sof_dev *sdev)
usleep_range(500, 1000);
/* Restore state for shutdown, back to reset */
- ret = hda_dsp_ctrl_link_reset(sdev, true);
- if (ret < 0)
- return ret;
-
- return ret;
+ return hda_dsp_ctrl_link_reset(sdev, true);
}
int hda_dsp_shutdown_dma_flush(struct snd_sof_dev *sdev)
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index 2b3abcf75d55..4347e71337f9 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -216,9 +216,10 @@ int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int
EXPORT_SYMBOL_NS(hda_cl_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
- bool persistent_buffer, struct hdac_ext_stream *hext_stream)
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool is_iccmax)
{
- return hda_data_stream_cleanup(dev, dmab, persistent_buffer, hext_stream, false);
+ return hda_data_stream_cleanup(dev, dmab, persistent_buffer, hext_stream,
+ is_iccmax, false);
}
EXPORT_SYMBOL_NS(hda_cl_cleanup, "SND_SOC_SOF_INTEL_HDA_COMMON");
@@ -302,7 +303,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
* If the cleanup also fails, we return the initial error
*/
ret1 = hda_cl_cleanup(sdev->dev, &hda->iccmax_dmab,
- persistent_cl_buffer, iccmax_stream);
+ persistent_cl_buffer, iccmax_stream, true);
if (ret1 < 0) {
dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n");
@@ -458,7 +459,7 @@ cleanup:
* If the cleanup also fails, we return the initial error
*/
ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab,
- persistent_cl_buffer, hext_stream);
+ persistent_cl_buffer, hext_stream, false);
if (ret1 < 0) {
dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n");
@@ -587,7 +588,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
cleanup:
/* clean up even in case of error and return the first error */
ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab, persistent_cl_buffer,
- hext_stream);
+ hext_stream, false);
if (ret1 < 0) {
dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__);
diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c
index 92314e3b568a..6f02fb5b70ce 100644
--- a/sound/soc/sof/intel/hda-mlink.c
+++ b/sound/soc/sof/intel/hda-mlink.c
@@ -432,6 +432,10 @@ int hda_bus_ml_init(struct hdac_bus *bus)
if (!bus->mlcap)
return 0;
+ /* Enumeration is a one time operation, skip if already done */
+ if (!list_empty(&bus->hlink_list))
+ return 0;
+
link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1;
dev_dbg(bus->dev, "HDAudio Multi-Link count: %d\n", link_count);
@@ -880,19 +884,6 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
return 0;
} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, "SND_SOC_SOF_HDA_MLINK");
-void hda_bus_ml_put_all(struct hdac_bus *bus)
-{
- struct hdac_ext_link *hlink;
-
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink);
-
- if (!h2link->alt)
- snd_hdac_ext_bus_link_put(bus, hlink);
- }
-}
-EXPORT_SYMBOL_NS(hda_bus_ml_put_all, "SND_SOC_SOF_HDA_MLINK");
-
void hda_bus_ml_reset_losidv(struct hdac_bus *bus)
{
struct hdac_ext_link *hlink;
@@ -903,6 +894,24 @@ void hda_bus_ml_reset_losidv(struct hdac_bus *bus)
}
EXPORT_SYMBOL_NS(hda_bus_ml_reset_losidv, "SND_SOC_SOF_HDA_MLINK");
+enum hda_bus_ml_link_type hda_bus_ml_link_get_type(struct hdac_ext_link *hlink)
+{
+ struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink);
+
+ if (!h2link->alt)
+ return HDA_BUS_ML_LINK_HDA;
+
+ switch (h2link->elid) {
+ case AZX_REG_ML_LEPTR_ID_SDW:
+ return HDA_BUS_ML_LINK_SDW;
+ case AZX_REG_ML_LEPTR_ID_INTEL_UAOL:
+ return HDA_BUS_ML_LINK_UAOL;
+ default:
+ return HDA_BUS_ML_LINK_OTHER;
+ }
+}
+EXPORT_SYMBOL_NS(hda_bus_ml_link_get_type, "SND_SOC_SOF_HDA_MLINK");
+
int hda_bus_ml_resume(struct hdac_bus *bus)
{
struct hdac_ext_link *hlink;
diff --git a/sound/soc/sof/intel/hda-sdw-bpt.c b/sound/soc/sof/intel/hda-sdw-bpt.c
index 7351a0870725..ba9fbd662b85 100644
--- a/sound/soc/sof/intel/hda-sdw-bpt.c
+++ b/sound/soc/sof/intel/hda-sdw-bpt.c
@@ -163,7 +163,7 @@ static int hda_sdw_bpt_dma_deprepare(struct device *dev, struct hdac_ext_stream
u32 mask;
int ret;
- ret = hda_data_stream_cleanup(sdev->dev, dmab_bdl, false, sdw_bpt_stream, true);
+ ret = hda_data_stream_cleanup(sdev->dev, dmab_bdl, false, sdw_bpt_stream, false, true);
if (ret < 0) {
dev_err(sdev->dev, "%s: SDW BPT DMA cleanup failed\n",
__func__);
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index 5c1f3b427cdb..c95230487a1b 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -198,13 +198,18 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
mask = (1 << hstream->index);
+ /* Reset the spib_addr before disabling SPIB */
+ if (!enable)
+ sof_io_write(sdev, hstream->spib_addr, 0);
+
/* enable/disable SPIB for the stream */
snd_sof_dsp_update_bits(sdev, HDA_DSP_SPIB_BAR,
SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, mask,
enable << hstream->index);
/* set the SPIB value */
- sof_io_write(sdev, hstream->spib_addr, size);
+ if (enable)
+ sof_io_write(sdev, hstream->spib_addr, size);
return 0;
}
@@ -608,6 +613,9 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
return ret;
}
+ /* Host DMA is not running */
+ hstream->running = false;
+
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
sd_offset + SOF_HDA_ADSP_REG_SD_STS,
SOF_HDA_CL_DMA_SD_INT_MASK,
@@ -1323,16 +1331,18 @@ out_put:
EXPORT_SYMBOL_NS(hda_data_stream_prepare, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_data_stream_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
- bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool pair)
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream,
+ bool is_iccmax, bool pair)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct hdac_stream *hstream = hdac_stream(hext_stream);
int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
int ret = 0;
- if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK)
+ if (!is_iccmax)
ret = hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0);
- else
+
+ if (hstream->direction == SNDRV_PCM_STREAM_CAPTURE)
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
SOF_HDA_SD_CTL_DMA_START, 0);
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index dc85903b8d46..4dbba9186b29 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -421,6 +421,20 @@ static inline void hda_dsp_sdw_process_mic_privacy(struct snd_sof_dev *sdev) { }
/* pre fw run operations */
int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ const struct sof_intel_dsp_desc *chip = hda->desc;
+ int ret;
+
+ /* Power down DSP if left enabled to ensure a clean boot state. */
+ if (hda_dsp_core_is_enabled(sdev, chip->host_managed_cores_mask)) {
+ dev_dbg(sdev->dev, "DSP core enabled, power down DSP first\n");
+
+ ret = chip->power_down_dsp(sdev);
+ if (ret < 0)
+ dev_warn(sdev->dev,
+ "%s: failed to power down already-enabled DSP\n", __func__);
+ }
+
/* disable clock gating and power gating */
return hda_dsp_ctrl_clock_power_gating(sdev, false);
}
@@ -625,8 +639,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
return ret;
}
- hda_bus_ml_init(bus);
-
/* Skip SoundWire if it is not supported */
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
goto skip_soundwire;
@@ -670,8 +682,6 @@ skip_soundwire:
if (!HDA_IDISP_CODEC(bus->codec_mask))
hda_codec_i915_display_power(sdev, false);
- hda_bus_ml_put_all(bus);
-
return 0;
}
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 3f0966477ace..1609589929a1 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -523,6 +523,29 @@ struct sof_intel_hda_dev {
/* the maximum number of streams (playback + capture) supported */
u32 stream_max;
+ /*
+ * ACE2+ link DMA stream allocation constraints (stream index =
+ * stream_tag - 1, shared between input and output directions). All
+ * masks are cleared by hda_dsp_ctrl_init_chip() on controller reset
+ * (CRST#).
+ *
+ * - Concurrent (cross-direction) constraint: a SoundWire stream and
+ * a HDA/iDisp/UAOL stream cannot share a physical stream index
+ * across directions, the resulting LLP/timestamp values are wrong.
+ * link_dma_active_sdw_mask and link_dma_active_multi_mask
+ * (indexed by SNDRV_PCM_STREAM_*) track currently allocated
+ * streams per direction in each of the conflicting groups; SSP
+ * and DMIC do not participate. Bits are cleared on stream release.
+ *
+ * - Sequential (playback only) constraint: once a HDA/iDisp link
+ * has used a playback stream index, that index cannot drive a
+ * non-HDA/iDisp link in the same direction until the next CRST#.
+ * link_dma_out_hda_used_mask records this.
+ */
+ u32 link_dma_active_sdw_mask[SNDRV_PCM_STREAM_LAST + 1];
+ u32 link_dma_active_multi_mask[SNDRV_PCM_STREAM_LAST + 1];
+ u32 link_dma_out_hda_used_mask;
+
/* PM related */
bool l1_disabled;/* is DMI link L1 disabled? */
@@ -739,7 +762,7 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format,
int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd);
int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
- bool persistent_buffer, struct hdac_ext_stream *hext_stream);
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool is_iccmax);
int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
#define HDA_CL_STREAM_FORMAT 0x40
@@ -911,7 +934,8 @@ hda_data_stream_prepare(struct device *dev, unsigned int format, unsigned int si
bool is_iccmax, bool pair);
int hda_data_stream_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
- bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool pair);
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream,
+ bool is_iccmax, bool pair);
/* common dai driver */
extern struct snd_soc_dai_driver skl_dai[];
@@ -1030,7 +1054,8 @@ struct hda_dai_widget_dma_ops {
struct snd_pcm_substream *substream);
struct hdac_ext_stream *(*assign_hext_stream)(struct snd_sof_dev *sdev,
struct snd_soc_dai *cpu_dai,
- struct snd_pcm_substream *substream);
+ struct snd_pcm_substream *substream,
+ struct hdac_ext_link *hlink);
void (*release_hext_stream)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream);
void (*setup_hext_stream)(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,
diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c
index c1018893750c..549bb4ca73e1 100644
--- a/sound/soc/sof/intel/icl.c
+++ b/sound/soc/sof/intel/icl.c
@@ -9,10 +9,14 @@
* Hardware interface for audio DSP on IceLake.
*/
-#include <linux/kernel.h>
-#include <linux/kconfig.h>
-#include <linux/export.h>
+#include <linux/array_size.h>
#include <linux/bits.h>
+#include <linux/dev_printk.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
#include "../ipc4-priv.h"
#include "../ops.h"
#include "hda.h"
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index 9503d00e6002..3d67d6777f1b 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -236,6 +236,17 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
}
EXPORT_SYMBOL_NS(mtl_enable_interrupts, "SND_SOC_SOF_INTEL_MTL");
+static bool mtl_dsp_is_enabled(struct snd_sof_dev *sdev)
+{
+ int val;
+
+ val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS);
+ if (val & MTL_HFDSSCS_CPA_MASK)
+ return true;
+
+ return false;
+}
+
/* pre fw run operations */
static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
@@ -249,6 +260,18 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
u32 dsppwrsts;
const struct sof_intel_dsp_desc *chip;
+ /* Power down the DSP if it is left enabled to ensure clean boot state */
+ if (mtl_dsp_is_enabled(sdev)) {
+ dev_dbg(sdev->dev, "powering down DSP first\n");
+
+ ret = mtl_power_down_dsp(sdev);
+ if (ret < 0) {
+ dev_warn(sdev->dev,
+ "%s: failed to power down already-enabled DSP\n", __func__);
+ /* Continue anyway to attempt recovery */
+ }
+ }
+
chip = get_chip_info(sdev->pdata);
if (chip->hw_ip_version > SOF_INTEL_ACE_2_0) {
dsppwrctl = PTL_HFPWRCTL2;
diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c
index 90ef5d99f626..143bf0fe8dd9 100644
--- a/sound/soc/sof/ipc3-pcm.c
+++ b/sound/soc/sof/ipc3-pcm.c
@@ -421,6 +421,12 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
dev_dbg(component->dev, "AMD_SDW channels_min: %d channels_max: %d\n",
channels->min, channels->max);
break;
+ case SOF_DAI_AMD_I2S:
+ rate->min = private->dai_config->acp_i2s.fsync_rate;
+ rate->max = private->dai_config->acp_i2s.fsync_rate;
+ channels->min = private->dai_config->acp_i2s.tdm_slots;
+ channels->max = private->dai_config->acp_i2s.tdm_slots;
+ break;
default:
dev_err(component->dev, "Invalid DAI type %d\n", private->dai_config->type);
break;
diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c
index 4e066bbded91..26d85ca9be26 100644
--- a/sound/soc/sof/ipc3-topology.c
+++ b/sound/soc/sof/ipc3-topology.c
@@ -281,7 +281,10 @@ static const struct sof_topology_token acpdmic_tokens[] = {
offsetof(struct sof_ipc_dai_acpdmic_params, pdm_ch)},
};
-/* ACPI2S */
+/*
+ * ACPI2S tokens fill struct sof_ipc_dai_acp_params; SOF_DAI_AMD_I2S (ACPTDM
+ * on ACP7.B/7.F) reuses this tuple group rather than defining a parallel set.
+ */
static const struct sof_topology_token acpi2s_tokens[] = {
{SOF_TKN_AMD_ACPI2S_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc_dai_acp_params, fsync_rate)},
@@ -289,6 +292,8 @@ static const struct sof_topology_token acpi2s_tokens[] = {
offsetof(struct sof_ipc_dai_acp_params, tdm_slots)},
{SOF_TKN_AMD_ACPI2S_TDM_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc_dai_acp_params, tdm_mode)},
+ {SOF_TKN_AMD_ACPI2S_FORMAT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_acp_params, format)},
};
/* MICFIL PDM */
@@ -1363,6 +1368,35 @@ static int sof_link_acp_sdw_load(struct snd_soc_component *scomp, struct snd_sof
return 0;
}
+static int sof_link_acp_i2s_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
+ struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
+{
+ struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
+ struct sof_dai_private_data *private = dai->private;
+ u32 size = sizeof(*config);
+ int ret;
+
+ /* handle master/slave and inverted clocks */
+ sof_dai_set_format(hw_config, config);
+
+ /* init IPC */
+ memset(&config->acp_i2s, 0, sizeof(config->acp_i2s));
+ config->hdr.size = size;
+
+ ret = sof_update_ipc_object(scomp, &config->acp_i2s, SOF_ACPI2S_TOKENS, slink->tuples,
+ slink->num_tuples, size, slink->num_hw_configs);
+ if (ret < 0)
+ return ret;
+
+ dai->number_configs = 1;
+ dai->current_config = 0;
+ private->dai_config = kmemdup(config, size, GFP_KERNEL);
+ if (!private->dai_config)
+ return -ENOMEM;
+
+ return 0;
+}
+
static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
{
@@ -1692,6 +1726,9 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
case SOF_DAI_AMD_SDW:
ret = sof_link_acp_sdw_load(scomp, slink, config, dai);
break;
+ case SOF_DAI_AMD_I2S:
+ ret = sof_link_acp_i2s_load(scomp, slink, config, dai);
+ break;
default:
break;
}
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 6fdfb667cce8..84cd5beb3de9 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -163,11 +163,11 @@ static const struct sof_topology_token comp_ext_tokens[] = {
{SOF_TKN_COMP_SCHED_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_domain,
offsetof(struct snd_sof_widget, comp_domain)},
{SOF_TKN_COMP_DOMAIN_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct snd_sof_widget, dp_domain_id)},
+ offsetof(struct snd_sof_widget, domain_id)},
{SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct snd_sof_widget, dp_heap_bytes)},
+ offsetof(struct snd_sof_widget, heap_bytes)},
{SOF_TKN_COMP_STACK_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct snd_sof_widget, dp_stack_bytes)},
+ offsetof(struct snd_sof_widget, stack_bytes)},
};
static const struct sof_topology_token gain_tokens[] = {
@@ -1127,6 +1127,7 @@ static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
"Invalid number of formats: input: %d, output: %d\n",
src->available_fmt.num_input_formats,
src->available_fmt.num_output_formats);
+ ret = -EINVAL;
goto err;
}
@@ -1179,6 +1180,7 @@ static int sof_ipc4_widget_setup_comp_asrc(struct snd_sof_widget *swidget)
"Invalid number of formats: input: %d, output: %d\n",
asrc->available_fmt.num_input_formats,
asrc->available_fmt.num_output_formats);
+ ret = -EINVAL;
goto err;
}
@@ -1369,6 +1371,22 @@ sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *
pipeline = pipe_widget->private;
pipeline->mem_usage += total;
+ /*
+ * If this is not a Data Processing module instance, add the
+ * required heap sizes to the sum of all module instances belonging
+ * to the same pipeline, and find the maximum stack requirement
+ * among all module instances belonging to the same pipeline.
+ */
+ if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) {
+ pipe_widget->heap_bytes += swidget->heap_bytes;
+ if (pipe_widget->stack_bytes < swidget->stack_bytes)
+ pipe_widget->stack_bytes = swidget->stack_bytes;
+
+ dev_dbg(sdev->dev, "%s mem reqs to %s heap %u stack %u",
+ swidget->widget->name, pipe_widget->widget->name,
+ pipe_widget->heap_bytes, pipe_widget->stack_bytes);
+ }
+
/* Update base_config->cpc from the module manifest */
sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config);
@@ -1686,6 +1704,8 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
pipeline->mem_usage = 0;
+ pipe_widget->heap_bytes = 0;
+ pipe_widget->stack_bytes = 0;
if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) {
if (pipeline->use_chain_dma) {
@@ -3083,27 +3103,47 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr
return 0;
}
-static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev,
- struct snd_sof_widget *swidget,
- struct sof_ipc4_msg *msg,
- void *ipc_data, u32 ipc_size,
- void **new_data)
+static void sof_ipc4_add_init_ext_dp_memory_data(struct snd_sof_dev *sdev,
+ struct snd_sof_widget *swidget,
+ u32 *payload, u32 *ext_pos,
+ struct sof_ipc4_module_init_ext_object **hdr)
+{
+ /* Add memory_data if comp_domain indicates DP */
+ if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) {
+ struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data;
+
+ *hdr = (struct sof_ipc4_module_init_ext_object *)&payload[*ext_pos];
+ (*hdr)->header =
+ SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA) |
+ SOF_IPC4_MOD_INIT_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*dp_mem_data),
+ sizeof(u32)));
+ *ext_pos += DIV_ROUND_UP(sizeof(**hdr), sizeof(u32));
+ dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[*ext_pos];
+ dp_mem_data->domain_id = swidget->domain_id;
+ dp_mem_data->stack_bytes = swidget->stack_bytes;
+ dp_mem_data->heap_bytes = swidget->heap_bytes;
+ *ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32));
+ }
+}
+
+static int sof_ipc4_widget_mod_init_msg_payload(struct snd_sof_dev *sdev,
+ struct snd_sof_widget *swidget,
+ struct sof_ipc4_msg *msg,
+ void *ipc_data, u32 ipc_size,
+ void **new_data)
{
- struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data;
struct sof_ipc4_module_init_ext_init *ext_init;
- struct sof_ipc4_module_init_ext_object *hdr;
+ struct sof_ipc4_module_init_ext_object *hdr = NULL;
int new_size;
u32 *payload;
u32 ext_pos;
- /* For the moment the only reason for adding init_ext_init payload is DP
- * memory data. If both stack and heap size are 0 (= use default), then
- * there is no need for init_ext_init payload.
+ /*
+ * Only DP widgets currently add init-ext objects here. Avoid allocating
+ * a max-sized payload buffer for widgets that will immediately return 0.
*/
- if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) {
- msg->extension &= ~SOF_IPC4_MOD_EXT_EXTENDED_INIT_MASK;
+ if (swidget->comp_domain != SOF_COMP_DOMAIN_DP)
return 0;
- }
payload = kzalloc(sdev->ipc->max_payload_size, GFP_KERNEL);
if (!payload)
@@ -3111,27 +3151,26 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev,
/* Add ext_init first and set objects array flag to 1 */
ext_init = (struct sof_ipc4_module_init_ext_init *)payload;
- ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK;
ext_pos = DIV_ROUND_UP(sizeof(*ext_init), sizeof(u32));
/* Add object array objects after ext_init */
- /* Add dp_memory_data if comp_domain indicates DP */
- if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) {
- hdr = (struct sof_ipc4_module_init_ext_object *)&payload[ext_pos];
- hdr->header = SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK |
- SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA) |
- SOF_IPC4_MOD_INIT_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*dp_mem_data),
- sizeof(u32)));
- ext_pos += DIV_ROUND_UP(sizeof(*hdr), sizeof(u32));
- dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[ext_pos];
- dp_mem_data->domain_id = swidget->dp_domain_id;
- dp_mem_data->stack_bytes = swidget->dp_stack_bytes;
- dp_mem_data->heap_bytes = swidget->dp_heap_bytes;
- ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32));
+ sof_ipc4_add_init_ext_dp_memory_data(sdev, swidget, payload, &ext_pos, &hdr);
+
+ /* Add following object array items here */
+
+ if (!hdr) {
+ /*
+ * NOTE: Remove this early bail out, when struct
+ * sof_ipc4_module_init_ext_init alone has some
+ * function.
+ */
+ kfree(payload);
+ return 0;
}
- /* If another array object is added, remember clear previous OBJ_LAST bit */
+ ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK;
+ hdr->header |= SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK;
/* Calculate final size and check that it fits to max payload size */
new_size = ext_pos * sizeof(u32) + ipc_size;
@@ -3154,6 +3193,69 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev,
return new_size;
}
+static void sof_ipc4_widget_pipe_ext_obj_memory_data(struct snd_sof_dev *sdev,
+ struct snd_sof_widget *swidget,
+ u32 *payload, u32 *ext_pos,
+ struct sof_ipc4_glb_pipe_ext_object **hdr)
+{
+ struct sof_ipc4_glb_pipe_ext_obj_memory_data *mem_data;
+
+ *hdr = (struct sof_ipc4_glb_pipe_ext_object *)&payload[*ext_pos];
+ (*hdr)->header =
+ SOF_IPC4_GLB_PIPE_EXT_OBJ_ID(SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA) |
+ SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*mem_data),
+ sizeof(u32)));
+ *ext_pos += DIV_ROUND_UP(sizeof(**hdr), sizeof(u32));
+ mem_data = (struct sof_ipc4_glb_pipe_ext_obj_memory_data *)&payload[*ext_pos];
+ mem_data->domain_id = swidget->domain_id;
+ mem_data->stack_bytes = swidget->stack_bytes;
+ mem_data->heap_bytes = swidget->heap_bytes;
+ *ext_pos += DIV_ROUND_UP(sizeof(*mem_data), sizeof(u32));
+
+ dev_dbg(sdev->dev,
+ "%s; domain_id %u stack %u heap %u bytes",
+ swidget->widget->name, mem_data->domain_id, mem_data->stack_bytes,
+ mem_data->heap_bytes);
+}
+
+static int sof_ipc4_widget_pipe_create_msg_payload(struct snd_sof_dev *sdev,
+ struct snd_sof_widget *swidget,
+ struct sof_ipc4_msg *msg,
+ void **new_data)
+{
+ struct sof_ipc4_glb_pipe_payload *payload_hdr;
+ struct sof_ipc4_glb_pipe_ext_object *hdr = NULL;
+ u32 *payload;
+ u32 ext_pos;
+
+ payload = kzalloc(sdev->ipc->max_payload_size, GFP_KERNEL);
+ if (!payload)
+ return -ENOMEM;
+
+ /* Add sof_ipc4_glb_pipe_payload and set array bit to 1 */
+ payload_hdr = (struct sof_ipc4_glb_pipe_payload *)payload;
+ payload_hdr->word0 |= SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_MASK;
+ ext_pos = DIV_ROUND_UP(sizeof(*payload_hdr), sizeof(u32));
+
+ sof_ipc4_widget_pipe_ext_obj_memory_data(sdev, swidget, payload, &ext_pos, &hdr);
+ /* Add following array objects here */
+
+ /* Mark end of object array */
+ hdr->header |= SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_MASK;
+
+ /* Put total payload size in words to the payload header */
+ payload_hdr->word0 |= SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS(ext_pos);
+ *new_data = payload;
+
+ /* Update msg extension bits according to the payload changes */
+ msg->extension |= SOF_IPC4_GLB_PIPE_PAYLOAD_MASK;
+
+ dev_dbg(sdev->dev, "%s: payload word0 %#x", swidget->widget->name,
+ payload_hdr->word0);
+
+ return ext_pos * sizeof(int32_t);
+}
+
static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
@@ -3340,8 +3442,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
swidget->widget->name, swidget->pipeline_id, module_id,
swidget->instance_id, swidget->core);
- ret = sof_ipc4_widget_setup_msg_payload(sdev, swidget, msg, ipc_data, ipc_size,
- &ext_data);
+ ret = sof_ipc4_widget_mod_init_msg_payload(sdev, swidget, msg, ipc_data, ipc_size,
+ &ext_data);
if (ret < 0)
goto fail;
@@ -3353,6 +3455,17 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
dev_dbg(sdev->dev, "Create pipeline %s (pipe %d) - instance %d, core %d\n",
swidget->widget->name, swidget->pipeline_id,
swidget->instance_id, swidget->core);
+
+ msg->extension &= ~SOF_IPC4_GLB_PIPE_PAYLOAD_MASK;
+ ret = sof_ipc4_widget_pipe_create_msg_payload(sdev, swidget, msg,
+ &ext_data);
+ if (ret < 0)
+ goto fail;
+
+ if (ret > 0) {
+ ipc_size = ret;
+ ipc_data = ext_data;
+ }
}
msg->data_size = ipc_size;
@@ -3410,6 +3523,8 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
swidget->widget->name);
pipeline->mem_usage = 0;
+ swidget->heap_bytes = 0;
+ swidget->stack_bytes = 0;
pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
ida_free(&pipeline_ida, swidget->instance_id);
swidget->instance_id = -EINVAL;
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index a289c1d8f3ff..54bf0236a127 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -167,7 +167,7 @@ struct sof_ipc4_pipeline {
};
/**
- * struct sof_ipc4_multi_pipeline_data - multi pipeline trigger IPC data
+ * struct ipc4_pipeline_set_state_data - multi pipeline trigger IPC data
* @count: Number of pipelines to be triggered
* @pipeline_instance_ids: Flexible array of IDs of the pipelines to be triggered
*/
@@ -210,7 +210,7 @@ struct sof_ipc4_available_audio_format {
* @node_id: ID of Gateway Node
* @dma_buffer_size: Preferred Gateway DMA buffer size (in bytes)
* @config_length: Length of gateway node configuration blob specified in #config_data
- * config_data: Gateway node configuration blob
+ * @config_data: Gateway node configuration blob
*/
struct sof_copier_gateway_cfg {
uint32_t node_id;
@@ -285,7 +285,9 @@ struct sof_ipc4_dma_stream_ch_map {
struct sof_ipc4_dma_config {
uint8_t dma_method;
uint8_t pre_allocated_by_host;
+ /* private: */
uint16_t rsvd;
+ /* public: */
uint32_t dma_channel_id;
uint32_t stream_id;
struct sof_ipc4_dma_stream_ch_map dma_stream_channel_map;
@@ -296,7 +298,7 @@ struct sof_ipc4_dma_config {
#define SOF_IPC4_GTW_DMA_CONFIG_ID 0x1000
/**
- * struct sof_ipc4_dma_config: DMA configuration
+ * struct sof_ipc4_dma_config_tlv - DMA configuration
* @type: set to SOF_IPC4_GTW_DMA_CONFIG_ID
* @length: sizeof(struct sof_ipc4_dma_config) + dma_config.dma_priv_config_size
* @dma_config: actual DMA configuration
@@ -321,6 +323,7 @@ struct sof_ipc4_alh_configuration_blob {
* @data: IPC copier data
* @copier_config: Copier + blob
* @ipc_config_size: Size of copier_config
+ * @ipc_config_data: Copier module config data
* @available_fmt: Available audio format
* @frame_fmt: frame format
* @msg: message structure for copier
diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c
index c9c6c0c52c62..e77f73390bd8 100644
--- a/sound/soc/sof/ipc4.c
+++ b/sound/soc/sof/ipc4.c
@@ -289,6 +289,89 @@ static void sof_ipc4_dump_payload(struct snd_sof_dev *sdev,
16, 4, ipc_data, size, false);
}
+static const char *sof_ipc4_resource_type_str(u32 type)
+{
+ switch (type) {
+ case SOF_IPC4_MODULE_INSTANCE:
+ return "resource: MODULE_INSTANCE";
+ case SOF_IPC4_PIPELINE:
+ return "resource: PIPELINE";
+ case SOF_IPC4_GATEWAY:
+ return "resource: GATEWAY";
+ case SOF_IPC4_EDF_TASK:
+ return "resource: EDF_TASK";
+ case SOF_IPC4_INVALID_RESOURCE_TYPE:
+ return "Resource is invalid";
+ default:
+ return "Unknown resource type";
+ }
+}
+
+static const char *sof_ipc4_resource_event_type_str(u32 event_type)
+{
+ switch (event_type) {
+ case SOF_IPC4_MIXER_UNDERRUN_DETECTED:
+ return "event: MIXER_UNDERRUN_DETECTED";
+ case SOF_IPC4_PROCESS_DATA_ERROR:
+ return "event: PROCESS_DATA_ERROR";
+ case SOF_IPC4_GATEWAY_UNDERRUN_DETECTED:
+ return "event: GATEWAY_UNDERRUN_DETECTED";
+ case SOF_IPC4_GATEWAY_OVERRUN_DETECTED:
+ return "event: GATEWAY_OVERRUN_DETECTED";
+ default:
+ return "Unknown event type";
+ }
+}
+
+static void sof_ipc4_resource_event_handler(struct snd_sof_dev *sdev,
+ struct sof_ipc4_msg *ipc4_msg)
+{
+ struct sof_ipc4_notify_resource_data *data = ipc4_msg->data_ptr;
+
+ /* Print event details */
+ switch (data->event_type) {
+ case SOF_IPC4_MIXER_UNDERRUN_DETECTED:
+ dev_dbg(sdev->dev, "%s (%u): eos %u, mixed %u, expected %u\n",
+ sof_ipc4_resource_event_type_str(data->event_type),
+ data->event_type, data->data.mixer_underrun.eos_flag,
+ data->data.mixer_underrun.data_mixed,
+ data->data.mixer_underrun.expected_data_mixed);
+ break;
+ case SOF_IPC4_PROCESS_DATA_ERROR:
+ dev_dbg(sdev->dev, "%s (%u): error_code %#x\n",
+ sof_ipc4_resource_event_type_str(data->event_type),
+ data->event_type, data->data.process_data_error.error_code);
+ break;
+ case SOF_IPC4_GATEWAY_UNDERRUN_DETECTED:
+ case SOF_IPC4_GATEWAY_OVERRUN_DETECTED:
+ dev_dbg(sdev->dev, "%s (%u)\n",
+ sof_ipc4_resource_event_type_str(data->event_type),
+ data->event_type);
+ break;
+ default:
+ dev_dbg(sdev->dev, "%s (%u): raw dws %#x %#x %#x %#x %#x %#x\n",
+ sof_ipc4_resource_event_type_str(data->event_type),
+ data->event_type,
+ data->data.dws[0], data->data.dws[1], data->data.dws[2],
+ data->data.dws[3], data->data.dws[4], data->data.dws[5]);
+ break;
+ }
+
+ /* Print resource details */
+ if (data->resource_type == SOF_IPC4_MODULE_INSTANCE) {
+ u32 module_id = SOF_IPC4_MOD_ID_GET(data->resource_id);
+ u32 instance_id = SOF_IPC4_MOD_INSTANCE_GET(data->resource_id);
+
+ dev_dbg(sdev->dev, "%s (%u), module_id %u, instance_id %u\n",
+ sof_ipc4_resource_type_str(data->resource_type),
+ data->resource_type, module_id, instance_id);
+ } else if (data->resource_type != SOF_IPC4_INVALID_RESOURCE_TYPE) {
+ dev_dbg(sdev->dev, "%s (%u), id %u\n",
+ sof_ipc4_resource_type_str(data->resource_type),
+ data->resource_type, data->resource_id);
+ }
+}
+
static int sof_ipc4_get_reply(struct snd_sof_dev *sdev)
{
struct snd_sof_ipc_msg *msg = sdev->msg;
@@ -734,6 +817,7 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev)
break;
case SOF_IPC4_NOTIFY_RESOURCE_EVENT:
data_size = sizeof(struct sof_ipc4_notify_resource_data);
+ handler_func = sof_ipc4_resource_event_handler;
break;
case SOF_IPC4_NOTIFY_LOG_BUFFER_STATUS:
sof_ipc4_mtrace_update_pos(sdev, SOF_IPC4_LOG_CORE_GET(ipc4_msg->primary));
diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c
index 11a95dba3c9c..34744f8ae34a 100644
--- a/sound/soc/sof/nocodec.c
+++ b/sound/soc/sof/nocodec.c
@@ -21,12 +21,13 @@ static struct snd_soc_card sof_nocodec_card = {
static int sof_nocodec_bes_setup(struct device *dev,
struct snd_soc_dai_driver *drv,
struct snd_soc_dai_link *links,
- int link_num, struct snd_soc_card *card)
+ int link_num)
{
+ struct snd_soc_card *card = &sof_nocodec_card;
struct snd_soc_dai_link_component *dlc;
int i;
- if (!drv || !links || !card)
+ if (!drv || !links)
return -EINVAL;
/* set up BE dai_links */
@@ -67,10 +68,10 @@ static int sof_nocodec_bes_setup(struct device *dev,
return 0;
}
-static int sof_nocodec_setup(struct device *dev,
- u32 num_dai_drivers,
- struct snd_soc_dai_driver *dai_drivers)
+static int sof_nocodec_setup(struct device *dev, struct snd_soc_acpi_mach *mach)
{
+ u32 num_dai_drivers = mach->mach_params.num_dai_drivers;
+ struct snd_soc_dai_driver *dai_drivers = mach->mach_params.dai_drivers;
struct snd_soc_dai_link *links;
/* create dummy BE dai_links */
@@ -78,7 +79,7 @@ static int sof_nocodec_setup(struct device *dev,
if (!links)
return -ENOMEM;
- return sof_nocodec_bes_setup(dev, dai_drivers, links, num_dai_drivers, &sof_nocodec_card);
+ return sof_nocodec_bes_setup(dev, dai_drivers, links, num_dai_drivers);
}
static int sof_nocodec_probe(struct platform_device *pdev)
@@ -92,8 +93,7 @@ static int sof_nocodec_probe(struct platform_device *pdev)
snd_soc_card_set_topology_name(card, "sof");
- ret = sof_nocodec_setup(card->dev, mach->mach_params.num_dai_drivers,
- mach->mach_params.dai_drivers);
+ ret = sof_nocodec_setup(card->dev, mach);
if (ret < 0)
return ret;
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index b2071edeaea6..f748d072109a 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -62,7 +62,7 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream)
* To avoid sending IPC before the previous IPC is handled, we
* schedule delayed work here to call the snd_pcm_period_elapsed().
*/
- schedule_work(&spcm->stream[substream->stream].period_elapsed_work);
+ queue_work(system_highpri_wq, &spcm->stream[substream->stream].period_elapsed_work);
}
EXPORT_SYMBOL(snd_sof_pcm_period_elapsed);
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 138e5fcc2dd0..ae95efc9be1c 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -459,10 +459,10 @@ struct snd_sof_widget {
/* Scheduling domain (enum sof_comp_domain), unset, Low Latency, or Data Processing */
u32 comp_domain;
- /* The values below are added to mod_init pay load if comp_domain indicates DP component */
- u32 dp_domain_id; /* DP process userspace domain ID */
- u32 dp_stack_bytes; /* DP process stack size requirement in bytes */
- u32 dp_heap_bytes; /* DP process heap size requirement in bytes */
+ /* Module instance's memory configuration. */
+ u32 domain_id; /* Module instance's userspace domain ID */
+ u32 stack_bytes; /* Module instance's stack size requirement */
+ u32 heap_bytes; /* Module instance's heap size requirement */
struct snd_soc_dapm_widget *widget;
struct list_head list; /* list in sdev widget list */
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index 42a2d90bb705..6fd69ba11c41 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -309,7 +309,7 @@ static const struct sof_dai_types sof_dais[] = {
{"ACPHS_VIRTUAL", SOF_DAI_AMD_HS_VIRTUAL},
{"MICFIL", SOF_DAI_IMX_MICFIL},
{"ACP_SDW", SOF_DAI_AMD_SDW},
-
+ {"ACPTDM", SOF_DAI_AMD_I2S},
};
static enum sof_ipc_dai_type find_dai(const char *name)
@@ -1102,7 +1102,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp,
full = NULL;
partial = NULL;
- list_for_each_entry(rtd, &card->rtd_list, list) {
+ for_each_card_rtds(card, rtd) {
/* does stream match DAI link ? */
if (rtd->dai_link->stream_name) {
if (!strcmp(rtd->dai_link->stream_name, w->sname)) {
@@ -1167,7 +1167,7 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp,
else
return;
- list_for_each_entry(rtd, &card->rtd_list, list) {
+ for_each_card_rtds(card, rtd) {
/* does stream match DAI link ? */
if (!rtd->dai_link->stream_name ||
!strstr(rtd->dai_link->stream_name, sname))
@@ -1943,8 +1943,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
private->array, le32_to_cpu(private->size));
if (ret < 0) {
dev_err(scomp->dev, "Failed tp parse common DAI link tokens\n");
- kfree(slink);
- return ret;
+ goto free_slink;
}
token_list = tplg_ops ? tplg_ops->token_list : NULL;
@@ -1995,6 +1994,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
case SOF_DAI_AMD_HS:
case SOF_DAI_AMD_SP_VIRTUAL:
case SOF_DAI_AMD_HS_VIRTUAL:
+ case SOF_DAI_AMD_I2S:
token_id = SOF_ACPI2S_TOKENS;
num_tuples += token_list[SOF_ACPI2S_TOKENS].count;
break;
@@ -2013,8 +2013,8 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
/* allocate memory for tuples array */
slink->tuples = kzalloc_objs(*slink->tuples, num_tuples);
if (!slink->tuples) {
- kfree(slink);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto free_slink;
}
if (token_list[SOF_DAI_LINK_TOKENS].tokens) {
@@ -2070,6 +2070,7 @@ out:
err:
kfree(slink->tuples);
+free_slink:
kfree(slink);
return ret;
diff --git a/sound/soc/spacemit/k1_i2s.c b/sound/soc/spacemit/k1_i2s.c
index 8871fc15b29c..2751485ac0b0 100644
--- a/sound/soc/spacemit/k1_i2s.c
+++ b/sound/soc/spacemit/k1_i2s.c
@@ -52,7 +52,7 @@ struct spacemit_i2s_dev {
struct clk *sysclk;
struct clk *bclk;
- struct clk *sspa_clk;
+ struct clk *func_clk;
struct clk *sysclk_div;
struct clk *c_sysclk;
struct clk *c_bclk;
@@ -221,7 +221,7 @@ static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream,
if (ret)
return ret;
- return clk_set_rate(i2s->sspa_clk, bclk_rate);
+ return clk_set_rate(i2s->func_clk, bclk_rate);
}
static int spacemit_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
@@ -335,6 +335,11 @@ static int spacemit_i2s_dai_remove(struct snd_soc_dai *dai)
return 0;
}
+static const u64 spacemit_i2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = {
.probe = spacemit_i2s_dai_probe,
.remove = spacemit_i2s_dai_remove,
@@ -343,6 +348,8 @@ static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = {
.set_sysclk = spacemit_i2s_set_sysclk,
.set_fmt = spacemit_i2s_set_fmt,
.trigger = spacemit_i2s_trigger,
+ .auto_selectable_formats = &spacemit_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver spacemit_i2s_dai = {
@@ -445,14 +452,14 @@ static int spacemit_i2s_probe(struct platform_device *pdev)
if (IS_ERR(i2s->bclk))
return dev_err_probe(i2s->dev, PTR_ERR(i2s->bclk), "failed to enable bit clock\n");
- clk = devm_clk_get_enabled(i2s->dev, "sspa_bus");
+ clk = devm_clk_get_enabled(i2s->dev, "bus");
if (IS_ERR(clk))
- return dev_err_probe(i2s->dev, PTR_ERR(clk), "failed to enable sspa_bus clock\n");
+ return dev_err_probe(i2s->dev, PTR_ERR(clk), "failed to enable bus clock\n");
- i2s->sspa_clk = devm_clk_get_enabled(i2s->dev, "sspa");
- if (IS_ERR(i2s->sspa_clk))
- return dev_err_probe(i2s->dev, PTR_ERR(i2s->sspa_clk),
- "failed to enable sspa clock\n");
+ i2s->func_clk = devm_clk_get_enabled(i2s->dev, "func");
+ if (IS_ERR(i2s->func_clk))
+ return dev_err_probe(i2s->dev, PTR_ERR(i2s->func_clk),
+ "failed to enable func clock\n");
i2s->sysclk_div = devm_clk_get_optional_enabled(i2s->dev, "sysclk_div");
if (IS_ERR(i2s->sysclk_div))
diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c
index b31b120a85de..dd1e176193af 100644
--- a/sound/soc/spear/spdif_in.c
+++ b/sound/soc/spear/spdif_in.c
@@ -55,7 +55,7 @@ static int spdif_in_dai_probe(struct snd_soc_dai *dai)
struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
host->dma_params_rx.filter_data = &host->dma_params;
- dai->capture_dma_data = &host->dma_params_rx;
+ snd_soc_dai_dma_data_set_capture(dai, &host->dma_params_rx);
return 0;
}
@@ -150,12 +150,12 @@ static int spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
static const struct snd_soc_dai_ops spdif_in_dai_ops = {
.shutdown = spdif_in_shutdown,
+ .probe = spdif_in_dai_probe,
.trigger = spdif_in_trigger,
.hw_params = spdif_in_hw_params,
};
static struct snd_soc_dai_driver spdif_in_dai = {
- .probe = spdif_in_dai_probe,
.capture = {
.channels_min = 2,
.channels_max = 2,
@@ -218,10 +218,8 @@ static int spdif_in_probe(struct platform_device *pdev)
host->io_base = io_base;
host->irq = platform_get_irq(pdev, 0);
- if (host->irq < 0) {
- dev_warn(&pdev->dev, "failed to get IRQ: %d\n", host->irq);
+ if (host->irq < 0)
return host->irq;
- }
host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk))
@@ -243,10 +241,8 @@ static int spdif_in_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, host->irq, spdif_in_irq, 0,
"spdif-in", host);
- if (ret) {
- dev_warn(&pdev->dev, "request_irq failed\n");
+ if (ret)
return ret;
- }
ret = devm_snd_soc_register_component(&pdev->dev, &spdif_in_component,
&spdif_in_dai, 1);
diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c
index c06f09c646a8..01dc2cef7448 100644
--- a/sound/soc/spear/spdif_out.c
+++ b/sound/soc/spear/spdif_out.c
@@ -249,6 +249,7 @@ static int spdif_soc_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops spdif_out_dai_ops = {
+ .probe = spdif_soc_dai_probe,
.mute_stream = spdif_mute,
.startup = spdif_out_startup,
.shutdown = spdif_out_shutdown,
@@ -266,7 +267,6 @@ static struct snd_soc_dai_driver spdif_out_dai = {
SNDRV_PCM_RATE_192000),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
- .probe = spdif_soc_dai_probe,
.ops = &spdif_out_dai_ops,
};
diff --git a/sound/soc/sprd/sprd-mcdt.c b/sound/soc/sprd/sprd-mcdt.c
index 5f3a2a7bce31..d9a7bbd6c0b6 100644
--- a/sound/soc/sprd/sprd-mcdt.c
+++ b/sound/soc/sprd/sprd-mcdt.c
@@ -931,10 +931,8 @@ static int sprd_mcdt_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, irq, sprd_mcdt_irq_handler,
0, "sprd-mcdt", mcdt);
- if (ret) {
- dev_err(&pdev->dev, "Failed to request MCDT IRQ\n");
+ if (ret)
return ret;
- }
sprd_mcdt_init_chans(mcdt, res);
diff --git a/sound/soc/sprd/sprd-pcm-dma.c b/sound/soc/sprd/sprd-pcm-dma.c
index cbf5bf82d96e..f509a4601de2 100644
--- a/sound/soc/sprd/sprd-pcm-dma.c
+++ b/sound/soc/sprd/sprd-pcm-dma.c
@@ -469,8 +469,6 @@ static int sprd_soc_platform_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(&pdev->dev, &sprd_soc_component,
NULL, 0);
- if (ret)
- dev_err(&pdev->dev, "could not register platform:%d\n", ret);
return ret;
}
diff --git a/sound/soc/starfive/jh7110_pwmdac.c b/sound/soc/starfive/jh7110_pwmdac.c
index a603dd17931c..5953c3a4e373 100644
--- a/sound/soc/starfive/jh7110_pwmdac.c
+++ b/sound/soc/starfive/jh7110_pwmdac.c
@@ -477,25 +477,22 @@ static int jh7110_pwmdac_probe(struct platform_device *pdev)
&jh7110_pwmdac_component,
&jh7110_pwmdac_dai, 1);
if (ret)
- return dev_err_probe(&pdev->dev, ret, "failed to register dai\n");
+ return ret;
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (ret)
- return dev_err_probe(&pdev->dev, ret, "failed to register pcm\n");
+ return ret;
pm_runtime_enable(dev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
ret = jh7110_pwmdac_runtime_resume(&pdev->dev);
- if (ret)
- goto err_pm_disable;
+ if (ret) {
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+ }
}
return 0;
-
-err_pm_disable:
- pm_runtime_disable(&pdev->dev);
-
- return ret;
}
static void jh7110_pwmdac_remove(struct platform_device *pdev)
diff --git a/sound/soc/starfive/jh7110_tdm.c b/sound/soc/starfive/jh7110_tdm.c
index afdcde7df91a..f7522bfbe8e6 100644
--- a/sound/soc/starfive/jh7110_tdm.c
+++ b/sound/soc/starfive/jh7110_tdm.c
@@ -559,10 +559,8 @@ static int jh7110_tdm_clk_reset_get(struct platform_device *pdev,
tdm->clks[5].id = "tdm";
ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(tdm->clks), tdm->clks);
- if (ret) {
- dev_err(&pdev->dev, "Failed to get tdm clocks\n");
+ if (ret)
return ret;
- }
tdm->resets = devm_reset_control_array_get_exclusive(&pdev->dev);
if (IS_ERR(tdm->resets)) {
@@ -589,42 +587,33 @@ static int jh7110_tdm_probe(struct platform_device *pdev)
tdm->dev = &pdev->dev;
ret = jh7110_tdm_clk_reset_get(pdev, tdm);
- if (ret) {
- dev_err(&pdev->dev, "Failed to enable audio-tdm clock\n");
+ if (ret)
return ret;
- }
jh7110_tdm_init_params(tdm);
dev_set_drvdata(&pdev->dev, tdm);
ret = devm_snd_soc_register_component(&pdev->dev, &jh7110_tdm_component,
&jh7110_tdm_dai, 1);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register dai\n");
+ if (ret)
return ret;
- }
ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
&jh7110_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_COMPAT);
- if (ret) {
- dev_err(&pdev->dev, "Could not register pcm: %d\n", ret);
+ if (ret)
return ret;
- }
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
ret = jh7110_tdm_runtime_resume(&pdev->dev);
- if (ret)
- goto err_pm_disable;
+ if (ret) {
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+ }
}
return 0;
-
-err_pm_disable:
- pm_runtime_disable(&pdev->dev);
-
- return ret;
}
static void jh7110_tdm_dev_remove(struct platform_device *pdev)
diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index 66efb9a0acb9..73c6460a6327 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -360,11 +360,8 @@ static int stm32_adfsdm_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(&pdev->dev,
&stm32_adfsdm_soc_platform,
NULL, 0);
- if (ret < 0) {
- dev_err(&pdev->dev, "%s: Failed to register PCM platform\n",
- __func__);
+ if (ret < 0)
return ret;
- }
pm_runtime_enable(&pdev->dev);
diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index ae9e25657f3f..83b51893b37c 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -1238,10 +1238,8 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
ret = devm_request_irq(&pdev->dev, irq, stm32_i2s_isr, 0,
dev_name(&pdev->dev), i2s);
- if (ret) {
- dev_err(&pdev->dev, "irq request returned %d\n", ret);
+ if (ret)
return ret;
- }
/* Reset */
rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
@@ -1295,7 +1293,7 @@ static int stm32_i2s_probe(struct platform_device *pdev)
ret = snd_dmaengine_pcm_register(&pdev->dev, &stm32_i2s_pcm_config, 0);
if (ret)
- return dev_err_probe(&pdev->dev, ret, "PCM DMA register error\n");
+ return ret;
ret = snd_soc_register_component(&pdev->dev, &stm32_i2s_component,
i2s->dai_drv, 1);
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index ea9e8bddd63f..9a201bdb306f 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -1696,19 +1696,15 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, sai->pdata->irq, stm32_sai_isr,
IRQF_SHARED, dev_name(&pdev->dev), sai);
- if (ret) {
- dev_err(&pdev->dev, "IRQ request returned %d\n", ret);
+ if (ret)
goto err_unprepare_pclk;
- }
if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
conf = &stm32_sai_pcm_config_spdif;
ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0);
- if (ret) {
- ret = dev_err_probe(&pdev->dev, ret, "Could not register pcm dma\n");
+ if (ret)
goto err_unprepare_pclk;
- }
ret = snd_soc_register_component(&pdev->dev, &stm32_component,
&sai->cpu_dai_drv, 1);
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index 2f83ca989e68..e0fef47a227e 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -970,10 +970,8 @@ static int stm32_spdifrx_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, spdifrx->irq, stm32_spdifrx_isr, 0,
dev_name(&pdev->dev), spdifrx);
- if (ret) {
- dev_err(&pdev->dev, "IRQ request returned %d\n", ret);
+ if (ret)
return ret;
- }
rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
if (IS_ERR(rst))
@@ -987,7 +985,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev)
pcm_config = &stm32_spdifrx_pcm_config;
ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config, 0);
if (ret)
- return dev_err_probe(&pdev->dev, ret, "PCM DMA register error\n");
+ return ret;
ret = snd_soc_register_component(&pdev->dev,
&stm32_spdifrx_component,
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 93f511fb6190..ff56700a9fe9 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -22,13 +22,13 @@
#include <linux/gpio/consumer.h>
#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
-#include <sound/initval.h>
-#include <sound/dmaengine_pcm.h>
/* Codec DAC digital controls and FIFO registers */
#define SUN4I_CODEC_DAC_DPC (0x00)
@@ -2317,67 +2317,54 @@ static int sun4i_codec_probe(struct platform_device *pdev)
scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
quirks->regmap_config);
- if (IS_ERR(scodec->regmap)) {
- dev_err(&pdev->dev, "Failed to create our regmap\n");
- return PTR_ERR(scodec->regmap);
- }
+ if (IS_ERR(scodec->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->regmap),
+ "Failed to create our regmap\n");
/* Get the clocks from the DT */
scodec->clk_apb = devm_clk_get_enabled(&pdev->dev, "apb");
- if (IS_ERR(scodec->clk_apb)) {
- dev_err(&pdev->dev, "Failed to get the APB clock\n");
- return PTR_ERR(scodec->clk_apb);
- }
+ if (IS_ERR(scodec->clk_apb))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->clk_apb),
+ "Failed to get the APB clock\n");
scodec->clk_module = devm_clk_get(&pdev->dev, "codec");
- if (IS_ERR(scodec->clk_module)) {
- dev_err(&pdev->dev, "Failed to get the module clock\n");
- return PTR_ERR(scodec->clk_module);
- }
+ if (IS_ERR(scodec->clk_module))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->clk_module),
+ "Failed to get the module clock\n");
if (quirks->has_reset) {
scodec->rst = devm_reset_control_get_exclusive_deasserted(&pdev->dev, NULL);
- if (IS_ERR(scodec->rst)) {
- dev_err(&pdev->dev, "Failed to get reset control\n");
- return PTR_ERR(scodec->rst);
- }
+ if (IS_ERR(scodec->rst))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->rst),
+ "Failed to get reset control\n");
}
scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
GPIOD_OUT_LOW);
- if (IS_ERR(scodec->gpio_pa)) {
- ret = PTR_ERR(scodec->gpio_pa);
- dev_err_probe(&pdev->dev, ret, "Failed to get pa gpio\n");
- return ret;
- }
+ if (IS_ERR(scodec->gpio_pa))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->gpio_pa),
+ "Failed to get pa gpio\n");
+
scodec->gpio_hp = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN);
- if (IS_ERR(scodec->gpio_hp)) {
- ret = PTR_ERR(scodec->gpio_hp);
- dev_err_probe(&pdev->dev, ret, "Failed to get hp-det gpio\n");
- return ret;
- }
+ if (IS_ERR(scodec->gpio_hp))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->gpio_hp),
+ "Failed to get hp-det gpio\n");
/* reg_field setup */
scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev,
scodec->regmap,
quirks->reg_adc_fifoc);
- if (IS_ERR(scodec->reg_adc_fifoc)) {
- ret = PTR_ERR(scodec->reg_adc_fifoc);
- dev_err(&pdev->dev, "Failed to create regmap fields: %d\n",
- ret);
- return ret;
- }
+ if (IS_ERR(scodec->reg_adc_fifoc))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->reg_adc_fifoc),
+ "Failed to create regmap fields\n");
scodec->reg_dac_fifoc = devm_regmap_field_alloc(&pdev->dev,
scodec->regmap,
quirks->reg_dac_fifoc);
- if (IS_ERR(scodec->reg_dac_fifoc)) {
- ret = PTR_ERR(scodec->reg_dac_fifoc);
- dev_err(&pdev->dev, "Failed to create regmap fields: %d\n",
- ret);
- return ret;
- }
+ if (IS_ERR(scodec->reg_dac_fifoc))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->reg_dac_fifoc),
+ "Failed to create regmap fields\n");
/* DMA configuration for TX FIFO */
scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
@@ -2394,39 +2381,29 @@ static int sun4i_codec_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec,
&sun4i_codec_dai, 1);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register our codec\n");
+ if (ret)
return ret;
- }
ret = devm_snd_soc_register_component(&pdev->dev,
&sun4i_codec_component,
&dummy_cpu_dai, 1);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register our DAI\n");
+ if (ret)
return ret;
- }
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register against DMAEngine\n");
+ if (ret)
return ret;
- }
card = quirks->create_card(&pdev->dev);
- if (IS_ERR(card)) {
- ret = PTR_ERR(card);
- dev_err(&pdev->dev, "Failed to create our card\n");
- return ret;
- }
+ if (IS_ERR(card))
+ return PTR_ERR(card);
snd_soc_card_set_drvdata(card, scodec);
ret = snd_soc_register_card(card);
- if (ret) {
- dev_err_probe(&pdev->dev, ret, "Failed to register our card\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to register our card\n");
return 0;
}
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 40de99a34bc3..716fa4d872ff 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -1550,30 +1550,26 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
}
i2s->bus_clk = devm_clk_get(&pdev->dev, "apb");
- if (IS_ERR(i2s->bus_clk)) {
- dev_err(&pdev->dev, "Can't get our bus clock\n");
- return PTR_ERR(i2s->bus_clk);
- }
+ if (IS_ERR(i2s->bus_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->bus_clk),
+ "Can't get our bus clock\n");
i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
i2s->variant->sun4i_i2s_regmap);
- if (IS_ERR(i2s->regmap)) {
- dev_err(&pdev->dev, "Regmap initialisation failed\n");
- return PTR_ERR(i2s->regmap);
- }
+ if (IS_ERR(i2s->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->regmap),
+ "Regmap initialisation failed\n");
i2s->mod_clk = devm_clk_get(&pdev->dev, "mod");
- if (IS_ERR(i2s->mod_clk)) {
- dev_err(&pdev->dev, "Can't get our mod clock\n");
- return PTR_ERR(i2s->mod_clk);
- }
+ if (IS_ERR(i2s->mod_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->mod_clk),
+ "Can't get our mod clock\n");
if (i2s->variant->has_reset) {
i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
- if (IS_ERR(i2s->rst)) {
- dev_err(&pdev->dev, "Failed to get reset control\n");
- return PTR_ERR(i2s->rst);
- }
+ if (IS_ERR(i2s->rst))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->rst),
+ "Failed to get reset control\n");
}
if (!IS_ERR(i2s->rst)) {
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index c2ec19437cd7..d979bb00312f 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -684,26 +684,23 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
host->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&sun4i_spdif_regmap_config);
- if (IS_ERR(host->regmap)) {
- dev_err(&pdev->dev, "failed to initialise regmap.\n");
- return PTR_ERR(host->regmap);
- }
+ if (IS_ERR(host->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(host->regmap),
+ "failed to initialise regmap.\n");
/* Clocks */
host->apb_clk = devm_clk_get(&pdev->dev, "apb");
- if (IS_ERR(host->apb_clk)) {
- dev_err(&pdev->dev, "failed to get a apb clock.\n");
- return PTR_ERR(host->apb_clk);
- }
+ if (IS_ERR(host->apb_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(host->apb_clk),
+ "failed to get a apb clock.\n");
if (quirks->tx_clk_name)
tx_clk_name = quirks->tx_clk_name;
host->spdif_clk = devm_clk_get(&pdev->dev, tx_clk_name);
- if (IS_ERR(host->spdif_clk)) {
- dev_err(&pdev->dev, "failed to get the \"%s\" clock.\n",
- tx_clk_name);
- return PTR_ERR(host->spdif_clk);
- }
+ if (IS_ERR(host->spdif_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(host->spdif_clk),
+ "failed to get the \"%s\" clock.\n",
+ tx_clk_name);
host->dma_params_tx.addr = res->start + quirks->reg_dac_txdata;
host->dma_params_tx.maxburst = 8;
diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c
index 9f5b067a8ccc..50c0dee8c433 100644
--- a/sound/soc/sunxi/sun50i-codec-analog.c
+++ b/sound/soc/sunxi/sun50i-codec-analog.c
@@ -551,16 +551,13 @@ static int sun50i_codec_analog_probe(struct platform_device *pdev)
bool enable;
base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base)) {
- dev_err(&pdev->dev, "Failed to map the registers\n");
+ if (IS_ERR(base))
return PTR_ERR(base);
- }
regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base);
- if (IS_ERR(regmap)) {
- dev_err(&pdev->dev, "Failed to create regmap\n");
- return PTR_ERR(regmap);
- }
+ if (IS_ERR(regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(regmap),
+ "Failed to create regmap\n");
enable = device_property_read_bool(&pdev->dev,
"allwinner,internal-bias-resistor");
diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c
index 2024e2b2553e..3335855c6311 100644
--- a/sound/soc/sunxi/sun8i-codec-analog.c
+++ b/sound/soc/sunxi/sun8i-codec-analog.c
@@ -822,16 +822,13 @@ static int sun8i_codec_analog_probe(struct platform_device *pdev)
void __iomem *base;
base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base)) {
- dev_err(&pdev->dev, "Failed to map the registers\n");
+ if (IS_ERR(base))
return PTR_ERR(base);
- }
regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base);
- if (IS_ERR(regmap)) {
- dev_err(&pdev->dev, "Failed to create regmap\n");
- return PTR_ERR(regmap);
- }
+ if (IS_ERR(regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(regmap),
+ "Failed to create regmap\n");
return devm_snd_soc_register_component(&pdev->dev,
&sun8i_codec_analog_cmpnt_drv,
diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c
index b48cc4a6967b..ea8bc9bcfa67 100644
--- a/sound/soc/tegra/tegra20_das.c
+++ b/sound/soc/tegra/tegra20_das.c
@@ -167,10 +167,9 @@ static int tegra20_das_probe(struct platform_device *pdev)
das->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
&tegra20_das_regmap_config);
- if (IS_ERR(das->regmap)) {
- dev_err(&pdev->dev, "regmap init failed\n");
- return PTR_ERR(das->regmap);
- }
+ if (IS_ERR(das->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(das->regmap),
+ "regmap init failed\n");
tegra20_das_connect_dap_to_dac(das, TEGRA20_DAS_DAP_ID_1,
TEGRA20_DAS_DAP_SEL_DAC1);
diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c
index 15a94196ee1a..e75bf50f8fb0 100644
--- a/sound/soc/tegra/tegra210_adx.c
+++ b/sound/soc/tegra/tegra210_adx.c
@@ -496,16 +496,12 @@ static struct snd_kcontrol_new tegra264_adx_controls[] = {
static int tegra210_adx_component_probe(struct snd_soc_component *component)
{
struct tegra210_adx *adx = snd_soc_component_get_drvdata(component);
- int err = 0;
- if (adx->soc_data->num_controls) {
- err = snd_soc_add_component_controls(component, adx->soc_data->controls,
- adx->soc_data->num_controls);
- if (err)
- dev_err(component->dev, "can't add ADX controls, err: %d\n", err);
- }
+ if (adx->soc_data->num_controls)
+ return snd_soc_add_component_controls(component, adx->soc_data->controls,
+ adx->soc_data->num_controls);
- return err;
+ return 0;
}
static const struct snd_soc_component_driver tegra210_adx_cmpnt = {
diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c
index cc1f9c158191..6a67ce6128b4 100644
--- a/sound/soc/tegra/tegra210_amx.c
+++ b/sound/soc/tegra/tegra210_amx.c
@@ -504,16 +504,12 @@ static struct snd_kcontrol_new tegra264_amx_controls[] = {
static int tegra210_amx_component_probe(struct snd_soc_component *component)
{
struct tegra210_amx *amx = snd_soc_component_get_drvdata(component);
- int err = 0;
- if (amx->soc_data->num_controls) {
- err = snd_soc_add_component_controls(component, amx->soc_data->controls,
- amx->soc_data->num_controls);
- if (err)
- dev_err(component->dev, "can't add AMX controls, err: %d\n", err);
- }
+ if (amx->soc_data->num_controls)
+ return snd_soc_add_component_controls(component, amx->soc_data->controls,
+ amx->soc_data->num_controls);
- return err;
+ return 0;
}
static const struct snd_soc_component_driver tegra210_amx_cmpnt = {
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
index ff8c72fc38c5..e7e26e917291 100644
--- a/sound/soc/tegra/tegra210_i2s.c
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -1078,13 +1078,13 @@ static int tegra210_i2s_probe(struct platform_device *pdev)
"can't retrieve I2S bit clock\n");
/*
- * Not an error, as this clock is needed only when some other I/O
- * requires input clock from current I2S instance, which is
- * configurable from DT.
+ * This clock is optional and is only needed when another I/O uses
+ * the current I2S instance as its input clock, as configured in DT.
*/
- i2s->clk_sync_input = devm_clk_get(dev, "sync_input");
+ i2s->clk_sync_input = devm_clk_get_optional(dev, "sync_input");
if (IS_ERR(i2s->clk_sync_input))
- dev_dbg(dev, "can't retrieve I2S sync input clock\n");
+ return dev_err_probe(dev, PTR_ERR(i2s->clk_sync_input),
+ "can't retrieve I2S sync input clock\n");
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c
index 61252359d5cb..b4f6be2ab4c8 100644
--- a/sound/soc/ti/ams-delta.c
+++ b/sound/soc/ti/ams-delta.c
@@ -562,21 +562,21 @@ static int ams_delta_probe(struct platform_device *pdev)
card->dev = &pdev->dev;
- handset_mute = devm_gpiod_get(card->dev, "handset_mute",
+ handset_mute = devm_gpiod_get(&pdev->dev, "handset_mute",
GPIOD_OUT_HIGH);
if (IS_ERR(handset_mute))
return PTR_ERR(handset_mute);
- handsfree_mute = devm_gpiod_get(card->dev, "handsfree_mute",
+ handsfree_mute = devm_gpiod_get(&pdev->dev, "handsfree_mute",
GPIOD_OUT_HIGH);
if (IS_ERR(handsfree_mute))
return PTR_ERR(handsfree_mute);
ret = snd_soc_register_card(card);
if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
card->dev = NULL;
- return ret;
+ return dev_err_probe(&pdev->dev, ret,
+ "snd_soc_register_card() failed\n");
}
return 0;
}
diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c
index ad514c2e5a25..3156d87a3a12 100644
--- a/sound/soc/ti/davinci-evm.c
+++ b/sound/soc/ti/davinci-evm.c
@@ -245,9 +245,8 @@ static int davinci_evm_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(&evm_soc_card, drvdata);
ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card);
-
if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+ dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n");
goto err_put;
}
diff --git a/sound/soc/ti/j721e-evm.c b/sound/soc/ti/j721e-evm.c
index c214ae0d7b95..600897a3e1c5 100644
--- a/sound/soc/ti/j721e-evm.c
+++ b/sound/soc/ti/j721e-evm.c
@@ -4,6 +4,7 @@
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*/
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -263,7 +264,7 @@ static int j721e_audio_startup(struct snd_pcm_substream *substream)
int ret = 0;
int i;
- guard(mutex)(&priv->mutex);
+ mutex_lock(&priv->mutex);
domain->active++;
@@ -303,6 +304,7 @@ static int j721e_audio_startup(struct snd_pcm_substream *substream)
out:
if (ret)
domain->active--;
+ mutex_unlock(&priv->mutex);
return ret;
}
@@ -868,10 +870,9 @@ static int j721e_soc_probe(struct platform_device *pdev)
card->num_dapm_routes = ARRAY_SIZE(j721e_cpb_dapm_routes);
card->fully_routed = 1;
- if (snd_soc_of_parse_card_name(card, "model")) {
- dev_err(&pdev->dev, "Card name is not provided\n");
- return -ENODEV;
- }
+ ret = snd_soc_of_parse_card_name(card, "model");
+ if (ret)
+ return ret;
link_cnt = 0;
conf_cnt = 0;
diff --git a/sound/soc/ti/omap-abe-twl6040.c b/sound/soc/ti/omap-abe-twl6040.c
index 56aa4b22083b..05239ccc1f41 100644
--- a/sound/soc/ti/omap-abe-twl6040.c
+++ b/sound/soc/ti/omap-abe-twl6040.c
@@ -234,16 +234,13 @@ static int omap_abe_probe(struct platform_device *pdev)
card->dapm_routes = audio_map;
card->num_dapm_routes = ARRAY_SIZE(audio_map);
- if (snd_soc_of_parse_card_name(card, "ti,model")) {
- dev_err(&pdev->dev, "Card name is not provided\n");
- return -ENODEV;
- }
+ ret = snd_soc_of_parse_card_name(card, "ti,model");
+ if (ret)
+ return ret;
ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
- if (ret) {
- dev_err(&pdev->dev, "Error while parsing DAPM routing\n");
+ if (ret)
return ret;
- }
dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
if (!dai_node) {
@@ -299,8 +296,8 @@ static int omap_abe_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret)
- dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
- ret);
+ dev_err_probe(&pdev->dev, ret,
+ "devm_snd_soc_register_card() failed\n");
return ret;
}
diff --git a/sound/soc/ti/omap-dmic.c b/sound/soc/ti/omap-dmic.c
index b795b9f66b0e..c8d791f05ae4 100644
--- a/sound/soc/ti/omap-dmic.c
+++ b/sound/soc/ti/omap-dmic.c
@@ -465,10 +465,9 @@ static int asoc_dmic_probe(struct platform_device *pdev)
mutex_init(&dmic->mutex);
dmic->fclk = devm_clk_get(dmic->dev, "fck");
- if (IS_ERR(dmic->fclk)) {
- dev_err(dmic->dev, "can't get fck\n");
- return -ENODEV;
- }
+ if (IS_ERR(dmic->fclk))
+ return dev_err_probe(dmic->dev, PTR_ERR(dmic->fclk),
+ "can't get fck\n");
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
if (!res) {
diff --git a/sound/soc/ti/omap-hdmi.c b/sound/soc/ti/omap-hdmi.c
index e60f5b483fc5..c3034a8979dd 100644
--- a/sound/soc/ti/omap-hdmi.c
+++ b/sound/soc/ti/omap-hdmi.c
@@ -24,8 +24,6 @@
#define DRV_NAME "omap-hdmi-audio"
struct hdmi_audio_data {
- struct snd_soc_card *card;
-
const struct omap_hdmi_audio_ops *ops;
struct device *dssdev;
struct snd_dmaengine_dai_dma_data dma_data;
@@ -375,12 +373,9 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)
card->dev = dev;
ret = devm_snd_soc_register_card(dev, card);
- if (ret) {
- dev_err(dev, "snd_soc_register_card failed (%d)\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "snd_soc_register_card() failed\n");
- ad->card = card;
snd_soc_card_set_drvdata(card, ad);
dev_set_drvdata(dev, ad);
diff --git a/sound/soc/ti/omap-twl4030.c b/sound/soc/ti/omap-twl4030.c
index 4d80f8a7a947..8a3a792a21c6 100644
--- a/sound/soc/ti/omap-twl4030.c
+++ b/sound/soc/ti/omap-twl4030.c
@@ -17,7 +17,6 @@
*/
#include <linux/platform_device.h>
-#include <linux/platform_data/omap-twl4030.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -29,6 +28,7 @@
#include "omap-mcbsp.h"
struct omap_twl4030 {
+ struct snd_soc_jack_gpio hs_jack_gpio;
struct snd_soc_jack hs_jack;
};
@@ -124,38 +124,18 @@ static struct snd_soc_jack_pin hs_jack_pins[] = {
},
};
-/* Headset jack detection gpios */
-static struct snd_soc_jack_gpio hs_jack_gpios[] = {
- {
- .name = "ti,jack-det",
- .report = SND_JACK_HEADSET,
- .debounce_time = 200,
- },
-};
-
-static inline void twl4030_disconnect_pin(struct snd_soc_dapm_context *dapm,
- int connected, char *pin)
-{
- if (!connected)
- snd_soc_dapm_disable_pin(dapm, pin);
-}
-
static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
- struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev);
+
struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
- int ret = 0;
+ int ret;
/*
* This is a bit of a hack, but the GPIO is optional so we
* only want to add the jack detection if the GPIO is there.
*/
if (of_property_present(card->dev->of_node, "ti,jack-det-gpio")) {
- hs_jack_gpios[0].gpiod_dev = card->dev;
- hs_jack_gpios[0].idx = 0;
-
ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
SND_JACK_HEADSET,
&priv->hs_jack, hs_jack_pins,
@@ -163,36 +143,19 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
if (ret)
return ret;
- ret = snd_soc_jack_add_gpios(&priv->hs_jack,
- ARRAY_SIZE(hs_jack_gpios),
- hs_jack_gpios);
+ priv->hs_jack_gpio.name = "ti,jack-det";
+ priv->hs_jack_gpio.report = SND_JACK_HEADSET;
+ priv->hs_jack_gpio.debounce_time = 200;
+ priv->hs_jack_gpio.gpiod_dev = card->dev;
+ priv->hs_jack_gpio.idx = 0;
+
+ ret = snd_soc_jack_add_gpios(&priv->hs_jack, 1,
+ &priv->hs_jack_gpio);
if (ret)
return ret;
}
- /*
- * NULL pdata means we booted with DT. In this case the routing is
- * provided and the card is fully routed, no need to mark pins.
- */
- if (!pdata || !pdata->custom_routing)
- return ret;
-
- /* Disable not connected paths if not used */
- twl4030_disconnect_pin(dapm, pdata->has_ear, "Earpiece Spk");
- twl4030_disconnect_pin(dapm, pdata->has_hf, "Handsfree Spk");
- twl4030_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
- twl4030_disconnect_pin(dapm, pdata->has_predriv, "Ext Spk");
- twl4030_disconnect_pin(dapm, pdata->has_carkit, "Carkit Spk");
-
- twl4030_disconnect_pin(dapm, pdata->has_mainmic, "Main Mic");
- twl4030_disconnect_pin(dapm, pdata->has_submic, "Sub Mic");
- twl4030_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
- twl4030_disconnect_pin(dapm, pdata->has_carkitmic, "Carkit Mic");
- twl4030_disconnect_pin(dapm, pdata->has_digimic0, "Digital0 Mic");
- twl4030_disconnect_pin(dapm, pdata->has_digimic1, "Digital1 Mic");
- twl4030_disconnect_pin(dapm, pdata->has_linein, "Line In");
-
- return ret;
+ return 0;
}
/* Digital audio interface glue - connects codec <--> CPU */
@@ -237,11 +200,15 @@ static struct snd_soc_card omap_twl4030_card = {
static int omap_twl4030_probe(struct platform_device *pdev)
{
- struct omap_tw4030_pdata *pdata = dev_get_platdata(&pdev->dev);
- struct device_node *node = pdev->dev.of_node;
struct snd_soc_card *card = &omap_twl4030_card;
+ struct device_node *node, *dai_node;
struct omap_twl4030 *priv;
- int ret = 0;
+ struct property *prop;
+ int ret;
+
+ node = pdev->dev.of_node;
+ if (!node)
+ return -ENODEV;
card->dev = &pdev->dev;
@@ -249,69 +216,48 @@ static int omap_twl4030_probe(struct platform_device *pdev)
if (priv == NULL)
return -ENOMEM;
- if (node) {
- struct device_node *dai_node;
- struct property *prop;
-
- if (snd_soc_of_parse_card_name(card, "ti,model")) {
- dev_err(&pdev->dev, "Card name is not provided\n");
- return -ENODEV;
- }
-
- dai_node = of_parse_phandle(node, "ti,mcbsp", 0);
- if (!dai_node) {
- dev_err(&pdev->dev, "McBSP node is not provided\n");
- return -EINVAL;
- }
- omap_twl4030_dai_links[0].cpus->dai_name = NULL;
- omap_twl4030_dai_links[0].cpus->of_node = dai_node;
-
- omap_twl4030_dai_links[0].platforms->name = NULL;
- omap_twl4030_dai_links[0].platforms->of_node = dai_node;
-
- dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0);
- if (!dai_node) {
- card->num_links = 1;
- } else {
- omap_twl4030_dai_links[1].cpus->dai_name = NULL;
- omap_twl4030_dai_links[1].cpus->of_node = dai_node;
-
- omap_twl4030_dai_links[1].platforms->name = NULL;
- omap_twl4030_dai_links[1].platforms->of_node = dai_node;
- }
-
- /* Optional: audio routing can be provided */
- prop = of_find_property(node, "ti,audio-routing", NULL);
- if (prop) {
- ret = snd_soc_of_parse_audio_routing(card,
- "ti,audio-routing");
- if (ret)
- return ret;
-
- card->fully_routed = 1;
- }
- } else if (pdata) {
- if (pdata->card_name) {
- card->name = pdata->card_name;
- } else {
- dev_err(&pdev->dev, "Card name is not provided\n");
- return -ENODEV;
- }
-
- if (!pdata->voice_connected)
- card->num_links = 1;
- } else {
- dev_err(&pdev->dev, "Missing pdata\n");
+ if (snd_soc_of_parse_card_name(card, "ti,model")) {
+ dev_err(&pdev->dev, "Card name is not provided\n");
return -ENODEV;
}
+ dai_node = of_parse_phandle(node, "ti,mcbsp", 0);
+ if (!dai_node) {
+ dev_err(&pdev->dev, "McBSP node is not provided\n");
+ return -EINVAL;
+ }
+ omap_twl4030_dai_links[0].cpus->dai_name = NULL;
+ omap_twl4030_dai_links[0].cpus->of_node = dai_node;
+
+ omap_twl4030_dai_links[0].platforms->name = NULL;
+ omap_twl4030_dai_links[0].platforms->of_node = dai_node;
+
+ dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0);
+ if (!dai_node) {
+ card->num_links = 1;
+ } else {
+ omap_twl4030_dai_links[1].cpus->dai_name = NULL;
+ omap_twl4030_dai_links[1].cpus->of_node = dai_node;
+
+ omap_twl4030_dai_links[1].platforms->name = NULL;
+ omap_twl4030_dai_links[1].platforms->of_node = dai_node;
+ }
+
+ /* Optional: audio routing can be provided */
+ prop = of_find_property(node, "ti,audio-routing", NULL);
+ if (prop) {
+ ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
+ if (ret)
+ return ret;
+
+ card->fully_routed = 1;
+ }
+
snd_soc_card_set_drvdata(card, priv);
ret = devm_snd_soc_register_card(&pdev->dev, card);
- if (ret) {
- dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
- ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "devm_snd_soc_register_card() failed\n");
return 0;
}
diff --git a/sound/soc/ti/rx51.c b/sound/soc/ti/rx51.c
index cfc23e0838c2..b4b26cb0cac5 100644
--- a/sound/soc/ti/rx51.c
+++ b/sound/soc/ti/rx51.c
@@ -358,21 +358,22 @@ static struct snd_soc_card rx51_sound_card = {
static int rx51_soc_probe(struct platform_device *pdev)
{
struct rx51_audio_pdata *pdata;
- struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct snd_soc_card *card = &rx51_sound_card;
int err;
if (!of_machine_is_compatible("nokia,omap3-n900"))
return -ENODEV;
- card->dev = &pdev->dev;
+ card->dev = dev;
if (np) {
struct device_node *dai_node;
dai_node = of_parse_phandle(np, "nokia,cpu-dai", 0);
if (!dai_node) {
- dev_err(card->dev, "McBSP node is not provided\n");
+ dev_err(dev, "McBSP node is not provided\n");
return -EINVAL;
}
rx51_dai[0].cpus->dai_name = NULL;
@@ -382,7 +383,7 @@ static int rx51_soc_probe(struct platform_device *pdev)
dai_node = of_parse_phandle(np, "nokia,audio-codec", 0);
if (!dai_node) {
- dev_err(card->dev, "Codec node is not provided\n");
+ dev_err(dev, "Codec node is not provided\n");
return -EINVAL;
}
rx51_dai[0].codecs->name = NULL;
@@ -390,7 +391,7 @@ static int rx51_soc_probe(struct platform_device *pdev)
dai_node = of_parse_phandle(np, "nokia,audio-codec", 1);
if (!dai_node) {
- dev_err(card->dev, "Auxiliary Codec node is not provided\n");
+ dev_err(dev, "Auxiliary Codec node is not provided\n");
return -EINVAL;
}
rx51_aux_dev[0].dlc.name = NULL;
@@ -400,7 +401,7 @@ static int rx51_soc_probe(struct platform_device *pdev)
dai_node = of_parse_phandle(np, "nokia,headphone-amplifier", 0);
if (!dai_node) {
- dev_err(card->dev, "Headphone amplifier node is not provided\n");
+ dev_err(dev, "Headphone amplifier node is not provided\n");
return -EINVAL;
}
rx51_aux_dev[1].dlc.name = NULL;
@@ -409,40 +410,36 @@ static int rx51_soc_probe(struct platform_device *pdev)
rx51_codec_conf[1].dlc.of_node = dai_node;
}
- pdata = devm_kzalloc(card->dev, sizeof(*pdata), GFP_KERNEL);
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (pdata == NULL)
return -ENOMEM;
snd_soc_card_set_drvdata(card, pdata);
- pdata->tvout_selection_gpio = devm_gpiod_get(card->dev,
+ pdata->tvout_selection_gpio = devm_gpiod_get(dev,
"tvout-selection",
GPIOD_OUT_LOW);
- if (IS_ERR(pdata->tvout_selection_gpio)) {
- dev_err(card->dev, "could not get tvout selection gpio\n");
- return PTR_ERR(pdata->tvout_selection_gpio);
- }
+ if (IS_ERR(pdata->tvout_selection_gpio))
+ return dev_err_probe(dev, PTR_ERR(pdata->tvout_selection_gpio),
+ "could not get tvout selection gpio\n");
- pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch",
+ pdata->eci_sw_gpio = devm_gpiod_get(dev, "eci-switch",
GPIOD_OUT_HIGH);
- if (IS_ERR(pdata->eci_sw_gpio)) {
- dev_err(card->dev, "could not get eci switch gpio\n");
- return PTR_ERR(pdata->eci_sw_gpio);
- }
+ if (IS_ERR(pdata->eci_sw_gpio))
+ return dev_err_probe(dev, PTR_ERR(pdata->eci_sw_gpio),
+ "could not get eci switch gpio\n");
- pdata->speaker_amp_gpio = devm_gpiod_get(card->dev,
+ pdata->speaker_amp_gpio = devm_gpiod_get(dev,
"speaker-amplifier",
GPIOD_OUT_LOW);
- if (IS_ERR(pdata->speaker_amp_gpio)) {
- dev_err(card->dev, "could not get speaker enable gpio\n");
- return PTR_ERR(pdata->speaker_amp_gpio);
- }
-
- err = devm_snd_soc_register_card(card->dev, card);
- if (err) {
- dev_err(card->dev, "snd_soc_register_card failed (%d)\n", err);
- return err;
- }
+ if (IS_ERR(pdata->speaker_amp_gpio))
+ return dev_err_probe(dev, PTR_ERR(pdata->speaker_amp_gpio),
+ "could not get speaker enable gpio\n");
+
+ err = devm_snd_soc_register_card(dev, card);
+ if (err)
+ return dev_err_probe(dev, err,
+ "snd_soc_register_card() failed\n");
return 0;
}
diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c
index d3dba21b2d04..78c82bf42a8f 100644
--- a/sound/soc/uniphier/aio-cpu.c
+++ b/sound/soc/uniphier/aio-cpu.c
@@ -795,16 +795,12 @@ int uniphier_aio_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(dev, &uniphier_aio_component,
chip->chip_spec->dais,
chip->chip_spec->num_dais);
- if (ret) {
- dev_err(dev, "Register component failed.\n");
+ if (ret)
goto err_out_reset;
- }
ret = uniphier_aiodma_soc_register_platform(pdev);
- if (ret) {
- dev_err(dev, "Register platform failed.\n");
+ if (ret)
goto err_out_reset;
- }
return 0;
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
index ae6d326167d1..6d196b4b8802 100644
--- a/sound/soc/ux500/mop500.c
+++ b/sound/soc/ux500/mop500.c
@@ -68,10 +68,11 @@ static void mop500_of_node_put(void)
of_node_put(mop500_dai_links[0].codecs->of_node);
}
-static int mop500_of_probe(struct platform_device *pdev,
- struct device_node *np)
+static int mop500_of_probe(struct snd_soc_card *card)
{
+ struct device *dev = card->dev;
struct device_node *codec_np, *msp_np[2];
+ struct device_node *np = dev->of_node;
int i;
msp_np[0] = of_parse_phandle(np, "stericsson,cpu-dai", 0);
@@ -79,7 +80,7 @@ static int mop500_of_probe(struct platform_device *pdev,
codec_np = of_parse_phandle(np, "stericsson,audio-codec", 0);
if (!(msp_np[0] && msp_np[1] && codec_np)) {
- dev_err(&pdev->dev, "Phandle missing or invalid\n");
+ dev_err(dev, "Phandle missing or invalid\n");
for (i = 0; i < 2; i++)
of_node_put(msp_np[i]);
of_node_put(codec_np);
@@ -95,21 +96,20 @@ static int mop500_of_probe(struct platform_device *pdev,
mop500_dai_links[i].codecs->name = NULL;
}
- snd_soc_of_parse_card_name(&mop500_card, "stericsson,card-name");
+ snd_soc_of_parse_card_name(card, "stericsson,card-name");
return 0;
}
static int mop500_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
int ret;
dev_dbg(&pdev->dev, "%s: Enter.\n", __func__);
mop500_card.dev = &pdev->dev;
- ret = mop500_of_probe(pdev, np);
+ ret = mop500_of_probe(&mop500_card);
if (ret)
return ret;
diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c
index 2a459267f0f9..feb683c55d11 100644
--- a/sound/soc/ux500/mop500_ab8500.c
+++ b/sound/soc/ux500/mop500_ab8500.c
@@ -433,5 +433,5 @@ void mop500_ab8500_remove(struct snd_soc_card *card)
clk_put(drvdata->clk_ptr_ulpclk);
clk_put(drvdata->clk_ptr_intclk);
- snd_soc_card_set_drvdata(card, drvdata);
+ snd_soc_card_set_drvdata(card, NULL);
}
diff --git a/sound/soc/xilinx/xlnx_i2s.c b/sound/soc/xilinx/xlnx_i2s.c
index ca915a001ad5..0676da122edd 100644
--- a/sound/soc/xilinx/xlnx_i2s.c
+++ b/sound/soc/xilinx/xlnx_i2s.c
@@ -185,17 +185,15 @@ static int xlnx_i2s_probe(struct platform_device *pdev)
return PTR_ERR(drv_data->base);
ret = of_property_read_u32(node, "xlnx,num-channels", &drv_data->channels);
- if (ret < 0) {
- dev_err(dev, "cannot get supported channels\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "cannot get supported channels\n");
+
drv_data->channels *= 2;
ret = of_property_read_u32(node, "xlnx,dwidth", &drv_data->data_width);
- if (ret < 0) {
- dev_err(dev, "cannot get data width\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "cannot get data width\n");
+
switch (drv_data->data_width) {
case 16:
format = SNDRV_PCM_FMTBIT_S16_LE;
@@ -233,10 +231,8 @@ static int xlnx_i2s_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(&pdev->dev, &xlnx_i2s_component,
&drv_data->dai_drv, 1);
- if (ret) {
- dev_err(&pdev->dev, "i2s component registration failed\n");
+ if (ret)
return ret;
- }
dev_info(&pdev->dev, "%s DAI registered\n", drv_data->dai_drv.name);
diff --git a/sound/soc/xilinx/xlnx_spdif.c b/sound/soc/xilinx/xlnx_spdif.c
index 017a64ab9f1e..ae05818ba064 100644
--- a/sound/soc/xilinx/xlnx_spdif.c
+++ b/sound/soc/xilinx/xlnx_spdif.c
@@ -249,21 +249,18 @@ static int xlnx_spdif_probe(struct platform_device *pdev)
return -ENOMEM;
ctx->axi_clk = devm_clk_get_enabled(dev, "s_axi_aclk");
- if (IS_ERR(ctx->axi_clk)) {
- ret = PTR_ERR(ctx->axi_clk);
- dev_err(dev, "failed to get s_axi_aclk(%d)\n", ret);
- return ret;
- }
+ if (IS_ERR(ctx->axi_clk))
+ return dev_err_probe(dev, PTR_ERR(ctx->axi_clk),
+ "failed to get s_axi_aclk\n");
ctx->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ctx->base))
return PTR_ERR(ctx->base);
ret = of_property_read_u32(node, "xlnx,spdif-mode", &ctx->mode);
- if (ret < 0) {
- dev_err(dev, "cannot get SPDIF mode\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "cannot get SPDIF mode\n");
+
if (ctx->mode) {
dai_drv = &xlnx_spdif_tx_dai;
} else {
@@ -274,29 +271,23 @@ static int xlnx_spdif_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, ret,
xlnx_spdifrx_irq_handler,
0, "XLNX_SPDIF_RX", ctx);
- if (ret) {
- dev_err(dev, "spdif rx irq request failed\n");
- return -ENODEV;
- }
+ if (ret)
+ return ret;
init_waitqueue_head(&ctx->chsts_q);
dai_drv = &xlnx_spdif_rx_dai;
}
ret = of_property_read_u32(node, "xlnx,aud_clk_i", &ctx->aclk);
- if (ret < 0) {
- dev_err(dev, "cannot get aud_clk_i value\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "cannot get aud_clk_i value\n");
dev_set_drvdata(dev, ctx);
ret = devm_snd_soc_register_component(dev, &xlnx_spdif_component,
dai_drv, 1);
- if (ret) {
- dev_err(dev, "SPDIF component registration failed\n");
+ if (ret)
return ret;
- }
writel(XSPDIF_SOFT_RESET_VALUE, ctx->base + XSPDIF_SOFT_RESET_REG);
dev_info(dev, "%s DAI registered\n", dai_drv->name);
diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c
index 9ad86c54e3ea..fd0990201b40 100644
--- a/sound/soc/xtensa/xtfpga-i2s.c
+++ b/sound/soc/xtensa/xtfpga-i2s.c
@@ -533,34 +533,25 @@ static int xtfpga_i2s_probe(struct platform_device *pdev)
int err, irq;
i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
- if (!i2s) {
- err = -ENOMEM;
- goto err;
- }
+ if (!i2s)
+ return -ENOMEM;
+
platform_set_drvdata(pdev, i2s);
i2s->dev = &pdev->dev;
dev_dbg(&pdev->dev, "dev: %p, i2s: %p\n", &pdev->dev, i2s);
i2s->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(i2s->regs)) {
- err = PTR_ERR(i2s->regs);
- goto err;
- }
+ if (IS_ERR(i2s->regs))
+ return PTR_ERR(i2s->regs);
i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->regs,
&xtfpga_i2s_regmap_config);
- if (IS_ERR(i2s->regmap)) {
- dev_err(&pdev->dev, "regmap init failed\n");
- err = PTR_ERR(i2s->regmap);
- goto err;
- }
+ if (IS_ERR(i2s->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->regmap), "regmap init failed\n");
i2s->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(i2s->clk)) {
- dev_err(&pdev->dev, "couldn't get clock\n");
- err = PTR_ERR(i2s->clk);
- goto err;
- }
+ if (IS_ERR(i2s->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->clk), "couldn't get clock\n");
regmap_write(i2s->regmap, XTFPGA_I2S_CONFIG,
(0x1 << XTFPGA_I2S_CONFIG_CHANNEL_BASE));
@@ -568,41 +559,34 @@ static int xtfpga_i2s_probe(struct platform_device *pdev)
regmap_write(i2s->regmap, XTFPGA_I2S_INT_MASK, XTFPGA_I2S_INT_UNDERRUN);
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- err = irq;
- goto err;
- }
+ if (irq < 0)
+ return irq;
+
err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
xtfpga_i2s_threaded_irq_handler,
IRQF_SHARED | IRQF_ONESHOT,
pdev->name, i2s);
- if (err < 0) {
- dev_err(&pdev->dev, "request_irq failed\n");
- goto err;
- }
+ if (err < 0)
+ return err;
err = devm_snd_soc_register_component(&pdev->dev,
&xtfpga_i2s_component,
xtfpga_i2s_dai,
ARRAY_SIZE(xtfpga_i2s_dai));
- if (err < 0) {
- dev_err(&pdev->dev, "couldn't register component\n");
- goto err;
- }
+ if (err < 0)
+ return err;
+
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
err = xtfpga_i2s_runtime_resume(&pdev->dev);
- if (err)
- goto err_pm_disable;
+ if (err) {
+ pm_runtime_disable(&pdev->dev);
+ return err;
+ }
}
- return 0;
-err_pm_disable:
- pm_runtime_disable(&pdev->dev);
-err:
- dev_err(&pdev->dev, "%s: err = %d\n", __func__, err);
- return err;
+ return 0;
}
static void xtfpga_i2s_remove(struct platform_device *pdev)