summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/adi,ssm2305.txt14
-rw-r--r--Documentation/devicetree/bindings/sound/adi,ssm2305.yaml46
-rw-r--r--Documentation/devicetree/bindings/sound/awinic,aw88395.yaml4
-rw-r--r--Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml3
-rw-r--r--Documentation/devicetree/bindings/sound/hisilicon,hi6210-i2s.txt42
-rw-r--r--Documentation/devicetree/bindings/sound/hisilicon,hi6210-i2s.yaml80
-rw-r--r--Documentation/devicetree/bindings/sound/imx-audio-card.yaml9
-rw-r--r--Documentation/devicetree/bindings/sound/mediatek,mt2701-wm8960.yaml4
-rw-r--r--Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml4
-rw-r--r--Documentation/devicetree/bindings/sound/mediatek,mt8173-rt5650-rt5514.yaml41
-rw-r--r--Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml4
-rw-r--r--Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt15
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra-audio-cpcap.yaml90
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max9808x.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8962.yaml88
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.txt22
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml60
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip,rockchip-audio-max98090.yaml59
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip-max98090.txt42
-rw-r--r--Documentation/devicetree/bindings/sound/simple-card.yaml14
-rw-r--r--Documentation/devicetree/bindings/sound/tdm-slot.txt29
-rw-r--r--Documentation/devicetree/bindings/sound/tdm-slot.yaml52
-rw-r--r--Documentation/devicetree/bindings/sound/ti,tas2770.yaml4
-rw-r--r--arch/arm/mach-s3c/mach-crag6410-module.c6
-rw-r--r--drivers/firmware/cirrus/cs_dsp.c117
-rw-r--r--drivers/firmware/cirrus/cs_dsp.h4
-rw-r--r--drivers/firmware/cirrus/test/cs_dsp_test_bin.c25
-rw-r--r--drivers/firmware/cirrus/test/cs_dsp_test_bin_error.c22
-rw-r--r--drivers/firmware/cirrus/test/cs_dsp_test_control_cache.c5
-rw-r--r--drivers/firmware/cirrus/test/cs_dsp_test_control_parse.c5
-rw-r--r--drivers/firmware/cirrus/test/cs_dsp_test_control_rw.c5
-rw-r--r--drivers/firmware/cirrus/test/cs_dsp_test_wmfw.c32
-rw-r--r--drivers/firmware/cirrus/test/cs_dsp_test_wmfw_error.c30
-rw-r--r--drivers/mfd/cs42l43-i2c.c7
-rw-r--r--drivers/mfd/cs42l43-sdw.c4
-rw-r--r--drivers/mfd/cs42l43.c93
-rw-r--r--drivers/mfd/cs42l43.h2
-rw-r--r--include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h12
-rw-r--r--include/linux/firmware/cirrus/cs_dsp.h3
-rw-r--r--include/linux/mfd/arizona/pdata.h10
-rw-r--r--include/linux/mfd/cs42l43-regs.h76
-rw-r--r--include/linux/mfd/cs42l43.h1
-rw-r--r--include/sound/cs35l56.h7
-rw-r--r--include/sound/sdca_asoc.h43
-rw-r--r--include/sound/simple_card_utils.h6
-rw-r--r--include/sound/soc-component.h11
-rw-r--r--include/sound/soc-dai.h22
-rw-r--r--include/sound/soc-dapm.h1
-rw-r--r--include/sound/soc.h33
-rw-r--r--include/sound/soc_sdw_utils.h5
-rw-r--r--include/sound/uda1380.h19
-rw-r--r--sound/hda/codecs/side-codecs/Kconfig1
-rw-r--r--sound/soc/amd/Kconfig10
-rw-r--r--sound/soc/amd/Makefile1
-rw-r--r--sound/soc/amd/acp-da7219-max98357a.c5
-rw-r--r--sound/soc/amd/acp-es8336.c1
-rw-r--r--sound/soc/amd/acp-pcm-dma.c2
-rw-r--r--sound/soc/amd/acp-rt5645.c22
-rw-r--r--sound/soc/amd/acp/acp-platform.c2
-rw-r--r--sound/soc/amd/acp/acp-sdw-legacy-mach.c10
-rw-r--r--sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c1
-rw-r--r--sound/soc/amd/acp3x-rt5682-max9836.c1
-rw-r--r--sound/soc/amd/include/acp_2_2_d.h18
-rw-r--r--sound/soc/amd/include/acp_2_2_enum.h18
-rw-r--r--sound/soc/amd/include/acp_2_2_sh_mask.h18
-rw-r--r--sound/soc/amd/ps/ps-pdm-dma.c3
-rw-r--r--sound/soc/amd/ps/ps-sdw-dma.c2
-rw-r--r--sound/soc/amd/raven/acp3x-pcm-dma.c2
-rw-r--r--sound/soc/amd/renoir/acp3x-pdm-dma.c2
-rw-r--r--sound/soc/amd/rpl/Makefile5
-rw-r--r--sound/soc/amd/rpl/rpl-pci-acp6x.c227
-rw-r--r--sound/soc/amd/rpl/rpl_acp6x.h36
-rw-r--r--sound/soc/amd/rpl/rpl_acp6x_chip_offset_byte.h30
-rw-r--r--sound/soc/amd/vangogh/acp5x-pcm-dma.c2
-rw-r--r--sound/soc/amd/yc/acp6x-mach.c28
-rw-r--r--sound/soc/amd/yc/acp6x-pdm-dma.c2
-rw-r--r--sound/soc/amd/yc/pci-acp6x.c12
-rw-r--r--sound/soc/apple/Kconfig1
-rw-r--r--sound/soc/apple/Makefile1
-rw-r--r--sound/soc/apple/mca.c4
-rw-r--r--sound/soc/atmel/atmel-pcm-pdc.c2
-rw-r--r--sound/soc/au1x/dbdma2.c2
-rw-r--r--sound/soc/au1x/dma.c2
-rw-r--r--sound/soc/bcm/bcm63xx-pcm-whistler.c2
-rw-r--r--sound/soc/bcm/cygnus-pcm.c2
-rw-r--r--sound/soc/codecs/Kconfig64
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/ak5558.c1
-rw-r--r--sound/soc/codecs/arizona-jack.c95
-rw-r--r--sound/soc/codecs/arizona.h1
-rw-r--r--sound/soc/codecs/aw87390.c3
-rw-r--r--sound/soc/codecs/aw88081.c3
-rw-r--r--sound/soc/codecs/aw88166.c12
-rw-r--r--sound/soc/codecs/aw88261.c16
-rw-r--r--sound/soc/codecs/cros_ec_codec.c2
-rw-r--r--sound/soc/codecs/cs-amp-lib-test.c1
-rw-r--r--sound/soc/codecs/cs-amp-lib.c2
-rw-r--r--sound/soc/codecs/cs35l41.c5
-rw-r--r--sound/soc/codecs/cs35l45.c3
-rw-r--r--sound/soc/codecs/cs35l56-sdw.c34
-rw-r--r--sound/soc/codecs/cs35l56-shared-test.c240
-rw-r--r--sound/soc/codecs/cs35l56-shared.c9
-rw-r--r--sound/soc/codecs/cs35l56-test.c101
-rw-r--r--sound/soc/codecs/cs35l56.c99
-rw-r--r--sound/soc/codecs/cs35l56.h4
-rw-r--r--sound/soc/codecs/cs4270.c6
-rw-r--r--sound/soc/codecs/cs42l43.c756
-rw-r--r--sound/soc/codecs/cs42l43.h4
-rw-r--r--sound/soc/codecs/cs42l84.c20
-rw-r--r--sound/soc/codecs/cs42xx8-i2c.c5
-rw-r--r--sound/soc/codecs/cs42xx8.c27
-rw-r--r--sound/soc/codecs/cs42xx8.h5
-rw-r--r--sound/soc/codecs/da7219-aad.c3
-rw-r--r--sound/soc/codecs/da7219-aad.h5
-rw-r--r--sound/soc/codecs/jz4725b.c18
-rw-r--r--sound/soc/codecs/jz4760.c20
-rw-r--r--sound/soc/codecs/jz4770.c20
-rw-r--r--sound/soc/codecs/max98390.c6
-rw-r--r--sound/soc/codecs/max98520.c4
-rw-r--r--sound/soc/codecs/nau8315.c1
-rw-r--r--sound/soc/codecs/peb2466.c19
-rw-r--r--sound/soc/codecs/rt1318.c1
-rw-r--r--sound/soc/codecs/rt1320-sdw.c67
-rw-r--r--sound/soc/codecs/rt1320-sdw.h14
-rw-r--r--sound/soc/codecs/rt5514-spi.c2
-rw-r--r--sound/soc/codecs/rt5575.c1
-rw-r--r--sound/soc/codecs/rt5640.c5
-rw-r--r--sound/soc/codecs/rt5677-spi.c9
-rw-r--r--sound/soc/codecs/rt5677.c40
-rw-r--r--sound/soc/codecs/rt5677.h2
-rw-r--r--sound/soc/codecs/sta529.c5
-rw-r--r--sound/soc/codecs/tas2552.c10
-rw-r--r--sound/soc/codecs/tas2764.c95
-rw-r--r--sound/soc/codecs/tas2764.h11
-rw-r--r--sound/soc/codecs/tas2770.c75
-rw-r--r--sound/soc/codecs/tas2770.h12
-rw-r--r--sound/soc/codecs/tas2781-i2c.c104
-rw-r--r--sound/soc/codecs/tlv320dac33.c10
-rw-r--r--sound/soc/codecs/ts3a227e.c1
-rw-r--r--sound/soc/codecs/uda1380.c112
-rw-r--r--sound/soc/codecs/wcd-clsh-v2.c3
-rw-r--r--sound/soc/codecs/wcd9335.c2
-rw-r--r--sound/soc/codecs/wm_adsp.c246
-rw-r--r--sound/soc/codecs/wm_adsp.h20
-rw-r--r--sound/soc/codecs/wm_adsp_fw_find_test.c1223
-rw-r--r--sound/soc/dwc/dwc-i2s.c5
-rw-r--r--sound/soc/dwc/dwc-pcm.c7
-rw-r--r--sound/soc/dwc/local.h5
-rw-r--r--sound/soc/fsl/efika-audio-fabric.c5
-rw-r--r--sound/soc/fsl/fsl_asrc_dma.c2
-rw-r--r--sound/soc/fsl/fsl_dma.c12
-rw-r--r--sound/soc/fsl/fsl_easrc.c125
-rw-r--r--sound/soc/fsl/fsl_micfil.c72
-rw-r--r--sound/soc/fsl/fsl_qmc_audio.c6
-rw-r--r--sound/soc/fsl/fsl_sai.c66
-rw-r--r--sound/soc/fsl/fsl_sai.h4
-rw-r--r--sound/soc/fsl/fsl_utils.c131
-rw-r--r--sound/soc/fsl/fsl_utils.h48
-rw-r--r--sound/soc/fsl/fsl_xcvr.c86
-rw-r--r--sound/soc/fsl/fsl_xcvr.h18
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c4
-rw-r--r--sound/soc/fsl/imx-pcm-rpmsg.c2
-rw-r--r--sound/soc/fsl/imx-rpmsg.c48
-rw-r--r--sound/soc/fsl/mpc5200_dma.c13
-rw-r--r--sound/soc/generic/audio-graph-card.c2
-rw-r--r--sound/soc/generic/simple-card-utils.c95
-rw-r--r--sound/soc/generic/simple-card.c52
-rw-r--r--sound/soc/generic/test-component.c12
-rw-r--r--sound/soc/google/chv3-i2s.c6
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c2
-rw-r--r--sound/soc/intel/avs/pcm.c8
-rw-r--r--sound/soc/intel/avs/probes.c2
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c4
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c4
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c6
-rw-r--r--sound/soc/intel/boards/ehl_rt5660.c2
-rw-r--r--sound/soc/intel/catpt/Makefile1
-rw-r--r--sound/soc/intel/catpt/core.h2
-rw-r--r--sound/soc/intel/catpt/device.c2
-rw-r--r--sound/soc/intel/catpt/ipc.c3
-rw-r--r--sound/soc/intel/catpt/loader.c2
-rw-r--r--sound/soc/intel/catpt/messages.h3
-rw-r--r--sound/soc/intel/catpt/pcm.c390
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-ptl-match.c100
-rw-r--r--sound/soc/intel/keembay/Makefile1
-rw-r--r--sound/soc/intel/keembay/kmb_platform.c2
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c2
-rw-r--r--sound/soc/loongson/loongson_dma.c2
-rw-r--r--sound/soc/mediatek/common/mtk-afe-platform-driver.c2
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-afe-pcm.c2
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-afe-pcm.c4
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c5
-rw-r--r--sound/soc/pxa/pxa-ssp.c2
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c2
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c2
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c2
-rw-r--r--sound/soc/qcom/common.c6
-rw-r--r--sound/soc/qcom/common.h3
-rw-r--r--sound/soc/qcom/lpass-platform.c2
-rw-r--r--sound/soc/qcom/lpass.h3
-rw-r--r--sound/soc/qcom/qdsp6/audioreach.c65
-rw-r--r--sound/soc/qcom/qdsp6/audioreach.h5
-rw-r--r--sound/soc/qcom/qdsp6/q6afe-dai.c6
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.c8
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.h3
-rw-r--r--sound/soc/qcom/qdsp6/q6apm-dai.c115
-rw-r--r--sound/soc/qcom/qdsp6/q6apm-lpass-dais.c48
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.c182
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.h20
-rw-r--r--sound/soc/qcom/qdsp6/q6asm-dai.c2
-rw-r--r--sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c76
-rw-r--r--sound/soc/qcom/qdsp6/topology.c8
-rw-r--r--sound/soc/renesas/dma-sh7760.c5
-rw-r--r--sound/soc/renesas/fsi.c2
-rw-r--r--sound/soc/renesas/rcar/core.c2
-rw-r--r--sound/soc/renesas/rcar/msiof.c2
-rw-r--r--sound/soc/renesas/rz-ssi.c2
-rw-r--r--sound/soc/renesas/siu_pcm.c5
-rw-r--r--sound/soc/rockchip/rockchip_sai.c4
-rw-r--r--sound/soc/samsung/idma.c4
-rw-r--r--sound/soc/samsung/spdif.c29
-rw-r--r--sound/soc/sdca/sdca_asoc.c118
-rw-r--r--sound/soc/sdca/sdca_class.c36
-rw-r--r--sound/soc/sdca/sdca_class_function.c12
-rw-r--r--sound/soc/sdca/sdca_fdl.c5
-rw-r--r--sound/soc/sdca/sdca_functions.c6
-rw-r--r--sound/soc/sdca/sdca_interrupts.c24
-rw-r--r--sound/soc/sdw_utils/Makefile1
-rw-r--r--sound/soc/sdw_utils/soc_sdw_cs42l43.c10
-rw-r--r--sound/soc/sdw_utils/soc_sdw_cs47l47.c80
-rw-r--r--sound/soc/sdw_utils/soc_sdw_rt_dmic.c46
-rw-r--r--sound/soc/sdw_utils/soc_sdw_utils.c234
-rw-r--r--sound/soc/soc-component.c25
-rw-r--r--sound/soc/soc-compress.c4
-rw-r--r--sound/soc/soc-core.c84
-rw-r--r--sound/soc/soc-dai.c40
-rw-r--r--sound/soc/soc-dapm.c11
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c4
-rw-r--r--sound/soc/soc-ops.c83
-rw-r--r--sound/soc/soc-pcm.c4
-rw-r--r--sound/soc/soc-topology.c73
-rw-r--r--sound/soc/sof/compress.c15
-rw-r--r--sound/soc/sof/intel/hda-stream.c10
-rw-r--r--sound/soc/sof/intel/hda.c17
-rw-r--r--sound/soc/sof/ipc4-topology.c13
-rw-r--r--sound/soc/sof/pcm.c10
-rw-r--r--sound/soc/sof/sof-audio.h13
-rw-r--r--sound/soc/sof/sof-priv.h2
-rw-r--r--sound/soc/sof/topology.c36
-rw-r--r--sound/soc/spear/spdif_in.c5
-rw-r--r--sound/soc/spear/spdif_out.c5
-rw-r--r--sound/soc/spear/spear_pcm.c5
-rw-r--r--sound/soc/sprd/sprd-pcm-dma.c2
-rw-r--r--sound/soc/starfive/Makefile1
-rw-r--r--sound/soc/sti/uniperif_player.c9
-rw-r--r--sound/soc/stm/stm32_adfsdm.c2
-rw-r--r--sound/soc/sunxi/sun4i-spdif.c13
-rw-r--r--sound/soc/tegra/Kconfig19
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/tegra186_asrc.c14
-rw-r--r--sound/soc/tegra/tegra186_dspk.c22
-rw-r--r--sound/soc/tegra/tegra20_spdif.h2
-rw-r--r--sound/soc/tegra/tegra210_admaif.c28
-rw-r--r--sound/soc/tegra/tegra210_adx.c20
-rw-r--r--sound/soc/tegra/tegra210_ahub.c33
-rw-r--r--sound/soc/tegra/tegra210_amx.c16
-rw-r--r--sound/soc/tegra/tegra210_dmic.c21
-rw-r--r--sound/soc/tegra/tegra210_i2s.c25
-rw-r--r--sound/soc/tegra/tegra210_mbdrc.c35
-rw-r--r--sound/soc/tegra/tegra210_mixer.c14
-rw-r--r--sound/soc/tegra/tegra210_mvc.c14
-rw-r--r--sound/soc/tegra/tegra210_ope.c22
-rw-r--r--sound/soc/tegra/tegra210_peq.c23
-rw-r--r--sound/soc/tegra/tegra210_sfc.c14
-rw-r--r--sound/soc/tegra/tegra_asoc_machine.c143
-rw-r--r--sound/soc/tegra/tegra_audio_graph_card.c21
-rw-r--r--sound/soc/tegra/tegra_pcm.c6
-rw-r--r--sound/soc/tegra/tegra_pcm.h4
-rw-r--r--sound/soc/tegra/tegra_wm8962.c165
-rw-r--r--sound/soc/ti/davinci-mcasp.c47
-rw-r--r--sound/soc/uniphier/aio-dma.c2
-rw-r--r--sound/soc/xilinx/xlnx_formatter_pcm.c2
-rw-r--r--sound/soc/xtensa/xtfpga-i2s.c2
-rw-r--r--sound/usb/qcom/Makefile1
-rw-r--r--sound/x86/intel_hdmi_audio.h22
286 files changed, 6681 insertions, 2613 deletions
diff --git a/Documentation/devicetree/bindings/sound/adi,ssm2305.txt b/Documentation/devicetree/bindings/sound/adi,ssm2305.txt
deleted file mode 100644
index a9c9d83c8a30..000000000000
--- a/Documentation/devicetree/bindings/sound/adi,ssm2305.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-Analog Devices SSM2305 Speaker Amplifier
-========================================
-
-Required properties:
- - compatible : "adi,ssm2305"
- - shutdown-gpios : The gpio connected to the shutdown pin.
- The gpio signal is ACTIVE_LOW.
-
-Example:
-
-ssm2305: analog-amplifier {
- compatible = "adi,ssm2305";
- shutdown-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
-};
diff --git a/Documentation/devicetree/bindings/sound/adi,ssm2305.yaml b/Documentation/devicetree/bindings/sound/adi,ssm2305.yaml
new file mode 100644
index 000000000000..b841da2dc284
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/adi,ssm2305.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/adi,ssm2305.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices SSM2305 Class-D Speaker Amplifier
+
+maintainers:
+ - Lars-Peter Clausen <lars@metafoo.de>
+
+description:
+ The SSM2305 is a filterless, high efficiency, mono 2.8 W Class-D
+ audio amplifier with a micropower shutdown mode controlled via a
+ dedicated active-low GPIO pin.
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ const: adi,ssm2305
+
+ shutdown-gpios:
+ maxItems: 1
+ description:
+ GPIO connected to the shutdown pin (SD) of the SSM2305.
+ The pin is active-low; asserting it puts the device into
+ micropower shutdown mode.
+
+required:
+ - compatible
+ - shutdown-gpios
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ analog-amplifier {
+ compatible = "adi,ssm2305";
+ shutdown-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml b/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml
index 994d68c074a9..b9abb10942ba 100644
--- a/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml
+++ b/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml
@@ -35,6 +35,10 @@ properties:
dvdd-supply: true
+ firmware-name:
+ maxItems: 1
+ description: Name of the *_acf.bin file used for amplifier initialization
+
awinic,audio-channel:
description:
It is used to distinguish multiple PA devices, so that different
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml
index 99a536601cc7..376928d1f64b 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml
@@ -16,6 +16,8 @@ description: |
DAC for headphone output, two integrated Class D amplifiers for
loudspeakers, and two ADCs for wired headset microphone input or
stereo line input. PDM inputs are provided for digital microphones.
+ CS42L43B variant adds dedicated PDM interface, SoundWire Clock Gearing
+ support and more decimators to ISRCs.
allOf:
- $ref: dai-common.yaml#
@@ -24,6 +26,7 @@ properties:
compatible:
enum:
- cirrus,cs42l43
+ - cirrus,cs42l43b
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/sound/hisilicon,hi6210-i2s.txt b/Documentation/devicetree/bindings/sound/hisilicon,hi6210-i2s.txt
deleted file mode 100644
index 7a296784eb37..000000000000
--- a/Documentation/devicetree/bindings/sound/hisilicon,hi6210-i2s.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-* Hisilicon 6210 i2s controller
-
-Required properties:
-
-- compatible: should be one of the following:
- - "hisilicon,hi6210-i2s"
-- reg: physical base address of the i2s controller unit and length of
- memory mapped region.
-- interrupts: should contain the i2s interrupt.
-- clocks: a list of phandle + clock-specifier pairs, one for each entry
- in clock-names.
-- clock-names: should contain following:
- - "dacodec"
- - "i2s-base"
-- dmas: DMA specifiers for tx dma. See the DMA client binding,
- Documentation/devicetree/bindings/dma/dma.txt
-- dma-names: should be "tx" and "rx"
-- hisilicon,sysctrl-syscon: phandle to sysctrl syscon
-- #sound-dai-cells: Should be set to 1 (for multi-dai)
- - The dai cell indexes reference the following interfaces:
- 0: S2 interface
- (Currently that is the only one available, but more may be
- supported in the future)
-
-Example for the hi6210 i2s controller:
-
-i2s0: i2s@f7118000{
- compatible = "hisilicon,hi6210-i2s";
- reg = <0x0 0xf7118000 0x0 0x8000>; /* i2s unit */
- interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>; /* 155 "DigACodec_intr"-32 */
- clocks = <&sys_ctrl HI6220_DACODEC_PCLK>,
- <&sys_ctrl HI6220_BBPPLL0_DIV>;
- clock-names = "dacodec", "i2s-base";
- dmas = <&dma0 15 &dma0 14>;
- dma-names = "rx", "tx";
- hisilicon,sysctrl-syscon = <&sys_ctrl>;
- #sound-dai-cells = <1>;
-};
-
-Then when referencing the i2s controller:
- sound-dai = <&i2s0 0>; /* index 0 => S2 interface */
-
diff --git a/Documentation/devicetree/bindings/sound/hisilicon,hi6210-i2s.yaml b/Documentation/devicetree/bindings/sound/hisilicon,hi6210-i2s.yaml
new file mode 100644
index 000000000000..5171f984630b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/hisilicon,hi6210-i2s.yaml
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/hisilicon,hi6210-i2s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: HiSilicon hi6210 I2S controller
+
+maintainers:
+ - John Stultz <john.stultz@linaro.org>
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ const: hisilicon,hi6210-i2s
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 2
+
+ clock-names:
+ items:
+ - const: dacodec
+ - const: i2s-base
+
+ dmas:
+ maxItems: 2
+
+ dma-names:
+ items:
+ - const: tx
+ - const: rx
+
+ hisilicon,sysctrl-syscon:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: phandle to sysctrl syscon
+
+ "#sound-dai-cells":
+ const: 1
+ description: |
+ The dai cell indexes reference the following interfaces:
+ 0: S2 interface
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - dmas
+ - dma-names
+ - hisilicon,sysctrl-syscon
+ - "#sound-dai-cells"
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/hi6220-clock.h>
+
+ i2s@f7118000 {
+ compatible = "hisilicon,hi6210-i2s";
+ reg = <0xf7118000 0x8000>;
+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&sys_ctrl HI6220_DACODEC_PCLK>,
+ <&sys_ctrl HI6220_BBPPLL0_DIV>;
+ clock-names = "dacodec", "i2s-base";
+ dmas = <&dma0 14>, <&dma0 15>;
+ dma-names = "tx", "rx";
+ hisilicon,sysctrl-syscon = <&sys_ctrl>;
+ #sound-dai-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
index 3c75c8c78987..5424d4f16f52 100644
--- a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
+++ b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml
@@ -24,6 +24,7 @@ patternProperties:
cpu/codec dais.
type: object
+ $ref: tdm-slot.yaml#
properties:
link-name:
@@ -38,13 +39,9 @@ patternProperties:
- i2s
- dsp_b
- dai-tdm-slot-num:
- description: see tdm-slot.txt.
- $ref: /schemas/types.yaml#/definitions/uint32
+ dai-tdm-slot-num: true
- dai-tdm-slot-width:
- description: see tdm-slot.txt.
- $ref: /schemas/types.yaml#/definitions/uint32
+ dai-tdm-slot-width: true
playback-only:
description: link is used only for playback
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt2701-wm8960.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt2701-wm8960.yaml
index cf985461a995..bb6a405b263e 100644
--- a/Documentation/devicetree/bindings/sound/mediatek,mt2701-wm8960.yaml
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt2701-wm8960.yaml
@@ -28,8 +28,6 @@ properties:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of the WM8960 audio codec.
-unevaluatedProperties: false
-
required:
- compatible
- mediatek,platform
@@ -38,6 +36,8 @@ required:
- pinctrl-names
- pinctrl-0
+additionalProperties: false
+
examples:
- |
sound {
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml
index 09247ceea3f7..f21cad4bae15 100644
--- a/Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml
@@ -36,14 +36,14 @@ properties:
required:
- sound-dai
-unevaluatedProperties: false
-
required:
- compatible
- audio-routing
- platform
- codec
+unevaluatedProperties: false
+
examples:
- |
sound {
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8173-rt5650-rt5514.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8173-rt5650-rt5514.yaml
new file mode 100644
index 000000000000..ed698c9ff42b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8173-rt5650-rt5514.yaml
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mt8173-rt5650-rt5514.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek MT8173 with RT5650 and RT5514 audio codecs
+
+maintainers:
+ - Koro Chen <koro.chen@mediatek.com>
+
+properties:
+ compatible:
+ const: mediatek,mt8173-rt5650-rt5514
+
+ mediatek,audio-codec:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description: Phandles of rt5650 and rt5514 codecs
+ items:
+ - description: phandle of rt5650 codec
+ - description: phandle of rt5514 codec
+
+ mediatek,platform:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of MT8173 ASoC platform.
+
+required:
+ - compatible
+ - mediatek,audio-codec
+ - mediatek,platform
+
+additionalProperties: false
+
+examples:
+ - |
+ sound {
+ compatible = "mediatek,mt8173-rt5650-rt5514";
+ mediatek,audio-codec = <&rt5650>, <&rt5514>;
+ mediatek,platform = <&afe>;
+ };
+...
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml
index 7ba2ea2dfa0b..539de75eb20d 100644
--- a/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml
@@ -105,12 +105,12 @@ patternProperties:
required:
- link-name
-unevaluatedProperties: false
-
required:
- compatible
- mediatek,platform
+unevaluatedProperties: false
+
examples:
- |
sound {
diff --git a/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt b/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt
deleted file mode 100644
index e8b3c80c6fff..000000000000
--- a/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-MT8173 with RT5650 RT5514 CODECS
-
-Required properties:
-- compatible : "mediatek,mt8173-rt5650-rt5514"
-- mediatek,audio-codec: the phandles of rt5650 and rt5514 codecs
-- mediatek,platform: the phandle of MT8173 ASoC platform
-
-Example:
-
- sound {
- compatible = "mediatek,mt8173-rt5650-rt5514";
- mediatek,audio-codec = <&rt5650 &rt5514>;
- mediatek,platform = <&afe>;
- };
-
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-cpcap.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-cpcap.yaml
new file mode 100644
index 000000000000..69af2022d0fa
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-cpcap.yaml
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-cpcap.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra audio complex with CPCAP CODEC
+
+maintainers:
+ - Svyatoslav Ryhel <clamor95@gmail.com>
+
+allOf:
+ - $ref: nvidia,tegra-audio-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - pattern: '^motorola,tegra-audio-cpcap(-[a-z0-9]+)+$'
+ - const: nvidia,tegra-audio-cpcap
+
+ nvidia,audio-routing:
+ $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+ description:
+ A list of the connections between audio components. Each entry is a
+ pair of strings, the first being the connection's sink, the second
+ being the connection's source. Valid names for sources and sinks are
+ the pins (documented in the binding document), and the jacks on the
+ board.
+ minItems: 2
+ items:
+ enum:
+ # Board Connectors
+ - Speakers
+ - Int Spk
+ - Earpiece
+ - Int Mic
+ - Headset Mic
+ - Internal Mic 1
+ - Internal Mic 2
+ - Headphone
+ - Headphones
+ - Headphone Jack
+ - Mic Jack
+
+ # CODEC Pins
+ - MICR
+ - HSMIC
+ - EMUMIC
+ - MICL
+ - EXTR
+ - EXTL
+ - EP
+ - SPKR
+ - SPKL
+ - LINER
+ - LINEL
+ - HSR
+ - HSL
+ - EMUR
+ - EMUL
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/tegra20-car.h>
+ #include <dt-bindings/soc/tegra-pmc.h>
+ sound {
+ compatible = "motorola,tegra-audio-cpcap-olympus",
+ "nvidia,tegra-audio-cpcap";
+ nvidia,model = "Motorola Atrix 4G (MB860) CPCAP";
+
+ nvidia,audio-routing =
+ "Headphones", "HSR",
+ "Headphones", "HSL",
+ "Int Spk", "SPKR",
+ "Int Spk", "SPKL",
+ "Earpiece", "EP",
+ "HSMIC", "Mic Jack",
+ "MICR", "Internal Mic 1",
+ "MICL", "Internal Mic 2";
+
+ nvidia,i2s-controller = <&tegra_i2s1>;
+ nvidia,audio-codec = <&cpcap_audio>;
+
+ clocks = <&tegra_car TEGRA20_CLK_PLL_A>,
+ <&tegra_car TEGRA20_CLK_PLL_A_OUT0>,
+ <&tegra_car TEGRA20_CLK_CDEV1>;
+ clock-names = "pll_a", "pll_a_out0", "mclk";
+ };
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max9808x.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max9808x.yaml
index 241d20f3aad0..4957645a8e03 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max9808x.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max9808x.yaml
@@ -35,10 +35,15 @@ properties:
items:
enum:
# Board Connectors
+ - Speakers
- Int Spk
+ - Headphone
+ - Headphones
- Headphone Jack
- Earpiece
- Headset Mic
+ - Mic Jack
+ - Int Mic
- Internal Mic 1
- Internal Mic 2
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8962.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8962.yaml
new file mode 100644
index 000000000000..2c3bf5a02a34
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8962.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-wm8962.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra audio complex with WM8962 CODEC
+
+maintainers:
+ - Svyatoslav Ryhel <clamor95@gmail.com>
+
+allOf:
+ - $ref: nvidia,tegra-audio-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - pattern: '^[a-z0-9]+,tegra-audio-wm8962(-[a-z0-9]+)+$'
+ - const: nvidia,tegra-audio-wm8962
+
+ nvidia,audio-routing:
+ $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+ description:
+ A list of the connections between audio components. Each entry is a
+ pair of strings, the first being the connection's sink, the second
+ being the connection's source. Valid names for sources and sinks are
+ the pins (documented in the binding document), and the jacks on the
+ board.
+ minItems: 2
+ items:
+ enum:
+ # Board Connectors
+ - Speakers
+ - Int Spk
+ - Earpiece
+ - Int Mic
+ - Headset Mic
+ - Internal Mic 1
+ - Internal Mic 2
+ - Headphone
+ - Headphones
+ - Headphone Jack
+ - Mic Jack
+
+ # CODEC Pins
+ - IN1L
+ - IN1R
+ - IN2L
+ - IN2R
+ - IN3L
+ - IN3R
+ - IN4L
+ - IN4R
+ - DMICDAT
+ - HPOUTL
+ - HPOUTR
+ - SPKOUT
+ - SPKOUTL
+ - SPKOUTR
+
+required:
+ - nvidia,i2s-controller
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/tegra30-car.h>
+ #include <dt-bindings/soc/tegra-pmc.h>
+ sound {
+ compatible = "microsoft,tegra-audio-wm8962-surface-rt",
+ "nvidia,tegra-audio-wm8962";
+ nvidia,model = "Microsoft Surface RT WM8962";
+
+ nvidia,audio-routing =
+ "Headphone Jack", "HPOUTR",
+ "Headphone Jack", "HPOUTL",
+ "Int Spk", "SPKOUTR",
+ "Int Spk", "SPKOUTL";
+
+ nvidia,i2s-controller = <&tegra_i2s1>;
+ nvidia,audio-codec = <&wm8962>;
+
+ clocks = <&tegra_car TEGRA30_CLK_PLL_A>,
+ <&tegra_car TEGRA30_CLK_PLL_A_OUT0>,
+ <&tegra_pmc TEGRA_PMC_CLK_OUT_1>;
+ clock-names = "pll_a", "pll_a_out0", "mclk";
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml
index 08c618e7e428..2b27d6c8f58f 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml
@@ -126,13 +126,16 @@ patternProperties:
reg:
contains:
# MI2S DAI ID range PRIMARY_MI2S_RX - QUATERNARY_MI2S_TX and
- # QUINARY_MI2S_RX - QUINARY_MI2S_TX
+ # QUINARY_MI2S_RX - QUINARY_MI2S_TX and
+ # LPI_MI2S_RX_0 - SENARY_MI2S_TX
items:
oneOf:
- minimum: 16
maximum: 23
- minimum: 127
maximum: 128
+ - minimum: 137
+ maximum: 148
then:
required:
- qcom,sd-lines
diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.txt b/Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.txt
deleted file mode 100644
index 72d3cf4c2606..000000000000
--- a/Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-ROCKCHIP with MAX98357A/RT5514/DA7219 codecs on GRU boards
-
-Required properties:
-- compatible: "rockchip,rk3399-gru-sound"
-- rockchip,cpu: The phandle of the Rockchip I2S controller that's
- connected to the codecs
-- rockchip,codec: The phandle of the audio codecs
-
-Optional properties:
-- dmic-wakeup-delay-ms : specify delay time (ms) for DMIC ready.
- If this option is specified, which means it's required dmic need
- delay for DMIC to ready so that rt5514 can avoid recording before
- DMIC send valid data
-
-Example:
-
-sound {
- compatible = "rockchip,rk3399-gru-sound";
- rockchip,cpu = <&i2s0>;
- rockchip,codec = <&max98357a &rt5514 &da7219>;
- dmic-wakeup-delay-ms = <20>;
-};
diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml b/Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml
new file mode 100644
index 000000000000..e9d13695cc77
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/rockchip,rk3399-gru-sound.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip with MAX98357A/RT5514/DA7219 codecs on GRU boards
+
+maintainers:
+ - Heiko Stuebner <heiko@sntech.de>
+
+properties:
+ compatible:
+ const: rockchip,rk3399-gru-sound
+
+ rockchip,cpu:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description: |
+ List of phandles to the Rockchip CPU DAI controllers connected to codecs
+ minItems: 1
+ items:
+ - items:
+ - description: Phandle to the Rockchip I2S controllers
+ - items:
+ - description: |
+ Phandle to the Rockchip SPDIF controller. Required when a
+ DisplayPort audio codec is referenced in rockchip,codec
+
+ rockchip,codec:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description: |
+ The phandles of the audio codecs connected to the Rockchip CPU DAI
+ controllers
+ minItems: 1
+ maxItems: 6
+ items:
+ maxItems: 1
+
+ dmic-wakeup-delay-ms:
+ description: |
+ specify delay time (ms) for DMIC ready.
+ If this option is specified, a delay is required for DMIC to get ready
+ so that rt5514 can avoid recording before DMIC sends valid data
+
+required:
+ - compatible
+ - rockchip,cpu
+ - rockchip,codec
+
+additionalProperties: false
+
+examples:
+ - |
+ sound {
+ compatible = "rockchip,rk3399-gru-sound";
+ rockchip,cpu = <&i2s0 &spdif>;
+ rockchip,codec = <&max98357a &rt5514 &da7219 &cdn_dp>;
+ dmic-wakeup-delay-ms = <20>;
+ };
+
diff --git a/Documentation/devicetree/bindings/sound/rockchip,rockchip-audio-max98090.yaml b/Documentation/devicetree/bindings/sound/rockchip,rockchip-audio-max98090.yaml
new file mode 100644
index 000000000000..5351d5f02edf
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip,rockchip-audio-max98090.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/rockchip,rockchip-audio-max98090.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip audio complex with MAX98090 codec
+
+maintainers:
+ - Fabio Estevam <festevam@gmail.com>
+
+properties:
+ compatible:
+ const: rockchip,rockchip-audio-max98090
+
+ rockchip,model:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: The user-visible name of this sound complex.
+
+ rockchip,i2s-controller:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: Phandle to the Rockchip I2S controller.
+
+ rockchip,audio-codec:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: Phandle to the MAX98090 audio codec.
+
+ rockchip,headset-codec:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: Phandle to the external chip for jack detection.
+
+ rockchip,hdmi-codec:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: Phandle to the HDMI device for HDMI codec.
+
+required:
+ - compatible
+ - rockchip,model
+ - rockchip,i2s-controller
+
+allOf:
+ - if:
+ required:
+ - rockchip,audio-codec
+ then:
+ required:
+ - rockchip,headset-codec
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ sound {
+ compatible = "rockchip,rockchip-audio-max98090";
+ rockchip,model = "ROCKCHIP-I2S";
+ rockchip,i2s-controller = <&i2s>;
+ rockchip,audio-codec = <&max98090>;
+ rockchip,headset-codec = <&headsetcodec>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/rockchip-max98090.txt b/Documentation/devicetree/bindings/sound/rockchip-max98090.txt
deleted file mode 100644
index e9c58b204399..000000000000
--- a/Documentation/devicetree/bindings/sound/rockchip-max98090.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-ROCKCHIP with MAX98090 CODEC
-
-Required properties:
-- compatible: "rockchip,rockchip-audio-max98090"
-- rockchip,model: The user-visible name of this sound complex
-- rockchip,i2s-controller: The phandle of the Rockchip I2S controller that's
- connected to the CODEC
-
-Optional properties:
-- rockchip,audio-codec: The phandle of the MAX98090 audio codec.
-- rockchip,headset-codec: The phandle of Ext chip for jack detection. This is
- required if there is rockchip,audio-codec.
-- rockchip,hdmi-codec: The phandle of HDMI device for HDMI codec.
-
-Example:
-
-/* For max98090-only board. */
-sound {
- compatible = "rockchip,rockchip-audio-max98090";
- rockchip,model = "ROCKCHIP-I2S";
- rockchip,i2s-controller = <&i2s>;
- rockchip,audio-codec = <&max98090>;
- rockchip,headset-codec = <&headsetcodec>;
-};
-
-/* For HDMI-only board. */
-sound {
- compatible = "rockchip,rockchip-audio-max98090";
- rockchip,model = "ROCKCHIP-I2S";
- rockchip,i2s-controller = <&i2s>;
- rockchip,hdmi-codec = <&hdmi>;
-};
-
-/* For max98090 plus HDMI board. */
-sound {
- compatible = "rockchip,rockchip-audio-max98090";
- rockchip,model = "ROCKCHIP-I2S";
- rockchip,i2s-controller = <&i2s>;
- rockchip,audio-codec = <&max98090>;
- rockchip,headset-codec = <&headsetcodec>;
- rockchip,hdmi-codec = <&hdmi>;
-};
diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml
index 533d0a1da56e..a14716b2732f 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.yaml
+++ b/Documentation/devicetree/bindings/sound/simple-card.yaml
@@ -27,14 +27,6 @@ definitions:
description: dai-link uses bit clock inversion
$ref: /schemas/types.yaml#/definitions/flag
- dai-tdm-slot-num:
- description: see tdm-slot.txt.
- $ref: /schemas/types.yaml#/definitions/uint32
-
- dai-tdm-slot-width:
- description: see tdm-slot.txt.
- $ref: /schemas/types.yaml#/definitions/uint32
-
system-clock-frequency:
description: |
If a clock is specified and a multiplication factor is given with
@@ -115,6 +107,8 @@ definitions:
dai:
type: object
+ $ref: tdm-slot.yaml#
+
properties:
sound-dai:
maxItems: 1
@@ -133,10 +127,6 @@ definitions:
bitclock-master:
$ref: /schemas/types.yaml#/definitions/flag
- dai-tdm-slot-num:
- $ref: "#/definitions/dai-tdm-slot-num"
- dai-tdm-slot-width:
- $ref: "#/definitions/dai-tdm-slot-width"
clocks:
maxItems: 1
system-clock-frequency:
diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.txt b/Documentation/devicetree/bindings/sound/tdm-slot.txt
deleted file mode 100644
index 4bb513ae62fc..000000000000
--- a/Documentation/devicetree/bindings/sound/tdm-slot.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-TDM slot:
-
-This specifies audio DAI's TDM slot.
-
-TDM slot properties:
-dai-tdm-slot-num : Number of slots in use.
-dai-tdm-slot-width : Width in bits for each slot.
-dai-tdm-slot-tx-mask : Transmit direction slot mask, optional
-dai-tdm-slot-rx-mask : Receive direction slot mask, optional
-
-For instance:
- dai-tdm-slot-num = <2>;
- dai-tdm-slot-width = <8>;
- dai-tdm-slot-tx-mask = <0 1>;
- dai-tdm-slot-rx-mask = <1 0>;
-
-And for each specified driver, there could be one .of_xlate_tdm_slot_mask()
-to specify an explicit mapping of the channels and the slots. If it's absent
-the default snd_soc_of_xlate_tdm_slot_mask() will be used to generating the
-tx and rx masks.
-
-For snd_soc_of_xlate_tdm_slot_mask(), the tx and rx masks will use a 1 bit
-for an active slot as default, and the default active bits are at the LSB of
-the masks.
-
-The explicit masks are given as array of integers, where the first
-number presents bit-0 (LSB), second presents bit-1, etc. Any non zero
-number is considered 1 and 0 is 0. snd_soc_of_xlate_tdm_slot_mask()
-does not do anything, if either mask is set non zero value.
diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.yaml b/Documentation/devicetree/bindings/sound/tdm-slot.yaml
new file mode 100644
index 000000000000..457a899e8872
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tdm-slot.yaml
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/tdm-slot.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Time Division Multiplexing (TDM) Slot Parameters
+
+maintainers:
+ - Liam Girdwood <lgirdwood@gmail.com>
+
+select: false
+
+properties:
+ dai-tdm-slot-num:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Number of slots in use
+
+ dai-tdm-slot-width:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Width, in bits, of each slot
+
+ dai-tdm-idle-mode:
+ $ref: /schemas/types.yaml#/definitions/string
+ enum:
+ - none
+ - off
+ - zero
+ - pulldown
+ - hiz
+ - pullup
+ - drivehigh
+ description: Drive mode for inactive/idle TDM slots. For hardware that
+ implements .set_tdm_idle(). Optional. "None" represents undefined
+ behaviour and is the same as not setting this property.
+
+patternProperties:
+ '^dai-tdm-slot-[rt]x-mask$':
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description: Slot mask for active TDM slots. Optional. Drivers may
+ specify .xlate_tdm_slot_mask() to generate a slot mask dynamically. If
+ neither this property nor a driver-specific function are specified, the
+ default snd_soc_xlate_tdm_slot_mask() function will be used to generate
+ a mask. The first element of the array is slot 0 (LSB). Any nonzero
+ value will be treated as 1.
+
+ '^dai-tdm-slot-[rt]x-idle-mask$':
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Idle slot mask. Optional. A bit being set to 1 indicates
+ that the corresponding TDM slot is inactive/idle.
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/sound/ti,tas2770.yaml b/Documentation/devicetree/bindings/sound/ti,tas2770.yaml
index 8eab98a0f7a2..8d49fbcf0b9b 100644
--- a/Documentation/devicetree/bindings/sound/ti,tas2770.yaml
+++ b/Documentation/devicetree/bindings/sound/ti,tas2770.yaml
@@ -30,7 +30,7 @@ properties:
description: |
I2C address of the device can be between 0x41 to 0x48.
- reset-gpio:
+ reset-gpios:
maxItems: 1
description: GPIO used to reset the device.
@@ -82,7 +82,7 @@ examples:
#sound-dai-cells = <0>;
interrupt-parent = <&gpio1>;
interrupts = <14>;
- reset-gpio = <&gpio1 15 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
shutdown-gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;
ti,imon-slot-no = <0>;
ti,vmon-slot-no = <2>;
diff --git a/arch/arm/mach-s3c/mach-crag6410-module.c b/arch/arm/mach-s3c/mach-crag6410-module.c
index 4ffcf024b09d..14b0f9cc103e 100644
--- a/arch/arm/mach-s3c/mach-crag6410-module.c
+++ b/arch/arm/mach-s3c/mach-crag6410-module.c
@@ -239,7 +239,6 @@ static struct gpiod_lookup_table wm8994_gpiod_table = {
static struct arizona_pdata wm5102_reva_pdata = {
.gpio_base = CODEC_GPIO_BASE,
.irq_flags = IRQF_TRIGGER_HIGH,
- .micd_pol_gpio = CODEC_GPIO_BASE + 4,
.micd_rate = 6,
.gpio_defaults = {
[2] = 0x10000, /* AIF3TXLRCLK */
@@ -265,6 +264,8 @@ static struct gpiod_lookup_table wm5102_reva_gpiod_table = {
.table = {
GPIO_LOOKUP("GPION", 7,
"wlf,ldoena", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("arizona", 4,
+ "wlf,micd-pol", GPIO_ACTIVE_HIGH),
{ },
},
};
@@ -272,7 +273,6 @@ static struct gpiod_lookup_table wm5102_reva_gpiod_table = {
static struct arizona_pdata wm5102_pdata = {
.gpio_base = CODEC_GPIO_BASE,
.irq_flags = IRQF_TRIGGER_HIGH,
- .micd_pol_gpio = CODEC_GPIO_BASE + 2,
.gpio_defaults = {
[2] = 0x10000, /* AIF3TXLRCLK */
[3] = 0x4, /* OPCLK */
@@ -297,6 +297,8 @@ static struct gpiod_lookup_table wm5102_gpiod_table = {
.table = {
GPIO_LOOKUP("GPION", 7,
"wlf,ldo1ena", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("arizona", 2,
+ "wlf,micd-pol", GPIO_ACTIVE_HIGH),
{ },
},
};
diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c
index 5d8be0ac7c5e..bb93b24c659d 100644
--- a/drivers/firmware/cirrus/cs_dsp.c
+++ b/drivers/firmware/cirrus/cs_dsp.c
@@ -9,6 +9,7 @@
* Cirrus Logic International Semiconductor Ltd.
*/
+#include <kunit/static_stub.h>
#include <kunit/visibility.h>
#include <linux/cleanup.h>
#include <linux/ctype.h>
@@ -18,6 +19,7 @@
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/ratelimit.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
@@ -30,45 +32,47 @@
/*
* When the KUnit test is running the error-case tests will cause a lot
* of messages. Rate-limit to prevent overflowing the kernel log buffer
- * during KUnit test runs.
+ * during KUnit test runs and allow the test to redirect this function.
+ * In normal (not KUnit) builds this collapses to only return true.
*/
-#if IS_ENABLED(CONFIG_FW_CS_DSP_KUNIT_TEST)
-bool cs_dsp_suppress_err_messages;
-EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_err_messages);
+VISIBLE_IF_KUNIT bool cs_dsp_can_emit_message(void)
+{
+ KUNIT_STATIC_STUB_REDIRECT(cs_dsp_can_emit_message);
-bool cs_dsp_suppress_warn_messages;
-EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_warn_messages);
+ if (IS_ENABLED(CONFIG_FW_CS_DSP_KUNIT_TEST)) {
+ static DEFINE_RATELIMIT_STATE(_rs,
+ DEFAULT_RATELIMIT_INTERVAL,
+ DEFAULT_RATELIMIT_BURST);
+ return __ratelimit(&_rs);
+ }
-bool cs_dsp_suppress_info_messages;
-EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_info_messages);
+ return true;
+}
+EXPORT_SYMBOL_IF_KUNIT(cs_dsp_can_emit_message);
-#define cs_dsp_err(_dsp, fmt, ...) \
- do { \
- if (!cs_dsp_suppress_err_messages) \
- dev_err_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
+#define cs_dsp_err(_dsp, fmt, ...) \
+ do { \
+ if (cs_dsp_can_emit_message()) \
+ dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
} while (false)
-#define cs_dsp_warn(_dsp, fmt, ...) \
- do { \
- if (!cs_dsp_suppress_warn_messages) \
- dev_warn_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
+
+#define cs_dsp_warn(_dsp, fmt, ...) \
+ do { \
+ if (cs_dsp_can_emit_message()) \
+ dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
} while (false)
-#define cs_dsp_info(_dsp, fmt, ...) \
- do { \
- if (!cs_dsp_suppress_info_messages) \
- dev_info_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
+
+#define cs_dsp_info(_dsp, fmt, ...) \
+ do { \
+ if (cs_dsp_can_emit_message()) \
+ dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
+ } while (false)
+
+#define cs_dsp_dbg(_dsp, fmt, ...) \
+ do { \
+ if (cs_dsp_can_emit_message()) \
+ dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
} while (false)
-#define cs_dsp_dbg(_dsp, fmt, ...) \
- dev_dbg_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
-#else
-#define cs_dsp_err(_dsp, fmt, ...) \
- dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
-#define cs_dsp_warn(_dsp, fmt, ...) \
- dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
-#define cs_dsp_info(_dsp, fmt, ...) \
- dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
-#define cs_dsp_dbg(_dsp, fmt, ...) \
- dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
-#endif
#define ADSP1_CONTROL_1 0x00
#define ADSP1_CONTROL_2 0x02
@@ -515,6 +519,7 @@ void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root)
debugfs_create_bool("booted", 0444, root, &dsp->booted);
debugfs_create_bool("running", 0444, root, &dsp->running);
+ debugfs_create_bool("hibernating", 0444, root, &dsp->hibernating);
debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id);
debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version);
@@ -703,7 +708,7 @@ int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int
lockdep_assert_held(&dsp->pwr_lock);
- if (!dsp->running)
+ if (!dsp->running || dsp->hibernating)
return -EPERM;
ret = cs_dsp_coeff_base_reg(ctl, &reg, 0);
@@ -827,7 +832,7 @@ int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl,
}
ctl->set = 1;
- if (ctl->enabled && ctl->dsp->running)
+ if (ctl->enabled && ctl->dsp->running && !ctl->dsp->hibernating)
ret = cs_dsp_coeff_write_ctrl_raw(ctl, off, buf, len);
if (ret < 0)
@@ -920,12 +925,12 @@ int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl,
return -EINVAL;
if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
- if (ctl->enabled && ctl->dsp->running)
+ if (ctl->enabled && ctl->dsp->running && !ctl->dsp->hibernating)
return cs_dsp_coeff_read_ctrl_raw(ctl, off, buf, len);
else
return -EPERM;
} else {
- if (!ctl->flags && ctl->enabled && ctl->dsp->running)
+ if (!ctl->flags && ctl->enabled && ctl->dsp->running && !ctl->dsp->hibernating)
ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len);
if (buf != ctl->cache)
@@ -1108,6 +1113,44 @@ err_ctl:
return ret;
}
+
+/**
+ * cs_dsp_hibernate() - Disable or enable all controls for a DSP
+ * @dsp: pointer to DSP structure
+ * @hibernate: whether to set controls to cache only mode
+ *
+ * When @hibernate is true, the DSP is entering hibernation mode where the
+ * regmap is inaccessible, and all controls become cache only.
+ * When @hibernate is false, the DSP has exited hibernation mode. If the DSP
+ * is running, all controls are re-synced to the DSP.
+ *
+ */
+void cs_dsp_hibernate(struct cs_dsp *dsp, bool hibernate)
+{
+ mutex_lock(&dsp->pwr_lock);
+
+ if (!dsp->running) {
+ cs_dsp_dbg(dsp, "Cannot hibernate, DSP not running\n");
+ goto out;
+ }
+
+ if (dsp->hibernating == hibernate)
+ goto out;
+
+ cs_dsp_dbg(dsp, "Set hibernating to %d\n", hibernate);
+ dsp->hibernating = hibernate;
+
+ if (!dsp->hibernating && dsp->running) {
+ int ret = cs_dsp_coeff_sync_controls(dsp);
+
+ if (ret)
+ cs_dsp_err(dsp, "Error syncing controls: %d\n", ret);
+ }
+out:
+ mutex_unlock(&dsp->pwr_lock);
+}
+EXPORT_SYMBOL_NS_GPL(cs_dsp_hibernate, "FW_CS_DSP");
+
struct cs_dsp_coeff_parsed_alg {
int id;
const u8 *name;
@@ -2510,6 +2553,7 @@ int cs_dsp_adsp1_power_up(struct cs_dsp *dsp,
goto err_ena;
dsp->booted = true;
+ dsp->hibernating = false;
/* Start the core running */
regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
@@ -2788,6 +2832,7 @@ int cs_dsp_power_up(struct cs_dsp *dsp,
dsp->ops->disable_core(dsp);
dsp->booted = true;
+ dsp->hibernating = false;
mutex_unlock(&dsp->pwr_lock);
diff --git a/drivers/firmware/cirrus/cs_dsp.h b/drivers/firmware/cirrus/cs_dsp.h
index adf543004aea..04d768d08d03 100644
--- a/drivers/firmware/cirrus/cs_dsp.h
+++ b/drivers/firmware/cirrus/cs_dsp.h
@@ -10,9 +10,7 @@
#define FW_CS_DSP_H
#if IS_ENABLED(CONFIG_KUNIT)
-extern bool cs_dsp_suppress_err_messages;
-extern bool cs_dsp_suppress_warn_messages;
-extern bool cs_dsp_suppress_info_messages;
+bool cs_dsp_can_emit_message(void);
#endif
#endif /* ifndef FW_CS_DSP_H */
diff --git a/drivers/firmware/cirrus/test/cs_dsp_test_bin.c b/drivers/firmware/cirrus/test/cs_dsp_test_bin.c
index 66140caeebb5..63416838f865 100644
--- a/drivers/firmware/cirrus/test/cs_dsp_test_bin.c
+++ b/drivers/firmware/cirrus/test/cs_dsp_test_bin.c
@@ -7,6 +7,7 @@
#include <kunit/device.h>
#include <kunit/resource.h>
+#include <kunit/static_stub.h>
#include <kunit/test.h>
#include <linux/build_bug.h>
#include <linux/firmware/cirrus/cs_dsp.h>
@@ -2155,6 +2156,15 @@ static void bin_patch_name_and_info(struct kunit *test)
KUNIT_EXPECT_EQ(test, reg_val, payload_data);
}
+static bool cs_dsp_bin_test_can_emit_message_hook(void)
+{
+#if defined(DEBUG)
+ return true;
+#else
+ return false;
+#endif
+}
+
static int cs_dsp_bin_test_common_init(struct kunit *test, struct cs_dsp *dsp,
int wmdr_ver)
{
@@ -2239,16 +2249,12 @@ static int cs_dsp_bin_test_common_init(struct kunit *test, struct cs_dsp *dsp,
* The large number of test cases will cause an unusually large amount
* of dev_info() messages from cs_dsp, so suppress these.
*/
- cs_dsp_suppress_info_messages = true;
+ kunit_activate_static_stub(test, cs_dsp_can_emit_message,
+ cs_dsp_bin_test_can_emit_message_hook);
return 0;
}
-static void cs_dsp_bin_test_exit(struct kunit *test)
-{
- cs_dsp_suppress_info_messages = false;
-}
-
static int cs_dsp_bin_test_halo_init_common(struct kunit *test, int wmdr_ver)
{
struct cs_dsp *dsp;
@@ -2833,28 +2839,29 @@ static struct kunit_case cs_dsp_bin_test_cases_adsp2[] = {
static struct kunit_suite cs_dsp_bin_test_halo = {
.name = "cs_dsp_bin_halo",
.init = cs_dsp_bin_test_halo_init,
- .exit = cs_dsp_bin_test_exit,
.test_cases = cs_dsp_bin_test_cases_halo,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_bin_test_halo_wmdr3 = {
.name = "cs_dsp_bin_halo_wmdr_v3",
.init = cs_dsp_bin_test_halo_wmdr3_init,
.test_cases = cs_dsp_bin_test_cases_halo_wmdr3,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_bin_test_adsp2_32bit = {
.name = "cs_dsp_bin_adsp2_32bit",
.init = cs_dsp_bin_test_adsp2_32bit_init,
- .exit = cs_dsp_bin_test_exit,
.test_cases = cs_dsp_bin_test_cases_adsp2,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_bin_test_adsp2_16bit = {
.name = "cs_dsp_bin_adsp2_16bit",
.init = cs_dsp_bin_test_adsp2_16bit_init,
- .exit = cs_dsp_bin_test_exit,
.test_cases = cs_dsp_bin_test_cases_adsp2,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
kunit_test_suites(&cs_dsp_bin_test_halo,
diff --git a/drivers/firmware/cirrus/test/cs_dsp_test_bin_error.c b/drivers/firmware/cirrus/test/cs_dsp_test_bin_error.c
index 9b2763b36970..f879c5467c98 100644
--- a/drivers/firmware/cirrus/test/cs_dsp_test_bin_error.c
+++ b/drivers/firmware/cirrus/test/cs_dsp_test_bin_error.c
@@ -8,6 +8,7 @@
#include <kunit/device.h>
#include <kunit/resource.h>
+#include <kunit/static_stub.h>
#include <kunit/test.h>
#include <linux/build_bug.h>
#include <linux/firmware/cirrus/cs_dsp.h>
@@ -380,11 +381,13 @@ static void bin_block_payload_len_garbage(struct kunit *test)
0);
}
-static void cs_dsp_bin_err_test_exit(struct kunit *test)
+static bool cs_dsp_bin_err_test_can_emit_message_hook(void)
{
- cs_dsp_suppress_err_messages = false;
- cs_dsp_suppress_warn_messages = false;
- cs_dsp_suppress_info_messages = false;
+#if defined(DEBUG)
+ return true;
+#else
+ return false;
+#endif
}
static int cs_dsp_bin_err_test_common_init(struct kunit *test, struct cs_dsp *dsp,
@@ -482,9 +485,8 @@ static int cs_dsp_bin_err_test_common_init(struct kunit *test, struct cs_dsp *ds
* Testing error conditions can produce a lot of log output
* from cs_dsp error messages, so suppress messages.
*/
- cs_dsp_suppress_err_messages = true;
- cs_dsp_suppress_warn_messages = true;
- cs_dsp_suppress_info_messages = true;
+ kunit_activate_static_stub(test, cs_dsp_can_emit_message,
+ cs_dsp_bin_err_test_can_emit_message_hook);
return 0;
}
@@ -584,22 +586,22 @@ static struct kunit_case cs_dsp_bin_err_test_cases[] = {
static struct kunit_suite cs_dsp_bin_err_test_halo = {
.name = "cs_dsp_bin_err_halo",
.init = cs_dsp_bin_err_test_halo_init,
- .exit = cs_dsp_bin_err_test_exit,
.test_cases = cs_dsp_bin_err_test_cases,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_bin_err_test_adsp2_32bit = {
.name = "cs_dsp_bin_err_adsp2_32bit",
.init = cs_dsp_bin_err_test_adsp2_32bit_init,
- .exit = cs_dsp_bin_err_test_exit,
.test_cases = cs_dsp_bin_err_test_cases,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_bin_err_test_adsp2_16bit = {
.name = "cs_dsp_bin_err_adsp2_16bit",
.init = cs_dsp_bin_err_test_adsp2_16bit_init,
- .exit = cs_dsp_bin_err_test_exit,
.test_cases = cs_dsp_bin_err_test_cases,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
kunit_test_suites(&cs_dsp_bin_err_test_halo,
diff --git a/drivers/firmware/cirrus/test/cs_dsp_test_control_cache.c b/drivers/firmware/cirrus/test/cs_dsp_test_control_cache.c
index ebca3a4ab0f1..b03cd7c37f6e 100644
--- a/drivers/firmware/cirrus/test/cs_dsp_test_control_cache.c
+++ b/drivers/firmware/cirrus/test/cs_dsp_test_control_cache.c
@@ -3248,30 +3248,35 @@ static struct kunit_suite cs_dsp_ctl_cache_test_halo = {
.name = "cs_dsp_ctl_cache_wmfwV3_halo",
.init = cs_dsp_ctl_cache_test_halo_init,
.test_cases = cs_dsp_ctl_cache_test_cases_v3,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_ctl_cache_test_adsp2_32bit_wmfw1 = {
.name = "cs_dsp_ctl_cache_wmfwV1_adsp2_32bit",
.init = cs_dsp_ctl_cache_test_adsp2_32bit_wmfw1_init,
.test_cases = cs_dsp_ctl_cache_test_cases_v1,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_ctl_cache_test_adsp2_32bit_wmfw2 = {
.name = "cs_dsp_ctl_cache_wmfwV2_adsp2_32bit",
.init = cs_dsp_ctl_cache_test_adsp2_32bit_wmfw2_init,
.test_cases = cs_dsp_ctl_cache_test_cases_v2,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_ctl_cache_test_adsp2_16bit_wmfw1 = {
.name = "cs_dsp_ctl_cache_wmfwV1_adsp2_16bit",
.init = cs_dsp_ctl_cache_test_adsp2_16bit_wmfw1_init,
.test_cases = cs_dsp_ctl_cache_test_cases_v1,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_ctl_cache_test_adsp2_16bit_wmfw2 = {
.name = "cs_dsp_ctl_cache_wmfwV2_adsp2_16bit",
.init = cs_dsp_ctl_cache_test_adsp2_16bit_wmfw2_init,
.test_cases = cs_dsp_ctl_cache_test_cases_v2,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
kunit_test_suites(&cs_dsp_ctl_cache_test_halo,
diff --git a/drivers/firmware/cirrus/test/cs_dsp_test_control_parse.c b/drivers/firmware/cirrus/test/cs_dsp_test_control_parse.c
index 942ba1af5e7c..368703767644 100644
--- a/drivers/firmware/cirrus/test/cs_dsp_test_control_parse.c
+++ b/drivers/firmware/cirrus/test/cs_dsp_test_control_parse.c
@@ -1805,30 +1805,35 @@ static struct kunit_suite cs_dsp_ctl_parse_test_halo = {
.name = "cs_dsp_ctl_parse_wmfwV3_halo",
.init = cs_dsp_ctl_parse_test_halo_init,
.test_cases = cs_dsp_ctl_parse_test_cases_v2_v3,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_32bit_wmfw1 = {
.name = "cs_dsp_ctl_parse_wmfwV1_adsp2_32bit",
.init = cs_dsp_ctl_parse_test_adsp2_32bit_wmfw1_init,
.test_cases = cs_dsp_ctl_parse_test_cases_v1,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_32bit_wmfw2 = {
.name = "cs_dsp_ctl_parse_wmfwV2_adsp2_32bit",
.init = cs_dsp_ctl_parse_test_adsp2_32bit_wmfw2_init,
.test_cases = cs_dsp_ctl_parse_test_cases_v2_v3,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_16bit_wmfw1 = {
.name = "cs_dsp_ctl_parse_wmfwV1_adsp2_16bit",
.init = cs_dsp_ctl_parse_test_adsp2_16bit_wmfw1_init,
.test_cases = cs_dsp_ctl_parse_test_cases_v1,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_16bit_wmfw2 = {
.name = "cs_dsp_ctl_parse_wmfwV2_adsp2_16bit",
.init = cs_dsp_ctl_parse_test_adsp2_16bit_wmfw2_init,
.test_cases = cs_dsp_ctl_parse_test_cases_v2_v3,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
kunit_test_suites(&cs_dsp_ctl_parse_test_halo,
diff --git a/drivers/firmware/cirrus/test/cs_dsp_test_control_rw.c b/drivers/firmware/cirrus/test/cs_dsp_test_control_rw.c
index bda00a95d4f9..d800f163b099 100644
--- a/drivers/firmware/cirrus/test/cs_dsp_test_control_rw.c
+++ b/drivers/firmware/cirrus/test/cs_dsp_test_control_rw.c
@@ -2636,30 +2636,35 @@ static struct kunit_suite cs_dsp_ctl_rw_test_halo = {
.name = "cs_dsp_ctl_rw_wmfwV3_halo",
.init = cs_dsp_ctl_rw_test_halo_init,
.test_cases = cs_dsp_ctl_rw_test_cases_halo,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_ctl_rw_test_adsp2_32bit_wmfw1 = {
.name = "cs_dsp_ctl_rw_wmfwV1_adsp2_32bit",
.init = cs_dsp_ctl_rw_test_adsp2_32bit_wmfw1_init,
.test_cases = cs_dsp_ctl_rw_test_cases_adsp,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_ctl_rw_test_adsp2_32bit_wmfw2 = {
.name = "cs_dsp_ctl_rw_wmfwV2_adsp2_32bit",
.init = cs_dsp_ctl_rw_test_adsp2_32bit_wmfw2_init,
.test_cases = cs_dsp_ctl_rw_test_cases_adsp,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_ctl_rw_test_adsp2_16bit_wmfw1 = {
.name = "cs_dsp_ctl_rw_wmfwV1_adsp2_16bit",
.init = cs_dsp_ctl_rw_test_adsp2_16bit_wmfw1_init,
.test_cases = cs_dsp_ctl_rw_test_cases_adsp,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_ctl_rw_test_adsp2_16bit_wmfw2 = {
.name = "cs_dsp_ctl_rw_wmfwV2_adsp2_16bit",
.init = cs_dsp_ctl_rw_test_adsp2_16bit_wmfw2_init,
.test_cases = cs_dsp_ctl_rw_test_cases_adsp,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
kunit_test_suites(&cs_dsp_ctl_rw_test_halo,
diff --git a/drivers/firmware/cirrus/test/cs_dsp_test_wmfw.c b/drivers/firmware/cirrus/test/cs_dsp_test_wmfw.c
index f02cb6cf7638..1de70e81a868 100644
--- a/drivers/firmware/cirrus/test/cs_dsp_test_wmfw.c
+++ b/drivers/firmware/cirrus/test/cs_dsp_test_wmfw.c
@@ -8,6 +8,7 @@
#include <kunit/device.h>
#include <kunit/resource.h>
+#include <kunit/static_stub.h>
#include <kunit/test.h>
#include <linux/build_bug.h>
#include <linux/firmware/cirrus/cs_dsp.h>
@@ -1775,6 +1776,15 @@ static void wmfw_load_with_info(struct kunit *test)
KUNIT_EXPECT_MEMEQ(test, readback, payload_data, payload_size_bytes);
}
+static bool cs_dsp_wmfw_test_can_emit_message_hook(void)
+{
+#if defined(DEBUG)
+ return true;
+#else
+ return false;
+#endif
+}
+
static int cs_dsp_wmfw_test_common_init(struct kunit *test, struct cs_dsp *dsp,
int wmfw_version)
{
@@ -1863,16 +1873,12 @@ static int cs_dsp_wmfw_test_common_init(struct kunit *test, struct cs_dsp *dsp,
* The large number of test cases will cause an unusually large amount
* of dev_info() messages from cs_dsp, so suppress these.
*/
- cs_dsp_suppress_info_messages = true;
+ kunit_activate_static_stub(test, cs_dsp_can_emit_message,
+ cs_dsp_wmfw_test_can_emit_message_hook);
return 0;
}
-static void cs_dsp_wmfw_test_exit(struct kunit *test)
-{
- cs_dsp_suppress_info_messages = false;
-}
-
static int cs_dsp_wmfw_test_halo_init(struct kunit *test)
{
struct cs_dsp *dsp;
@@ -2180,50 +2186,50 @@ static struct kunit_case cs_dsp_wmfw_test_cases_adsp2[] = {
static struct kunit_suite cs_dsp_wmfw_test_halo = {
.name = "cs_dsp_wmfwV3_halo",
.init = cs_dsp_wmfw_test_halo_init,
- .exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_halo,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw0 = {
.name = "cs_dsp_wmfwV0_adsp2_32bit",
.init = cs_dsp_wmfw_test_adsp2_32bit_wmfw0_init,
- .exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw1 = {
.name = "cs_dsp_wmfwV1_adsp2_32bit",
.init = cs_dsp_wmfw_test_adsp2_32bit_wmfw1_init,
- .exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw2 = {
.name = "cs_dsp_wmfwV2_adsp2_32bit",
.init = cs_dsp_wmfw_test_adsp2_32bit_wmfw2_init,
- .exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw0 = {
.name = "cs_dsp_wmfwV0_adsp2_16bit",
.init = cs_dsp_wmfw_test_adsp2_16bit_wmfw0_init,
- .exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw1 = {
.name = "cs_dsp_wmfwV1_adsp2_16bit",
.init = cs_dsp_wmfw_test_adsp2_16bit_wmfw1_init,
- .exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw2 = {
.name = "cs_dsp_wmfwV2_adsp2_16bit",
.init = cs_dsp_wmfw_test_adsp2_16bit_wmfw2_init,
- .exit = cs_dsp_wmfw_test_exit,
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
kunit_test_suites(&cs_dsp_wmfw_test_halo,
diff --git a/drivers/firmware/cirrus/test/cs_dsp_test_wmfw_error.c b/drivers/firmware/cirrus/test/cs_dsp_test_wmfw_error.c
index 37162d12e2fa..e7bf5dc474f5 100644
--- a/drivers/firmware/cirrus/test/cs_dsp_test_wmfw_error.c
+++ b/drivers/firmware/cirrus/test/cs_dsp_test_wmfw_error.c
@@ -8,6 +8,7 @@
#include <kunit/device.h>
#include <kunit/resource.h>
+#include <kunit/static_stub.h>
#include <kunit/test.h>
#include <linux/build_bug.h>
#include <linux/firmware/cirrus/cs_dsp.h>
@@ -989,11 +990,13 @@ static void wmfw_v2_coeff_description_exceeds_block(struct kunit *test)
-EOVERFLOW);
}
-static void cs_dsp_wmfw_err_test_exit(struct kunit *test)
+static bool cs_dsp_wmfw_err_test_can_emit_message_hook(void)
{
- cs_dsp_suppress_err_messages = false;
- cs_dsp_suppress_warn_messages = false;
- cs_dsp_suppress_info_messages = false;
+#if defined(DEBUG)
+ return true;
+#else
+ return false;
+#endif
}
static int cs_dsp_wmfw_err_test_common_init(struct kunit *test, struct cs_dsp *dsp,
@@ -1080,9 +1083,8 @@ static int cs_dsp_wmfw_err_test_common_init(struct kunit *test, struct cs_dsp *d
* Testing error conditions can produce a lot of log output
* from cs_dsp error messages, so suppress messages.
*/
- cs_dsp_suppress_err_messages = true;
- cs_dsp_suppress_warn_messages = true;
- cs_dsp_suppress_info_messages = true;
+ kunit_activate_static_stub(test, cs_dsp_can_emit_message,
+ cs_dsp_wmfw_err_test_can_emit_message_hook);
return 0;
}
@@ -1304,50 +1306,50 @@ static struct kunit_case cs_dsp_wmfw_err_test_cases_v3[] = {
static struct kunit_suite cs_dsp_wmfw_err_test_halo = {
.name = "cs_dsp_wmfwV3_err_halo",
.init = cs_dsp_wmfw_err_test_halo_init,
- .exit = cs_dsp_wmfw_err_test_exit,
.test_cases = cs_dsp_wmfw_err_test_cases_v3,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_32bit_wmfw0 = {
.name = "cs_dsp_wmfwV0_err_adsp2_32bit",
.init = cs_dsp_wmfw_err_test_adsp2_32bit_wmfw0_init,
- .exit = cs_dsp_wmfw_err_test_exit,
.test_cases = cs_dsp_wmfw_err_test_cases_v0,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_32bit_wmfw1 = {
.name = "cs_dsp_wmfwV1_err_adsp2_32bit",
.init = cs_dsp_wmfw_err_test_adsp2_32bit_wmfw1_init,
- .exit = cs_dsp_wmfw_err_test_exit,
.test_cases = cs_dsp_wmfw_err_test_cases_v1,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_32bit_wmfw2 = {
.name = "cs_dsp_wmfwV2_err_adsp2_32bit",
.init = cs_dsp_wmfw_err_test_adsp2_32bit_wmfw2_init,
- .exit = cs_dsp_wmfw_err_test_exit,
.test_cases = cs_dsp_wmfw_err_test_cases_v2,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_16bit_wmfw0 = {
.name = "cs_dsp_wmfwV0_err_adsp2_16bit",
.init = cs_dsp_wmfw_err_test_adsp2_16bit_wmfw0_init,
- .exit = cs_dsp_wmfw_err_test_exit,
.test_cases = cs_dsp_wmfw_err_test_cases_v0,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_16bit_wmfw1 = {
.name = "cs_dsp_wmfwV1_err_adsp2_16bit",
.init = cs_dsp_wmfw_err_test_adsp2_16bit_wmfw1_init,
- .exit = cs_dsp_wmfw_err_test_exit,
.test_cases = cs_dsp_wmfw_err_test_cases_v1,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_16bit_wmfw2 = {
.name = "cs_dsp_wmfwV2_err_adsp2_16bit",
.init = cs_dsp_wmfw_err_test_adsp2_16bit_wmfw2_init,
- .exit = cs_dsp_wmfw_err_test_exit,
.test_cases = cs_dsp_wmfw_err_test_cases_v2,
+ .attr.speed = KUNIT_SPEED_SLOW,
};
kunit_test_suites(&cs_dsp_wmfw_err_test_halo,
diff --git a/drivers/mfd/cs42l43-i2c.c b/drivers/mfd/cs42l43-i2c.c
index a2ab001a600a..0a0ab5e549a5 100644
--- a/drivers/mfd/cs42l43-i2c.c
+++ b/drivers/mfd/cs42l43-i2c.c
@@ -47,6 +47,7 @@ static int cs42l43_i2c_probe(struct i2c_client *i2c)
cs42l43->irq = i2c->irq;
/* A device on an I2C is always attached by definition. */
cs42l43->attached = true;
+ cs42l43->variant_id = (long)device_get_match_data(cs42l43->dev);
cs42l43->regmap = devm_regmap_init_i2c(i2c, &cs42l43_i2c_regmap);
if (IS_ERR(cs42l43->regmap))
@@ -58,7 +59,8 @@ static int cs42l43_i2c_probe(struct i2c_client *i2c)
#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id cs42l43_of_match[] = {
- { .compatible = "cirrus,cs42l43", },
+ { .compatible = "cirrus,cs42l43", .data = (void *)CS42L43_DEVID_VAL },
+ { .compatible = "cirrus,cs42l43b", .data = (void *)CS42L43B_DEVID_VAL },
{}
};
MODULE_DEVICE_TABLE(of, cs42l43_of_match);
@@ -66,7 +68,8 @@ MODULE_DEVICE_TABLE(of, cs42l43_of_match);
#if IS_ENABLED(CONFIG_ACPI)
static const struct acpi_device_id cs42l43_acpi_match[] = {
- { "CSC4243", 0 },
+ { "CSC4243", CS42L43_DEVID_VAL },
+ { "CSC2A3B", CS42L43B_DEVID_VAL },
{}
};
MODULE_DEVICE_TABLE(acpi, cs42l43_acpi_match);
diff --git a/drivers/mfd/cs42l43-sdw.c b/drivers/mfd/cs42l43-sdw.c
index 023f7e1a30f8..794c98378175 100644
--- a/drivers/mfd/cs42l43-sdw.c
+++ b/drivers/mfd/cs42l43-sdw.c
@@ -178,6 +178,7 @@ static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *
cs42l43->dev = dev;
cs42l43->sdw = sdw;
+ cs42l43->variant_id = (long)id->driver_data;
cs42l43->regmap = devm_regmap_init_sdw(sdw, &cs42l43_sdw_regmap);
if (IS_ERR(cs42l43->regmap))
@@ -188,7 +189,8 @@ static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *
}
static const struct sdw_device_id cs42l43_sdw_id[] = {
- SDW_SLAVE_ENTRY(0x01FA, 0x4243, 0),
+ SDW_SLAVE_ENTRY(0x01FA, 0x4243, (void *) CS42L43_DEVID_VAL),
+ SDW_SLAVE_ENTRY(0x01FA, 0x2A3B, (void *) CS42L43B_DEVID_VAL),
{}
};
MODULE_DEVICE_TABLE(sdw, cs42l43_sdw_id);
diff --git a/drivers/mfd/cs42l43.c b/drivers/mfd/cs42l43.c
index 107cfb983fec..166881751e69 100644
--- a/drivers/mfd/cs42l43.c
+++ b/drivers/mfd/cs42l43.c
@@ -115,9 +115,14 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = {
{ CS42L43_DECIM_HPF_WNF_CTRL2, 0x00000001 },
{ CS42L43_DECIM_HPF_WNF_CTRL3, 0x00000001 },
{ CS42L43_DECIM_HPF_WNF_CTRL4, 0x00000001 },
+ { CS42L43B_DECIM_HPF_WNF_CTRL5, 0x00000001 },
+ { CS42L43B_DECIM_HPF_WNF_CTRL6, 0x00000001 },
{ CS42L43_DMIC_PDM_CTRL, 0x00000000 },
{ CS42L43_DECIM_VOL_CTRL_CH1_CH2, 0x20122012 },
{ CS42L43_DECIM_VOL_CTRL_CH3_CH4, 0x20122012 },
+ { CS42L43B_DECIM_VOL_CTRL_CH1_CH2, 0x20122012 },
+ { CS42L43B_DECIM_VOL_CTRL_CH3_CH4, 0x20122012 },
+ { CS42L43B_DECIM_VOL_CTRL_CH5_CH6, 0x20122012 },
{ CS42L43_INTP_VOLUME_CTRL1, 0x00000180 },
{ CS42L43_INTP_VOLUME_CTRL2, 0x00000180 },
{ CS42L43_AMP1_2_VOL_RAMP, 0x00000022 },
@@ -155,8 +160,12 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = {
{ CS42L43_SWIRE_DP2_CH2_INPUT, 0x00000000 },
{ CS42L43_SWIRE_DP3_CH1_INPUT, 0x00000000 },
{ CS42L43_SWIRE_DP3_CH2_INPUT, 0x00000000 },
+ { CS42L43B_SWIRE_DP3_CH3_INPUT, 0x00000000 },
+ { CS42L43B_SWIRE_DP3_CH4_INPUT, 0x00000000 },
{ CS42L43_SWIRE_DP4_CH1_INPUT, 0x00000000 },
{ CS42L43_SWIRE_DP4_CH2_INPUT, 0x00000000 },
+ { CS42L43B_SWIRE_DP4_CH3_INPUT, 0x00000000 },
+ { CS42L43B_SWIRE_DP4_CH4_INPUT, 0x00000000 },
{ CS42L43_ASRC_INT1_INPUT1, 0x00000000 },
{ CS42L43_ASRC_INT2_INPUT1, 0x00000000 },
{ CS42L43_ASRC_INT3_INPUT1, 0x00000000 },
@@ -169,10 +178,14 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = {
{ CS42L43_ISRC1INT2_INPUT1, 0x00000000 },
{ CS42L43_ISRC1DEC1_INPUT1, 0x00000000 },
{ CS42L43_ISRC1DEC2_INPUT1, 0x00000000 },
+ { CS42L43B_ISRC1DEC3_INPUT1, 0x00000000 },
+ { CS42L43B_ISRC1DEC4_INPUT1, 0x00000000 },
{ CS42L43_ISRC2INT1_INPUT1, 0x00000000 },
{ CS42L43_ISRC2INT2_INPUT1, 0x00000000 },
{ CS42L43_ISRC2DEC1_INPUT1, 0x00000000 },
{ CS42L43_ISRC2DEC2_INPUT1, 0x00000000 },
+ { CS42L43B_ISRC2DEC3_INPUT1, 0x00000000 },
+ { CS42L43B_ISRC2DEC4_INPUT1, 0x00000000 },
{ CS42L43_EQ1MIX_INPUT1, 0x00800000 },
{ CS42L43_EQ1MIX_INPUT2, 0x00800000 },
{ CS42L43_EQ1MIX_INPUT3, 0x00800000 },
@@ -269,6 +282,8 @@ EXPORT_SYMBOL_NS_GPL(cs42l43_reg_default, "MFD_CS42L43");
bool cs42l43_readable_register(struct device *dev, unsigned int reg)
{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
+
switch (reg) {
case CS42L43_DEVID:
case CS42L43_REVID:
@@ -292,7 +307,6 @@ bool cs42l43_readable_register(struct device *dev, unsigned int reg)
case CS42L43_ADC_B_CTRL1 ... CS42L43_ADC_B_CTRL2:
case CS42L43_DECIM_HPF_WNF_CTRL1 ... CS42L43_DECIM_HPF_WNF_CTRL4:
case CS42L43_DMIC_PDM_CTRL:
- case CS42L43_DECIM_VOL_CTRL_CH1_CH2 ... CS42L43_DECIM_VOL_CTRL_CH3_CH4:
case CS42L43_INTP_VOLUME_CTRL1 ... CS42L43_INTP_VOLUME_CTRL2:
case CS42L43_AMP1_2_VOL_RAMP:
case CS42L43_ASP_CTRL:
@@ -387,8 +401,16 @@ bool cs42l43_readable_register(struct device *dev, unsigned int reg)
case CS42L43_BOOT_CONTROL:
case CS42L43_BLOCK_EN:
case CS42L43_SHUTTER_CONTROL:
- case CS42L43_MCU_SW_REV ... CS42L43_MCU_RAM_MAX:
- return true;
+ case CS42L43B_MCU_SW_REV ... CS42L43B_MCU_RAM_MAX:
+ return true; // registers present on all variants
+ case CS42L43_MCU_SW_REV ... CS42L43B_MCU_SW_REV - 1:
+ case CS42L43B_MCU_RAM_MAX + 1 ... CS42L43_MCU_RAM_MAX:
+ case CS42L43_DECIM_VOL_CTRL_CH1_CH2 ... CS42L43_DECIM_VOL_CTRL_CH3_CH4:
+ return cs42l43->variant_id == CS42L43_DEVID_VAL; // regs only in CS42L43 variant
+ case CS42L43B_DECIM_VOL_CTRL_CH1_CH2 ... CS42L43B_DECIM_HPF_WNF_CTRL6:
+ case CS42L43B_SWIRE_DP3_CH3_INPUT ... CS42L43B_SWIRE_DP4_CH4_INPUT:
+ case CS42L43B_ISRC1DEC3_INPUT1 ... CS42L43B_ISRC2DEC4_INPUT1:
+ return cs42l43->variant_id == CS42L43B_DEVID_VAL; // regs only in CS42L43B variant
default:
return false;
}
@@ -597,15 +619,27 @@ static int cs42l43_wait_for_attach(struct cs42l43 *cs42l43)
static int cs42l43_mcu_stage_2_3(struct cs42l43 *cs42l43, bool shadow)
{
unsigned int need_reg = CS42L43_NEED_CONFIGS;
+ unsigned int boot_reg;
unsigned int val;
int ret;
- if (shadow)
- need_reg = CS42L43_FW_SH_BOOT_CFG_NEED_CONFIGS;
+ switch (cs42l43->variant_id) {
+ case CS42L43_DEVID_VAL:
+ if (shadow)
+ need_reg = CS42L43_FW_SH_BOOT_CFG_NEED_CONFIGS;
+ boot_reg = CS42L43_BOOT_STATUS;
+ break;
+ case CS42L43B_DEVID_VAL:
+ need_reg = CS42L43B_NEED_CONFIGS;
+ boot_reg = CS42L43B_BOOT_STATUS;
+ break;
+ default:
+ return -EINVAL;
+ }
regmap_write(cs42l43->regmap, need_reg, 0);
- ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_BOOT_STATUS,
+ ret = regmap_read_poll_timeout(cs42l43->regmap, boot_reg,
val, (val == CS42L43_MCU_BOOT_STAGE3),
CS42L43_MCU_POLL_US, CS42L43_MCU_CMD_TIMEOUT_US);
if (ret) {
@@ -644,13 +678,25 @@ static int cs42l43_mcu_stage_3_2(struct cs42l43 *cs42l43)
*/
static int cs42l43_mcu_disable(struct cs42l43 *cs42l43)
{
- unsigned int val;
+ unsigned int val, cfg_reg, ctrl_reg;
int ret;
- regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG,
- CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_DISABLE_VAL);
- regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_CTRL_SELECTION,
- CS42L43_FW_MM_CTRL_MCU_SEL_MASK);
+ switch (cs42l43->variant_id) {
+ case CS42L43_DEVID_VAL:
+ cfg_reg = CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG;
+ ctrl_reg = CS42L43_FW_MISSION_CTRL_MM_CTRL_SELECTION;
+ break;
+ case CS42L43B_DEVID_VAL:
+ cfg_reg = CS42L43B_FW_MISSION_CTRL_MM_MCU_CFG_REG;
+ ctrl_reg = CS42L43B_FW_MISSION_CTRL_MM_CTRL_SELECTION;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_write(cs42l43->regmap, cfg_reg, CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_DISABLE_VAL);
+ regmap_write(cs42l43->regmap, ctrl_reg, CS42L43_FW_MM_CTRL_MCU_SEL_MASK);
+
regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, CS42L43_CONTROL_IND_MASK);
regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, 0);
@@ -740,18 +786,32 @@ static int cs42l43_mcu_update_step(struct cs42l43 *cs42l43)
{
unsigned int mcu_rev, bios_rev, boot_status, secure_cfg;
bool patched, shadow;
+ int boot_status_reg, mcu_sw_rev_reg;
int ret;
+ switch (cs42l43->variant_id) {
+ case CS42L43_DEVID_VAL:
+ boot_status_reg = CS42L43_BOOT_STATUS;
+ mcu_sw_rev_reg = CS42L43_MCU_SW_REV;
+ break;
+ case CS42L43B_DEVID_VAL:
+ boot_status_reg = CS42L43B_BOOT_STATUS;
+ mcu_sw_rev_reg = CS42L43B_MCU_SW_REV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
/* Clear any stale software interrupt bits. */
regmap_read(cs42l43->regmap, CS42L43_SOFT_INT, &mcu_rev);
- ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_STATUS, &boot_status);
+ ret = regmap_read(cs42l43->regmap, boot_status_reg, &boot_status);
if (ret) {
dev_err(cs42l43->dev, "Failed to read boot status: %d\n", ret);
return ret;
}
- ret = regmap_read(cs42l43->regmap, CS42L43_MCU_SW_REV, &mcu_rev);
+ ret = regmap_read(cs42l43->regmap, mcu_sw_rev_reg, &mcu_rev);
if (ret) {
dev_err(cs42l43->dev, "Failed to read firmware revision: %d\n", ret);
return ret;
@@ -918,6 +978,13 @@ static void cs42l43_boot_work(struct work_struct *work)
switch (devid) {
case CS42L43_DEVID_VAL:
+ case CS42L43B_DEVID_VAL:
+ if (devid != cs42l43->variant_id) {
+ dev_err(cs42l43->dev,
+ "Device ID (0x%06x) does not match variant ID (0x%06lx)\n",
+ devid, cs42l43->variant_id);
+ goto err;
+ }
break;
default:
dev_err(cs42l43->dev, "Unrecognised devid: 0x%06x\n", devid);
diff --git a/drivers/mfd/cs42l43.h b/drivers/mfd/cs42l43.h
index f3da783930f5..a0068f6572e2 100644
--- a/drivers/mfd/cs42l43.h
+++ b/drivers/mfd/cs42l43.h
@@ -9,7 +9,7 @@
#ifndef CS42L43_CORE_INT_H
#define CS42L43_CORE_INT_H
-#define CS42L43_N_DEFAULTS 176
+#define CS42L43_N_DEFAULTS 189
struct dev_pm_ops;
struct device;
diff --git a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h
index 6d1ce7f5da51..45850f2d4342 100644
--- a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h
+++ b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h
@@ -140,6 +140,18 @@
#define DISPLAY_PORT_RX_6 134
#define DISPLAY_PORT_RX_7 135
#define USB_RX 136
+#define LPI_MI2S_RX_0 137
+#define LPI_MI2S_TX_0 138
+#define LPI_MI2S_RX_1 139
+#define LPI_MI2S_TX_1 140
+#define LPI_MI2S_RX_2 141
+#define LPI_MI2S_TX_2 142
+#define LPI_MI2S_RX_3 143
+#define LPI_MI2S_TX_3 144
+#define LPI_MI2S_RX_4 145
+#define LPI_MI2S_TX_4 146
+#define SENARY_MI2S_RX 147
+#define SENARY_MI2S_TX 148
#define LPASS_CLK_ID_PRI_MI2S_IBIT 1
#define LPASS_CLK_ID_PRI_MI2S_EBIT 2
diff --git a/include/linux/firmware/cirrus/cs_dsp.h b/include/linux/firmware/cirrus/cs_dsp.h
index 0ec1cdc5585d..4e3baa557068 100644
--- a/include/linux/firmware/cirrus/cs_dsp.h
+++ b/include/linux/firmware/cirrus/cs_dsp.h
@@ -179,6 +179,7 @@ struct cs_dsp {
bool booted;
bool running;
+ bool hibernating;
struct list_head ctl_list;
@@ -354,4 +355,6 @@ int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val);
int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch);
int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits);
+void cs_dsp_hibernate(struct cs_dsp *dsp, bool hibernating);
+
#endif
diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h
index f72e6d4b14a7..d465dcd8c90a 100644
--- a/include/linux/mfd/arizona/pdata.h
+++ b/include/linux/mfd/arizona/pdata.h
@@ -117,11 +117,6 @@ struct arizona_pdata {
/** Check for line output with HPDET method */
bool hpdet_acc_id_line;
-#ifdef CONFIG_GPIOLIB_LEGACY
- /** GPIO used for mic isolation with HPDET */
- int hpdet_id_gpio;
-#endif
-
/** Channel to use for headphone detection */
unsigned int hpdet_channel;
@@ -131,11 +126,6 @@ struct arizona_pdata {
/** Extra debounce timeout used during initial mic detection (ms) */
unsigned int micd_detect_debounce;
-#ifdef CONFIG_GPIOLIB_LEGACY
- /** GPIO for mic detection polarity */
- int micd_pol_gpio;
-#endif
-
/** Mic detect ramp rate */
unsigned int micd_bias_start_time;
diff --git a/include/linux/mfd/cs42l43-regs.h b/include/linux/mfd/cs42l43-regs.h
index c39a49269cb7..68831f113589 100644
--- a/include/linux/mfd/cs42l43-regs.h
+++ b/include/linux/mfd/cs42l43-regs.h
@@ -1181,4 +1181,80 @@
/* CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG */
#define CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_DISABLE_VAL 0xF05AA50F
+/* CS42L43B VARIANT REGISTERS */
+#define CS42L43B_DEVID_VAL 0x0042A43B
+
+#define CS42L43B_DECIM_VOL_CTRL_CH1_CH2 0x00008280
+#define CS42L43B_DECIM_VOL_CTRL_CH3_CH4 0x00008284
+
+#define CS42L43B_DECIM_VOL_CTRL_CH5_CH6 0x00008290
+#define CS42L43B_DECIM_VOL_CTRL_UPDATE 0x0000829C
+
+#define CS42L43B_DECIM_HPF_WNF_CTRL5 0x000082A0
+#define CS42L43B_DECIM_HPF_WNF_CTRL6 0x000082A4
+
+#define CS42L43B_SWIRE_DP3_CH3_INPUT 0x0000C320
+#define CS42L43B_SWIRE_DP3_CH4_INPUT 0x0000C330
+#define CS42L43B_SWIRE_DP4_CH3_INPUT 0x0000C340
+#define CS42L43B_SWIRE_DP4_CH4_INPUT 0x0000C350
+
+#define CS42L43B_ISRC1DEC3_INPUT1 0x0000C780
+#define CS42L43B_ISRC1DEC4_INPUT1 0x0000C790
+#define CS42L43B_ISRC2DEC3_INPUT1 0x0000C7A0
+#define CS42L43B_ISRC2DEC4_INPUT1 0x0000C7B0
+
+#define CS42L43B_FW_MISSION_CTRL_NEED_CONFIGS 0x00117E00
+#define CS42L43B_FW_MISSION_CTRL_HAVE_CONFIGS 0x00117E04
+#define CS42L43B_FW_MISSION_CTRL_PATCH_START_ADDR_REG 0x00117E08
+#define CS42L43B_FW_MISSION_CTRL_MM_CTRL_SELECTION 0x00117E0C
+#define CS42L43B_FW_MISSION_CTRL_MM_MCU_CFG_REG 0x00117E10
+
+#define CS42L43B_MCU_SW_REV 0x00117314
+#define CS42L43B_PATCH_START_ADDR 0x00117318
+#define CS42L43B_CONFIG_SELECTION 0x0011731C
+#define CS42L43B_NEED_CONFIGS 0x00117320
+#define CS42L43B_BOOT_STATUS 0x00117330
+
+#define CS42L43B_FW_MISSION_CTRL_NEED_CONFIGS 0x00117E00
+#define CS42L43B_FW_MISSION_CTRL_HAVE_CONFIGS 0x00117E04
+#define CS42L43B_FW_MISSION_CTRL_PATCH_START_ADDR_REG 0x00117E08
+#define CS42L43B_FW_MISSION_CTRL_MM_CTRL_SELECTION 0x00117E0C
+#define CS42L43B_FW_MISSION_CTRL_MM_MCU_CFG_REG 0x00117E10
+
+#define CS42L43B_MCU_RAM_MAX 0x00117FFF
+
+/* CS42L43B_DECIM_DECIM_VOL_CTRL_CH5_CH6 */
+#define CS42L43B_DECIM6_MUTE_MASK 0x80000000
+#define CS42L43B_DECIM6_MUTE_SHIFT 31
+#define CS42L43B_DECIM6_VOL_MASK 0x3FC00000
+#define CS42L43B_DECIM6_VOL_SHIFT 22
+#define CS42L43B_DECIM6_PATH1_VOL_FALL_RATE_MASK 0x00380000
+#define CS42L43B_DECIM6_PATH1_VOL_FALL_RATE_SHIFT 19
+#define CS42L43B_DECIM6_PATH1_VOL_RISE_RATE_MASK 0x00070000
+#define CS42L43B_DECIM6_PATH1_VOL_RISE_RATE_SHIFT 16
+#define CS42L43B_DECIM5_MUTE_MASK 0x00008000
+#define CS42L43B_DECIM5_MUTE_SHIFT 15
+#define CS42L43B_DECIM5_VOL_MASK 0x00003FC0
+#define CS42L43B_DECIM5_VOL_SHIFT 6
+#define CS42L43B_DECIM5_PATH1_VOL_FALL_RATE_MASK 0x00000038
+#define CS42L43B_DECIM5_PATH1_VOL_FALL_RATE_SHIFT 3
+#define CS42L43B_DECIM5_PATH1_VOL_RISE_RATE_MASK 0x00000007
+#define CS42L43B_DECIM5_PATH1_VOL_RISE_RATE_SHIFT 0
+
+/* CS42L43B_DECIM_VOL_CTRL_UPDATE */
+#define CS42L43B_DECIM6_PATH1_VOL_TRIG_MASK 0x00000800
+#define CS42L43B_DECIM6_PATH1_VOL_TRIG_SHIFT 11
+#define CS42L43B_DECIM5_PATH1_VOL_TRIG_MASK 0x00000100
+#define CS42L43B_DECIM5_PATH1_VOL_TRIG_SHIFT 8
+#define CS42L43B_DECIM4_VOL_UPDATE_MASK 0x00000020
+#define CS42L43B_DECIM4_VOL_UPDATE_SHIFT 5
+
+/* CS42L43_ISRC1_CTRL..CS42L43_ISRC2_CTRL */
+#define CS42L43B_ISRC_DEC4_EN_MASK 0x00000008
+#define CS42L43B_ISRC_DEC4_EN_SHIFT 3
+#define CS42L43B_ISRC_DEC4_EN_WIDTH 1
+#define CS42L43B_ISRC_DEC3_EN_MASK 0x00000004
+#define CS42L43B_ISRC_DEC3_EN_SHIFT 2
+#define CS42L43B_ISRC_DEC3_EN_WIDTH 1
+
#endif /* CS42L43_CORE_REGS_H */
diff --git a/include/linux/mfd/cs42l43.h b/include/linux/mfd/cs42l43.h
index 2239d8585e78..ff0f7e365a19 100644
--- a/include/linux/mfd/cs42l43.h
+++ b/include/linux/mfd/cs42l43.h
@@ -98,6 +98,7 @@ struct cs42l43 {
bool sdw_pll_active;
bool attached;
bool hw_lock;
+ long variant_id;
};
#endif /* CS42L43_CORE_EXT_H */
diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h
index 28f9f5940ab6..c3b10587cb4c 100644
--- a/include/sound/cs35l56.h
+++ b/include/sound/cs35l56.h
@@ -32,9 +32,6 @@ struct snd_ctl_elem_value;
#define CS35L56_UPDATE_REGS 0x0002A0C
#define CS35L56_REFCLK_INPUT 0x0002C04
#define CS35L56_GLOBAL_SAMPLE_RATE 0x0002C0C
-#define CS35L56_OTP_MEM_53 0x00300D4
-#define CS35L56_OTP_MEM_54 0x00300D8
-#define CS35L56_OTP_MEM_55 0x00300DC
#define CS35L56_ASP1_ENABLES1 0x0004800
#define CS35L56_ASP1_CONTROL1 0x0004804
#define CS35L56_ASP1_CONTROL2 0x0004808
@@ -86,6 +83,9 @@ struct snd_ctl_elem_value;
#define CS35L56_DIE_STS1 0x0017040
#define CS35L56_DIE_STS2 0x0017044
#define CS35L56_DSP_RESTRICT_STS1 0x00190F0
+#define CS35L56_OTP_MEM_53 0x00300D4
+#define CS35L56_OTP_MEM_54 0x00300D8
+#define CS35L56_OTP_MEM_55 0x00300DC
#define CS35L56_DSP1_XMEM_PACKED_0 0x2000000
#define CS35L56_DSP1_XMEM_PACKED_6143 0x2005FFC
#define CS35L56_DSP1_XMEM_UNPACKED32_0 0x2400000
@@ -435,6 +435,7 @@ ssize_t cs35l56_cal_data_debugfs_read(struct cs35l56_base *cs35l56_base,
ssize_t cs35l56_cal_data_debugfs_write(struct cs35l56_base *cs35l56_base,
const char __user *from, size_t count,
loff_t *ppos);
+int cs35l56_factory_calibrate(struct cs35l56_base *cs35l56_base);
void cs35l56_create_cal_debugfs(struct cs35l56_base *cs35l56_base,
const struct cs35l56_cal_debugfs_fops *fops);
void cs35l56_remove_cal_debugfs(struct cs35l56_base *cs35l56_base);
diff --git a/include/sound/sdca_asoc.h b/include/sound/sdca_asoc.h
index aa9124f93218..46a61a52decc 100644
--- a/include/sound/sdca_asoc.h
+++ b/include/sound/sdca_asoc.h
@@ -13,6 +13,8 @@
struct device;
struct regmap;
struct sdca_function_data;
+struct snd_ctl_elem_value;
+struct snd_kcontrol;
struct snd_kcontrol_new;
struct snd_pcm_hw_params;
struct snd_pcm_substream;
@@ -23,6 +25,42 @@ struct snd_soc_dai_ops;
struct snd_soc_dapm_route;
struct snd_soc_dapm_widget;
+/* 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) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw, \
+ .get = sdca_asoc_q78_get_volsw, \
+ .put = sdca_asoc_q78_put_volsw, \
+ .private_value = (unsigned long)&(struct soc_mixer_control) { \
+ .reg = (xreg), .rreg = (xreg), \
+ .min = (xmin), .max = (xmax), \
+ .shift = (xstep), .rshift = (xstep), \
+ .sign_bit = 15 \
+ } \
+}
+
+/* convenient macro for stereo volume in 7.8 fixed format with separate registers for L/R */
+#define SDCA_DOUBLE_Q78_TLV(xname, xreg_l, xreg_r, xmin, xmax, xstep, tlv_array) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw, \
+ .get = sdca_asoc_q78_get_volsw, \
+ .put = sdca_asoc_q78_put_volsw, \
+ .private_value = (unsigned long)&(struct soc_mixer_control) { \
+ .reg = (xreg_l), .rreg = (xreg_r), \
+ .min = (xmin), .max = (xmax), \
+ .shift = (xstep), .rshift = (xstep), \
+ .sign_bit = 15 \
+ } \
+}
+
int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *function,
int *num_widgets, int *num_routes, int *num_controls,
int *num_dais);
@@ -57,5 +95,8 @@ int sdca_asoc_hw_params(struct device *dev, struct regmap *regmap,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai);
-
+int sdca_asoc_q78_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int sdca_asoc_q78_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
#endif // __SDCA_ASOC_H__
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index 69a9c9c4d0e9..915e6ae5f68d 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -54,6 +54,11 @@ struct prop_nums {
int platforms;
};
+enum simple_util_sysclk_order {
+ SIMPLE_SYSCLK_ORDER_CODEC_FIRST = 0,
+ SIMPLE_SYSCLK_ORDER_CPU_FIRST,
+};
+
struct simple_util_priv {
struct snd_soc_card snd_card;
struct simple_dai_props {
@@ -63,6 +68,7 @@ struct simple_util_priv {
struct snd_soc_codec_conf *codec_conf;
struct prop_nums num;
unsigned int mclk_fs;
+ enum simple_util_sysclk_order sysclk_order;
} *dai_props;
struct simple_util_jack hp_jack;
struct simple_util_jack mic_jack;
diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h
index 2a2b74b24a60..7e158d27ae8d 100644
--- a/include/sound/soc-component.h
+++ b/include/sound/soc-component.h
@@ -86,10 +86,10 @@ struct snd_soc_component_driver {
unsigned int reg, unsigned int val);
/* pcm creation and destruction */
- int (*pcm_construct)(struct snd_soc_component *component,
- struct snd_soc_pcm_runtime *rtd);
- void (*pcm_destruct)(struct snd_soc_component *component,
- struct snd_pcm *pcm);
+ int (*pcm_new)(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtd);
+ void (*pcm_free)(struct snd_soc_component *component,
+ struct snd_pcm *pcm);
/* component wide operations */
int (*set_sysclk)(struct snd_soc_component *component,
@@ -224,7 +224,6 @@ struct snd_soc_component {
int num_dai;
struct regmap *regmap;
- int val_bytes;
struct mutex io_mutex;
@@ -327,7 +326,7 @@ int snd_soc_component_stream_event(struct snd_soc_component *component,
int snd_soc_component_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level);
-void snd_soc_component_setup_regmap(struct snd_soc_component *component);
+int snd_soc_component_regmap_val_bytes(struct snd_soc_component *component);
#ifdef CONFIG_REGMAP
void snd_soc_component_init_regmap(struct snd_soc_component *component,
struct regmap *regmap);
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 224396927aef..6a42812bba8c 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -53,6 +53,21 @@ struct snd_compr_stream;
#define SND_SOC_POSSIBLE_DAIFMT_PDM (1 << SND_SOC_DAI_FORMAT_PDM)
/*
+ * DAI TDM slot idle modes
+ *
+ * Describes a CODEC/CPU's behaviour when not actively receiving or
+ * transmitting on a given TDM slot. NONE is undefined behaviour.
+ * Add new modes to the end.
+ */
+#define SND_SOC_DAI_TDM_IDLE_NONE 0
+#define SND_SOC_DAI_TDM_IDLE_OFF 1
+#define SND_SOC_DAI_TDM_IDLE_ZERO 2
+#define SND_SOC_DAI_TDM_IDLE_PULLDOWN 3
+#define SND_SOC_DAI_TDM_IDLE_HIZ 4
+#define SND_SOC_DAI_TDM_IDLE_PULLUP 5
+#define SND_SOC_DAI_TDM_IDLE_DRIVE_HIGH 6
+
+/*
* DAI Clock gating.
*
* DAI bit clocks can be gated (disabled) when the DAI is not
@@ -181,6 +196,10 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width);
+int snd_soc_dai_set_tdm_idle(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int tx_mode, int rx_mode);
+
int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
unsigned int tx_num, const unsigned int *tx_slot,
unsigned int rx_num, const unsigned int *rx_slot);
@@ -297,6 +316,9 @@ struct snd_soc_dai_ops {
int (*set_tdm_slot)(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask,
int slots, int slot_width);
+ int (*set_tdm_idle)(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int tx_mode, int rx_mode);
int (*set_channel_map)(struct snd_soc_dai *dai,
unsigned int tx_num, const unsigned int *tx_slot,
unsigned int rx_num, const unsigned int *rx_slot);
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 49f0fe05db01..4f8fb7622a13 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -424,6 +424,7 @@ enum snd_soc_dapm_type {
snd_soc_dapm_input = 0, /* input pin */
snd_soc_dapm_output, /* output pin */
snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
+ snd_soc_dapm_mux_named_ctl, /* mux with named controls */
snd_soc_dapm_demux, /* connects the input to one of multiple outputs */
snd_soc_dapm_mixer, /* mixes several analog signals together */
snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 7d8376c8e1be..5e3eb617d832 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -311,6 +311,12 @@ struct platform_device;
.info = snd_soc_info_bool_ext, \
.get = xhandler_get, .put = xhandler_put, \
.private_value = xdata }
+#define SOC_SINGLE_BOOL_EXT_ACC(xname, xdata, xhandler_get, xhandler_put, xaccess) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = xaccess, \
+ .info = snd_soc_info_bool_ext, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = xdata }
#define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_enum_double, \
@@ -422,11 +428,6 @@ struct snd_soc_jack_pin;
#include <sound/soc-dpcm.h>
#include <sound/soc-topology.h>
-enum snd_soc_pcm_subclass {
- SND_SOC_PCM_CLASS_PCM = 0,
- SND_SOC_PCM_CLASS_BE = 1,
-};
-
int snd_soc_register_card(struct snd_soc_card *card);
void snd_soc_unregister_card(struct snd_soc_card *card);
int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card);
@@ -465,6 +466,7 @@ struct snd_soc_component *snd_soc_lookup_component_nolocked(struct device *dev,
const char *driver_name);
struct snd_soc_component *snd_soc_lookup_component(struct device *dev,
const char *driver_name);
+struct snd_soc_component *snd_soc_lookup_component_by_name(const char *component_name);
int soc_new_pcm(struct snd_soc_pcm_runtime *rtd);
#ifdef CONFIG_SND_SOC_COMPRESS
@@ -999,7 +1001,6 @@ struct snd_soc_card {
/* Mutex for PCM operations */
struct mutex pcm_mutex;
- enum snd_soc_pcm_subclass pcm_subclass;
int (*probe)(struct snd_soc_card *card);
int (*late_probe)(struct snd_soc_card *card);
@@ -1026,8 +1027,6 @@ struct snd_soc_card {
void (*remove_dai_link)(struct snd_soc_card *,
struct snd_soc_dai_link *link);
- long pmdown_time;
-
/* CPU <--> Codec DAI links */
struct snd_soc_dai_link *dai_link; /* predefined links only */
int num_links; /* predefined links only */
@@ -1072,9 +1071,6 @@ struct snd_soc_card {
struct list_head dapm_list;
struct list_head dapm_dirty;
- /* attached dynamic objects */
- struct list_head dobj_list;
-
/* Generic DAPM context for the card */
struct snd_soc_dapm_context *dapm;
struct snd_soc_dapm_stats dapm_stats;
@@ -1239,7 +1235,6 @@ struct soc_mixer_control {
unsigned int sign_bit;
unsigned int invert:1;
unsigned int autodisable:1;
- unsigned int sdca_q78:1;
#ifdef CONFIG_SND_SOC_TOPOLOGY
struct snd_soc_dobj dobj;
#endif
@@ -1340,15 +1335,6 @@ void snd_soc_of_parse_node_prefix(struct device_node *np,
struct snd_soc_codec_conf *codec_conf,
struct device_node *of_node,
const char *propname);
-static inline
-void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
- struct snd_soc_codec_conf *codec_conf,
- struct device_node *of_node,
- const char *propname)
-{
- snd_soc_of_parse_node_prefix(card->dev->of_node,
- codec_conf, of_node, propname);
-}
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname);
@@ -1412,6 +1398,9 @@ struct snd_soc_dai *snd_soc_find_dai(
struct snd_soc_dai *snd_soc_find_dai_with_mutex(
const struct snd_soc_dai_link_component *dlc);
+void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
+ struct snd_pcm_hw_params *params);
+
#include <sound/soc-dai.h>
static inline
@@ -1517,7 +1506,7 @@ static inline void _snd_soc_dapm_mutex_assert_held_d(struct snd_soc_dapm_context
*/
static inline void _snd_soc_dpcm_mutex_lock_c(struct snd_soc_card *card)
{
- mutex_lock_nested(&card->pcm_mutex, card->pcm_subclass);
+ mutex_lock(&card->pcm_mutex);
}
static inline void _snd_soc_dpcm_mutex_unlock_c(struct snd_soc_card *card)
diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h
index 227347c8f0b3..489083183673 100644
--- a/include/sound/soc_sdw_utils.h
+++ b/include/sound/soc_sdw_utils.h
@@ -71,6 +71,7 @@ struct asoc_sdw_aux_info {
};
struct asoc_sdw_codec_info {
+ const int vendor_id;
const int part_id;
const int version_id;
const char *name_prefix;
@@ -82,6 +83,8 @@ struct asoc_sdw_codec_info {
const int dai_num;
struct asoc_sdw_aux_info auxs[SOC_SDW_MAX_AUX_NUM];
const int aux_num;
+ /* Force AMP-style name_prefix handling (append AMP index) even if MIC/Jack DAIs exist */
+ const bool is_amp;
int (*codec_card_late_probe)(struct snd_soc_card *card);
@@ -259,6 +262,8 @@ int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_so
int asoc_sdw_cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_cs42l45_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_cs42l45_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
+int asoc_sdw_cs47l47_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
+int asoc_sdw_cs47l47_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
/* TI */
diff --git a/include/sound/uda1380.h b/include/sound/uda1380.h
deleted file mode 100644
index 2e42ea2d0cfd..000000000000
--- a/include/sound/uda1380.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * UDA1380 ALSA SoC Codec driver
- *
- * Copyright 2009 Philipp Zabel
- */
-
-#ifndef __UDA1380_H
-#define __UDA1380_H
-
-struct uda1380_platform_data {
- int gpio_power;
- int gpio_reset;
- int dac_clk;
-#define UDA1380_DAC_CLK_SYSCLK 0
-#define UDA1380_DAC_CLK_WSPLL 1
-};
-
-#endif /* __UDA1380_H */
diff --git a/sound/hda/codecs/side-codecs/Kconfig b/sound/hda/codecs/side-codecs/Kconfig
index f674e9a9c7d7..fc5651e555e3 100644
--- a/sound/hda/codecs/side-codecs/Kconfig
+++ b/sound/hda/codecs/side-codecs/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config SND_HDA_CIRRUS_SCODEC
tristate
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index f7c3010624df..53139766fafb 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -122,16 +122,6 @@ config SND_AMD_ACP_CONFIG
source "sound/soc/amd/acp/Kconfig"
-config SND_SOC_AMD_RPL_ACP6x
- tristate "AMD Audio Coprocessor-v6.2 RPL support"
- depends on X86 && PCI
- help
- This option enables Audio Coprocessor i.e. ACP v6.2 support on
- AMD RPL platform. By enabling this flag build will be
- triggered for ACP PCI driver.
- Say m if you have such a device.
- If unsure select "N".
-
config SND_SOC_AMD_ACP63_TOPLEVEL
tristate "support for AMD platforms with ACP version >= 6.3"
default SND_AMD_ACP_CONFIG
diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile
index 4f89d962cce2..23b25ff0d800 100644
--- a/sound/soc/amd/Makefile
+++ b/sound/soc/amd/Makefile
@@ -17,5 +17,4 @@ obj-$(CONFIG_SND_SOC_AMD_ACP5x) += vangogh/
obj-$(CONFIG_SND_SOC_AMD_ACP6x) += yc/
obj-$(CONFIG_SND_AMD_ACP_CONFIG) += acp/
obj-$(CONFIG_SND_AMD_ACP_CONFIG) += snd-acp-config.o
-obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += rpl/
obj-$(CONFIG_SND_SOC_AMD_PS) += ps/
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
index 42aa009c4e13..af559653e625 100644
--- a/sound/soc/amd/acp-da7219-max98357a.c
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -11,7 +11,6 @@
#include <sound/soc-dapm.h>
#include <sound/jack.h>
#include <linux/clk.h>
-#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/driver.h>
@@ -48,8 +47,6 @@ static struct clk *da7219_dai_bclk;
static struct clk *rt5682_dai_wclk;
static struct clk *rt5682_dai_bclk;
-void *acp_soc_is_rltk_max(struct device *dev);
-
static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
{
int ret;
@@ -704,7 +701,7 @@ static struct snd_soc_card cz_rt5682_card = {
.num_controls = ARRAY_SIZE(cz_mc_controls),
};
-void *acp_soc_is_rltk_max(struct device *dev)
+static void *acp_soc_is_rltk_max(struct device *dev)
{
const struct acpi_device_id *match;
diff --git a/sound/soc/amd/acp-es8336.c b/sound/soc/amd/acp-es8336.c
index b16dde0e2987..9f3f11256788 100644
--- a/sound/soc/amd/acp-es8336.c
+++ b/sound/soc/amd/acp-es8336.c
@@ -11,7 +11,6 @@
#include <sound/pcm_params.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/gpio/consumer.h>
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index c76a4bcc9645..6ad70aa0ea83 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -1252,7 +1252,7 @@ static const struct snd_soc_component_driver acp_asoc_platform = {
.pointer = acp_dma_pointer,
.delay = acp_dma_delay,
.prepare = acp_dma_prepare,
- .pcm_construct = acp_dma_new,
+ .pcm_new = acp_dma_new,
};
static int acp_audio_probe(struct platform_device *pdev)
diff --git a/sound/soc/amd/acp-rt5645.c b/sound/soc/amd/acp-rt5645.c
index 11d373169380..5c38fa11db7a 100644
--- a/sound/soc/amd/acp-rt5645.c
+++ b/sound/soc/amd/acp-rt5645.c
@@ -1,29 +1,10 @@
+// SPDX-License-Identifier: MIT
/*
* Machine driver for AMD ACP Audio engine using Realtek RT5645 codec
*
* Copyright 2017 Advanced Micro Devices, Inc.
*
* This file is modified from rt288 machine driver
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- *
*/
#include <sound/core.h>
@@ -32,7 +13,6 @@
#include <sound/pcm_params.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c
index 88613569fd64..6b1e18b31c1c 100644
--- a/sound/soc/amd/acp/acp-platform.c
+++ b/sound/soc/amd/acp/acp-platform.c
@@ -321,7 +321,7 @@ static const struct snd_soc_component_driver acp_pcm_component = {
.close = acp_dma_close,
.hw_params = acp_dma_hw_params,
.pointer = acp_dma_pointer,
- .pcm_construct = acp_dma_new,
+ .pcm_new = acp_dma_new,
.legacy_dai_naming = 1,
};
diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
index cd7b1acc7216..0f21e5f64531 100644
--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
@@ -394,10 +394,8 @@ static int create_dmic_dailinks(struct snd_soc_card *card,
static int soc_card_dai_links_create(struct snd_soc_card *card)
{
struct device *dev = card->dev;
- struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
int sdw_be_num = 0, dmic_num = 0;
struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
struct snd_soc_aux_dev *soc_aux;
struct snd_soc_codec_conf *codec_conf;
struct snd_soc_dai_link *dai_links;
@@ -440,7 +438,7 @@ static int soc_card_dai_links_create(struct snd_soc_card *card)
sdw_be_num = ret;
/* enable dmic */
- if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC || mach_params->dmic_num)
+ if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC)
dmic_num = 1;
dev_dbg(dev, "sdw %d, dmic %d", sdw_be_num, dmic_num);
@@ -551,11 +549,11 @@ static int mc_probe(struct platform_device *pdev)
" cfg-amp:%d", amp_num);
if (!card->components)
return -ENOMEM;
- if (mach->mach_params.dmic_num) {
+ if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC) {
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s mic:dmic cfg-mics:%d",
+ "%s mic:acp-dmic cfg-mics:%d",
card->components,
- mach->mach_params.dmic_num);
+ 1);
if (!card->components)
return -ENOMEM;
}
diff --git a/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c b/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c
index 141ea4787d99..46fff565d732 100644
--- a/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c
+++ b/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c
@@ -11,7 +11,6 @@
#include <sound/jack.h>
#include <sound/soc-acpi.h>
#include <linux/clk.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/i2c.h>
diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c
index d1eb6f12a183..4affb00bdc95 100644
--- a/sound/soc/amd/acp3x-rt5682-max9836.c
+++ b/sound/soc/amd/acp3x-rt5682-max9836.c
@@ -11,7 +11,6 @@
#include <sound/soc-dapm.h>
#include <sound/jack.h>
#include <linux/clk.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/i2c.h>
diff --git a/sound/soc/amd/include/acp_2_2_d.h b/sound/soc/amd/include/acp_2_2_d.h
index 0118fe9e6a87..d07ec8646ee8 100644
--- a/sound/soc/amd/include/acp_2_2_d.h
+++ b/sound/soc/amd/include/acp_2_2_d.h
@@ -1,24 +1,8 @@
+/* SPDX-License-Identifier: MIT */
/*
* ACP_2_2 Register documentation
*
* Copyright (C) 2014 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef ACP_2_2_D_H
diff --git a/sound/soc/amd/include/acp_2_2_enum.h b/sound/soc/amd/include/acp_2_2_enum.h
index f3577c851086..26c7993ac395 100644
--- a/sound/soc/amd/include/acp_2_2_enum.h
+++ b/sound/soc/amd/include/acp_2_2_enum.h
@@ -1,24 +1,8 @@
+/* SPDX-License-Identifier: MIT */
/*
* ACP_2_2 Register documentation
*
* Copyright (C) 2014 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef ACP_2_2_ENUM_H
diff --git a/sound/soc/amd/include/acp_2_2_sh_mask.h b/sound/soc/amd/include/acp_2_2_sh_mask.h
index 32d2d4104309..9749c11e733f 100644
--- a/sound/soc/amd/include/acp_2_2_sh_mask.h
+++ b/sound/soc/amd/include/acp_2_2_sh_mask.h
@@ -1,24 +1,8 @@
+/* SPDX-License-Identifier: MIT */
/*
* ACP_2_2 Register documentation
*
* Copyright (C) 2014 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef ACP_2_2_SH_MASK_H
diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c
index 7c529fc6ba99..04c014349347 100644
--- a/sound/soc/amd/ps/ps-pdm-dma.c
+++ b/sound/soc/amd/ps/ps-pdm-dma.c
@@ -351,7 +351,8 @@ static const struct snd_soc_component_driver acp63_pdm_component = {
.close = acp63_pdm_dma_close,
.hw_params = acp63_pdm_dma_hw_params,
.pointer = acp63_pdm_dma_pointer,
- .pcm_construct = acp63_pdm_dma_new,
+ .pcm_new = acp63_pdm_dma_new,
+ .use_dai_pcm_id = true,
};
static int acp63_pdm_audio_probe(struct platform_device *pdev)
diff --git a/sound/soc/amd/ps/ps-sdw-dma.c b/sound/soc/amd/ps/ps-sdw-dma.c
index 366d7c4bb07e..f27ebbd21379 100644
--- a/sound/soc/amd/ps/ps-sdw-dma.c
+++ b/sound/soc/amd/ps/ps-sdw-dma.c
@@ -634,7 +634,7 @@ static const struct snd_soc_component_driver acp63_sdw_component = {
.hw_params = acp63_sdw_dma_hw_params,
.trigger = acp63_sdw_dma_trigger,
.pointer = acp63_sdw_dma_pointer,
- .pcm_construct = acp63_sdw_dma_new,
+ .pcm_new = acp63_sdw_dma_new,
.use_dai_pcm_id = true,
};
diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c
index 4529404ebd93..37ea5c572eb9 100644
--- a/sound/soc/amd/raven/acp3x-pcm-dma.c
+++ b/sound/soc/amd/raven/acp3x-pcm-dma.c
@@ -363,7 +363,7 @@ static const struct snd_soc_component_driver acp3x_i2s_component = {
.close = acp3x_dma_close,
.hw_params = acp3x_dma_hw_params,
.pointer = acp3x_dma_pointer,
- .pcm_construct = acp3x_dma_new,
+ .pcm_new = acp3x_dma_new,
};
static int acp3x_audio_probe(struct platform_device *pdev)
diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c
index e832c7c4b96f..e60e3821703c 100644
--- a/sound/soc/amd/renoir/acp3x-pdm-dma.c
+++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c
@@ -376,7 +376,7 @@ static const struct snd_soc_component_driver acp_pdm_component = {
.close = acp_pdm_dma_close,
.hw_params = acp_pdm_dma_hw_params,
.pointer = acp_pdm_dma_pointer,
- .pcm_construct = acp_pdm_dma_new,
+ .pcm_new = acp_pdm_dma_new,
.legacy_dai_naming = 1,
};
diff --git a/sound/soc/amd/rpl/Makefile b/sound/soc/amd/rpl/Makefile
deleted file mode 100644
index a3825c5be4e7..000000000000
--- a/sound/soc/amd/rpl/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0+
-# RPL platform Support
-snd-rpl-pci-acp6x-y := rpl-pci-acp6x.o
-
-obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += snd-rpl-pci-acp6x.o
diff --git a/sound/soc/amd/rpl/rpl-pci-acp6x.c b/sound/soc/amd/rpl/rpl-pci-acp6x.c
deleted file mode 100644
index e3afe9172bdf..000000000000
--- a/sound/soc/amd/rpl/rpl-pci-acp6x.c
+++ /dev/null
@@ -1,227 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * AMD RPL ACP PCI Driver
- *
- * Copyright 2022 Advanced Micro Devices, Inc.
- */
-
-#include <linux/pci.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-
-#include "rpl_acp6x.h"
-
-struct rpl_dev_data {
- void __iomem *acp6x_base;
-};
-
-static int rpl_power_on(void __iomem *acp_base)
-{
- u32 val;
- int timeout;
-
- val = rpl_acp_readl(acp_base + ACP_PGFSM_STATUS);
-
- if (!val)
- return val;
-
- if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS)
- rpl_acp_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
- timeout = 0;
- while (++timeout < 500) {
- val = rpl_acp_readl(acp_base + ACP_PGFSM_STATUS);
- if (!val)
- return 0;
- udelay(1);
- }
- return -ETIMEDOUT;
-}
-
-static int rpl_reset(void __iomem *acp_base)
-{
- u32 val;
- int timeout;
-
- rpl_acp_writel(1, acp_base + ACP_SOFT_RESET);
- timeout = 0;
- while (++timeout < 500) {
- val = rpl_acp_readl(acp_base + ACP_SOFT_RESET);
- if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK)
- break;
- cpu_relax();
- }
- rpl_acp_writel(0, acp_base + ACP_SOFT_RESET);
- timeout = 0;
- while (++timeout < 500) {
- val = rpl_acp_readl(acp_base + ACP_SOFT_RESET);
- if (!val)
- return 0;
- cpu_relax();
- }
- return -ETIMEDOUT;
-}
-
-static int rpl_init(void __iomem *acp_base)
-{
- int ret;
-
- /* power on */
- ret = rpl_power_on(acp_base);
- if (ret) {
- pr_err("ACP power on failed\n");
- return ret;
- }
- rpl_acp_writel(0x01, acp_base + ACP_CONTROL);
- /* Reset */
- ret = rpl_reset(acp_base);
- if (ret) {
- pr_err("ACP reset failed\n");
- return ret;
- }
- rpl_acp_writel(0x03, acp_base + ACP_CLKMUX_SEL);
- return 0;
-}
-
-static int rpl_deinit(void __iomem *acp_base)
-{
- int ret;
-
- /* Reset */
- ret = rpl_reset(acp_base);
- if (ret) {
- pr_err("ACP reset failed\n");
- return ret;
- }
- rpl_acp_writel(0x00, acp_base + ACP_CLKMUX_SEL);
- rpl_acp_writel(0x00, acp_base + ACP_CONTROL);
- return 0;
-}
-
-static int snd_rpl_probe(struct pci_dev *pci,
- const struct pci_device_id *pci_id)
-{
- struct rpl_dev_data *adata;
- u32 addr;
- int ret;
-
- /* RPL device check */
- switch (pci->revision) {
- case 0x62:
- break;
- default:
- dev_dbg(&pci->dev, "acp6x pci device not found\n");
- return -ENODEV;
- }
- if (pci_enable_device(pci)) {
- dev_err(&pci->dev, "pci_enable_device failed\n");
- return -ENODEV;
- }
-
- ret = pci_request_regions(pci, "AMD ACP6x audio");
- if (ret < 0) {
- dev_err(&pci->dev, "pci_request_regions failed\n");
- goto disable_pci;
- }
-
- adata = devm_kzalloc(&pci->dev, sizeof(struct rpl_dev_data),
- GFP_KERNEL);
- if (!adata) {
- ret = -ENOMEM;
- goto release_regions;
- }
-
- addr = pci_resource_start(pci, 0);
- adata->acp6x_base = devm_ioremap(&pci->dev, addr,
- pci_resource_len(pci, 0));
- if (!adata->acp6x_base) {
- ret = -ENOMEM;
- goto release_regions;
- }
- pci_set_master(pci);
- pci_set_drvdata(pci, adata);
- ret = rpl_init(adata->acp6x_base);
- if (ret)
- goto release_regions;
- pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
- pm_runtime_use_autosuspend(&pci->dev);
- pm_runtime_put_noidle(&pci->dev);
- pm_runtime_allow(&pci->dev);
-
- return 0;
-release_regions:
- pci_release_regions(pci);
-disable_pci:
- pci_disable_device(pci);
-
- return ret;
-}
-
-static int snd_rpl_suspend(struct device *dev)
-{
- struct rpl_dev_data *adata;
- int ret;
-
- adata = dev_get_drvdata(dev);
- ret = rpl_deinit(adata->acp6x_base);
- if (ret)
- dev_err(dev, "ACP de-init failed\n");
- return ret;
-}
-
-static int snd_rpl_resume(struct device *dev)
-{
- struct rpl_dev_data *adata;
- int ret;
-
- adata = dev_get_drvdata(dev);
- ret = rpl_init(adata->acp6x_base);
- if (ret)
- dev_err(dev, "ACP init failed\n");
- return ret;
-}
-
-static const struct dev_pm_ops rpl_pm = {
- RUNTIME_PM_OPS(snd_rpl_suspend, snd_rpl_resume, NULL)
- SYSTEM_SLEEP_PM_OPS(snd_rpl_suspend, snd_rpl_resume)
-};
-
-static void snd_rpl_remove(struct pci_dev *pci)
-{
- struct rpl_dev_data *adata;
- int ret;
-
- adata = pci_get_drvdata(pci);
- ret = rpl_deinit(adata->acp6x_base);
- if (ret)
- dev_err(&pci->dev, "ACP de-init failed\n");
- pm_runtime_forbid(&pci->dev);
- pm_runtime_get_noresume(&pci->dev);
- pci_release_regions(pci);
- pci_disable_device(pci);
-}
-
-static const struct pci_device_id snd_rpl_ids[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID),
- .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
- .class_mask = 0xffffff },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, snd_rpl_ids);
-
-static struct pci_driver rpl_acp6x_driver = {
- .name = KBUILD_MODNAME,
- .id_table = snd_rpl_ids,
- .probe = snd_rpl_probe,
- .remove = snd_rpl_remove,
- .driver = {
- .pm = pm_ptr(&rpl_pm),
- }
-};
-
-module_pci_driver(rpl_acp6x_driver);
-
-MODULE_DESCRIPTION("AMD ACP RPL PCI driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/rpl/rpl_acp6x.h b/sound/soc/amd/rpl/rpl_acp6x.h
deleted file mode 100644
index f5816a33632e..000000000000
--- a/sound/soc/amd/rpl/rpl_acp6x.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * AMD ACP Driver
- *
- * Copyright (C) 2021 Advanced Micro Devices, Inc. All rights reserved.
- */
-
-#include "rpl_acp6x_chip_offset_byte.h"
-
-#define ACP_DEVICE_ID 0x15E2
-#define ACP6x_PHY_BASE_ADDRESS 0x1240000
-
-#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001
-#define ACP_PGFSM_CNTL_POWER_ON_MASK 1
-#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0
-#define ACP_PGFSM_STATUS_MASK 3
-#define ACP_POWERED_ON 0
-#define ACP_POWER_ON_IN_PROGRESS 1
-#define ACP_POWERED_OFF 2
-#define ACP_POWER_OFF_IN_PROGRESS 3
-
-#define DELAY_US 5
-#define ACP_COUNTER 20000
-
-/* time in ms for runtime suspend delay */
-#define ACP_SUSPEND_DELAY_MS 2000
-
-static inline u32 rpl_acp_readl(void __iomem *base_addr)
-{
- return readl(base_addr - ACP6x_PHY_BASE_ADDRESS);
-}
-
-static inline void rpl_acp_writel(u32 val, void __iomem *base_addr)
-{
- writel(val, base_addr - ACP6x_PHY_BASE_ADDRESS);
-}
diff --git a/sound/soc/amd/rpl/rpl_acp6x_chip_offset_byte.h b/sound/soc/amd/rpl/rpl_acp6x_chip_offset_byte.h
deleted file mode 100644
index 456498f5396d..000000000000
--- a/sound/soc/amd/rpl/rpl_acp6x_chip_offset_byte.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * AMD ACP 6.2 Register Documentation
- *
- * Copyright 2022 Advanced Micro Devices, Inc.
- */
-
-#ifndef _rpl_acp6x_OFFSET_HEADER
-#define _rpl_acp6x_OFFSET_HEADER
-
-/* Registers from ACP_CLKRST block */
-#define ACP_SOFT_RESET 0x1241000
-#define ACP_CONTROL 0x1241004
-#define ACP_STATUS 0x1241008
-#define ACP_DYNAMIC_CG_MASTER_CONTROL 0x1241010
-#define ACP_PGFSM_CONTROL 0x124101C
-#define ACP_PGFSM_STATUS 0x1241020
-#define ACP_CLKMUX_SEL 0x1241024
-
-/* Registers from ACP_AON block */
-#define ACP_PME_EN 0x1241400
-#define ACP_DEVICE_STATE 0x1241404
-#define AZ_DEVICE_STATE 0x1241408
-#define ACP_PIN_CONFIG 0x1241440
-#define ACP_PAD_PULLUP_CTRL 0x1241444
-#define ACP_PAD_PULLDOWN_CTRL 0x1241448
-#define ACP_PAD_DRIVE_STRENGTH_CTRL 0x124144C
-#define ACP_PAD_SCHMEN_CTRL 0x1241450
-
-#endif
diff --git a/sound/soc/amd/vangogh/acp5x-pcm-dma.c b/sound/soc/amd/vangogh/acp5x-pcm-dma.c
index 6ce82cd8859b..831e30e9b042 100644
--- a/sound/soc/amd/vangogh/acp5x-pcm-dma.c
+++ b/sound/soc/amd/vangogh/acp5x-pcm-dma.c
@@ -357,7 +357,7 @@ static const struct snd_soc_component_driver acp5x_i2s_component = {
.close = acp5x_dma_close,
.hw_params = acp5x_dma_hw_params,
.pointer = acp5x_dma_pointer,
- .pcm_construct = acp5x_dma_new,
+ .pcm_new = acp5x_dma_new,
};
static int acp5x_audio_probe(struct platform_device *pdev)
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index aa6200933182..c5cf45881416 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -48,6 +48,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
{
.driver_data = &acp6x_card,
.matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Lecoo"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Bellator N176"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Laptop 15-fc0xxx"),
}
@@ -496,6 +503,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
{
.driver_data = &acp6x_card,
.matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Vector A16 HX A8WHG"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"),
}
@@ -734,6 +748,20 @@ 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_BOARD_NAME, "BM1403CDA"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Thin A15 B7VF"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
DMI_MATCH(DMI_PRODUCT_NAME, "Thin A15 B7VE"),
}
diff --git a/sound/soc/amd/yc/acp6x-pdm-dma.c b/sound/soc/amd/yc/acp6x-pdm-dma.c
index 1c8aad849916..710db721ffa4 100644
--- a/sound/soc/amd/yc/acp6x-pdm-dma.c
+++ b/sound/soc/amd/yc/acp6x-pdm-dma.c
@@ -346,7 +346,7 @@ static const struct snd_soc_component_driver acp6x_pdm_component = {
.close = acp6x_pdm_dma_close,
.hw_params = acp6x_pdm_dma_hw_params,
.pointer = acp6x_pdm_dma_pointer,
- .pcm_construct = acp6x_pdm_dma_new,
+ .pcm_new = acp6x_pdm_dma_new,
.legacy_dai_naming = 1,
};
diff --git a/sound/soc/amd/yc/pci-acp6x.c b/sound/soc/amd/yc/pci-acp6x.c
index 1140ed1cbb3d..671443204e04 100644
--- a/sound/soc/amd/yc/pci-acp6x.c
+++ b/sound/soc/amd/yc/pci-acp6x.c
@@ -163,6 +163,7 @@ static int snd_acp6x_probe(struct pci_dev *pci,
switch (pci->revision) {
case 0x60:
case 0x6f:
+ case 0x62: /* RPL */
break;
default:
dev_dbg(&pci->dev, "acp6x pci device not found\n");
@@ -208,6 +209,17 @@ static int snd_acp6x_probe(struct pci_dev *pci,
case ACP_CONFIG_15:
dev_info(&pci->dev, "Audio Mode %d\n", val);
break;
+ case ACP_CONFIG_10:
+ case ACP_CONFIG_11:
+ case ACP_CONFIG_12:
+ case ACP_CONFIG_13:
+ case ACP_CONFIG_14:
+ /* PIN 10 to 14 is reserve for RPL */
+ if (pci->revision == 0x62) {
+ dev_info(&pci->dev, "RPL Audio Mode %d\n", val);
+ break;
+ }
+ fallthrough;
default:
adata->res = devm_kzalloc(&pci->dev,
sizeof(struct resource),
diff --git a/sound/soc/apple/Kconfig b/sound/soc/apple/Kconfig
index d8dc2f1ccc83..f1d071a99fbf 100644
--- a/sound/soc/apple/Kconfig
+++ b/sound/soc/apple/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
menu "Apple"
config SND_SOC_APPLE_MCA
diff --git a/sound/soc/apple/Makefile b/sound/soc/apple/Makefile
index 1eb8fbef60c6..252ba5fc18cb 100644
--- a/sound/soc/apple/Makefile
+++ b/sound/soc/apple/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
snd-soc-apple-mca-y := mca.o
obj-$(CONFIG_SND_SOC_APPLE_MCA) += snd-soc-apple-mca.o
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index c4dcb2b54591..39269cc7def6 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -1002,8 +1002,8 @@ static const struct snd_soc_component_driver mca_component = {
.hw_params = mca_hw_params,
.trigger = mca_trigger,
.pointer = mca_pointer,
- .pcm_construct = mca_pcm_new,
- .pcm_destruct = mca_pcm_free,
+ .pcm_new = mca_pcm_new,
+ .pcm_free = mca_pcm_free,
};
static void apple_mca_release(struct mca_data *mca)
diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c
index 1a0c584801f0..374f93fa6e0b 100644
--- a/sound/soc/atmel/atmel-pcm-pdc.c
+++ b/sound/soc/atmel/atmel-pcm-pdc.c
@@ -316,7 +316,7 @@ static const struct snd_soc_component_driver atmel_soc_platform = {
.prepare = atmel_pcm_prepare,
.trigger = atmel_pcm_trigger,
.pointer = atmel_pcm_pointer,
- .pcm_construct = atmel_pcm_new,
+ .pcm_new = atmel_pcm_new,
};
int atmel_pcm_pdc_platform_register(struct device *dev)
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index 3392693faeb9..3d10d6460472 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -319,7 +319,7 @@ static const struct snd_soc_component_driver au1xpsc_soc_component = {
.prepare = au1xpsc_pcm_prepare,
.trigger = au1xpsc_pcm_trigger,
.pointer = au1xpsc_pcm_pointer,
- .pcm_construct = au1xpsc_pcm_new,
+ .pcm_new = au1xpsc_pcm_new,
};
static int au1xpsc_pcm_drvprobe(struct platform_device *pdev)
diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
index 8d91a0e0f112..026d9f36db10 100644
--- a/sound/soc/au1x/dma.c
+++ b/sound/soc/au1x/dma.c
@@ -296,7 +296,7 @@ static const struct snd_soc_component_driver alchemy_pcm_soc_component = {
.hw_free = alchemy_pcm_hw_free,
.trigger = alchemy_pcm_trigger,
.pointer = alchemy_pcm_pointer,
- .pcm_construct = alchemy_pcm_new,
+ .pcm_new = alchemy_pcm_new,
};
static int alchemy_pcm_drvprobe(struct platform_device *pdev)
diff --git a/sound/soc/bcm/bcm63xx-pcm-whistler.c b/sound/soc/bcm/bcm63xx-pcm-whistler.c
index 6a3fd0d89365..a40f6bed69c6 100644
--- a/sound/soc/bcm/bcm63xx-pcm-whistler.c
+++ b/sound/soc/bcm/bcm63xx-pcm-whistler.c
@@ -386,7 +386,7 @@ static const struct snd_soc_component_driver bcm63xx_soc_platform = {
.prepare = bcm63xx_pcm_prepare,
.trigger = bcm63xx_pcm_trigger,
.pointer = bcm63xx_pcm_pointer,
- .pcm_construct = bcm63xx_soc_pcm_new,
+ .pcm_new = bcm63xx_soc_pcm_new,
};
int bcm63xx_soc_platform_probe(struct platform_device *pdev,
diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c
index 4cb2fe10bcdc..dc243f2dfd32 100644
--- a/sound/soc/bcm/cygnus-pcm.c
+++ b/sound/soc/bcm/cygnus-pcm.c
@@ -713,7 +713,7 @@ static const struct snd_soc_component_driver cygnus_soc_platform = {
.prepare = cygnus_pcm_prepare,
.trigger = cygnus_pcm_trigger,
.pointer = cygnus_pcm_pointer,
- .pcm_construct = cygnus_dma_new,
+ .pcm_new = cygnus_dma_new,
};
int cygnus_soc_platform_register(struct device *dev,
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index adb3fb923be3..cf94a1c756e0 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -398,31 +398,21 @@ config SND_SOC_WM_HUBS
default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m
config SND_SOC_WM_ADSP
- tristate
+ tristate "Cirrus Logic wm_adsp driver" if KUNIT
select FW_CS_DSP
select SND_SOC_COMPRESS
- default y if SND_SOC_MADERA=y
- default y if SND_SOC_CS47L24=y
- default y if SND_SOC_WM5102=y
- default y if SND_SOC_WM5110=y
- default y if SND_SOC_WM2200=y
- default y if SND_SOC_CS35L41_SPI=y
- default y if SND_SOC_CS35L41_I2C=y
- default y if SND_SOC_CS35L45_SPI=y
- default y if SND_SOC_CS35L45_I2C=y
- default y if SND_SOC_CS35L56=y
- default y if SND_SOC_CS48L32=y
- default m if SND_SOC_MADERA=m
- default m if SND_SOC_CS47L24=m
- default m if SND_SOC_WM5102=m
- default m if SND_SOC_WM5110=m
- default m if SND_SOC_WM2200=m
- default m if SND_SOC_CS35L41_SPI=m
- default m if SND_SOC_CS35L41_I2C=m
- default m if SND_SOC_CS35L45_SPI=m
- default m if SND_SOC_CS35L45_I2C=m
- default m if SND_SOC_CS35L56=m
- default m if SND_SOC_CS48L32=m
+
+config SND_SOC_WM_ADSP_TEST
+ tristate "KUnit tests for Cirrus Logic wm_adsp" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ depends on SND_SOC_WM_ADSP
+ default KUNIT_ALL_TESTS
+ help
+ This builds KUnit tests for the Cirrus Logic wm_adsp library.
+ For more information on KUnit and unit tests in general,
+ please refer to the KUnit documentation in
+ Documentation/dev-tools/kunit/.
+ If in doubt, say "N".
config SND_SOC_AB8500_CODEC
tristate
@@ -822,6 +812,7 @@ config SND_SOC_CS35L41_LIB
config SND_SOC_CS35L41
tristate
+ select SND_SOC_WM_ADSP
config SND_SOC_CS35L41_SPI
tristate "Cirrus Logic CS35L41 CODEC (SPI)"
@@ -840,6 +831,7 @@ config SND_SOC_CS35L41_I2C
config SND_SOC_CS35L45
tristate
select REGMAP_IRQ
+ select SND_SOC_WM_ADSP
config SND_SOC_CS35L45_SPI
tristate "Cirrus Logic CS35L45 CODEC (SPI)"
@@ -863,6 +855,7 @@ config SND_SOC_CS35L45_I2C
config SND_SOC_CS35L56
tristate
+ select SND_SOC_WM_ADSP
config SND_SOC_CS35L56_SHARED
select SND_SOC_CS_AMP_LIB
@@ -928,6 +921,19 @@ config SND_SOC_CS35L56_CAL_SET_CTRL
If unsure select "N".
+config SND_SOC_CS35L56_CAL_PERFORM_CTRL
+ bool "CS35L56 ALSA control to perform factory calibration"
+ default N
+ select SND_SOC_CS35L56_CAL_DEBUGFS_COMMON
+ help
+ Allow performing factory calibration data through an ALSA
+ control. It is recommended to use the debugfs method instead
+ because debugfs has restricted access permissions.
+
+ On most platforms this is not needed.
+
+ If unsure select "N".
+
config SND_SOC_CS35L56_TEST
tristate "KUnit test for Cirrus Logic cs35l56 driver" if !KUNIT_ALL_TESTS
depends on SND_SOC_CS35L56 && KUNIT
@@ -1100,6 +1106,7 @@ config SND_SOC_CS47L15
config SND_SOC_CS47L24
tristate
depends on MFD_CS47L24 && MFD_ARIZONA
+ select SND_SOC_WM_ADSP
config SND_SOC_CS47L35
tristate
@@ -1121,6 +1128,7 @@ config SND_SOC_CS48L32
tristate "Cirrus Logic CS48L32 audio DSP"
depends on SPI_MASTER
select REGMAP_SPI
+ select SND_SOC_WM_ADSP
help
Build the codec driver for the Cirrus Logic CS48L32 audio DSP.
@@ -1379,6 +1387,7 @@ config SND_SOC_LOCHNAGAR_SC
config SND_SOC_MADERA
tristate
+ select SND_SOC_WM_ADSP
default y if SND_SOC_CS47L15=y
default y if SND_SOC_CS47L35=y
default y if SND_SOC_CS47L85=y
@@ -2364,9 +2373,11 @@ config SND_SOC_UDA1342
mic inputs), stereo audio DAC, with basic audio processing.
config SND_SOC_UDA1380
- tristate
+ tristate "Philips UDA1380 CODEC"
depends on I2C
- depends on GPIOLIB_LEGACY
+ help
+ The UDA1380 codec is used in the HTC Magician and on a number of
+ Samsung reference boards, as well as the LPC32xx series.
config SND_SOC_WCD_CLASSH
tristate
@@ -2477,6 +2488,7 @@ config SND_SOC_WM2000
config SND_SOC_WM2200
tristate
depends on I2C
+ select SND_SOC_WM_ADSP
config SND_SOC_WM5100
tristate
@@ -2485,10 +2497,12 @@ config SND_SOC_WM5100
config SND_SOC_WM5102
tristate
depends on MFD_WM5102 && MFD_ARIZONA
+ select SND_SOC_WM_ADSP
config SND_SOC_WM5110
tristate
depends on MFD_WM5110 && MFD_ARIZONA
+ select SND_SOC_WM_ADSP
config SND_SOC_WM8350
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 3ddee5298721..172861d17cfd 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -361,6 +361,7 @@ snd-soc-wcd938x-sdw-y := wcd938x-sdw.o
snd-soc-wcd939x-y := wcd939x.o
snd-soc-wcd939x-sdw-y := wcd939x-sdw.o
snd-soc-wm-adsp-y := wm_adsp.o
+snd-soc-wm-adsp-test-y := wm_adsp_fw_find_test.o
snd-soc-wm0010-y := wm0010.o
snd-soc-wm1250-ev1-y := wm1250-ev1.o
snd-soc-wm2000-y := wm2000.o
@@ -862,6 +863,7 @@ obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o
obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o
+obj-$(CONFIG_SND_SOC_WM_ADSP_TEST) += snd-soc-wm-adsp-test.o
obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o
obj-$(CONFIG_SND_SOC_WSA883X) += snd-soc-wsa883x.o
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c
index 73684fc5beb1..691db6565c20 100644
--- a/sound/soc/codecs/ak5558.c
+++ b/sound/soc/codecs/ak5558.c
@@ -38,7 +38,6 @@ static const char *ak5558_supply_names[AK5558_NUM_SUPPLIES] = {
/* AK5558 Codec Private Data */
struct ak5558_priv {
struct regulator_bulk_data supplies[AK5558_NUM_SUPPLIES];
- struct snd_soc_component component;
struct regmap *regmap;
struct i2c_client *i2c;
struct gpio_desc *reset_gpiod; /* Reset & Power down GPIO */
diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c
index 303c1d44ebd8..a9063bac2752 100644
--- a/sound/soc/codecs/arizona-jack.c
+++ b/sound/soc/codecs/arizona-jack.c
@@ -11,7 +11,6 @@
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
-#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
@@ -459,11 +458,6 @@ static int arizona_hpdet_do_id(struct arizona_priv *info, int *reading,
bool *mic)
{
struct arizona *arizona = info->arizona;
-#ifdef CONFIG_GPIOLIB_LEGACY
- int id_gpio = arizona->pdata.hpdet_id_gpio;
-#else
- int id_gpio = 0;
-#endif
if (!arizona->pdata.hpdet_acc_id)
return 0;
@@ -474,9 +468,8 @@ static int arizona_hpdet_do_id(struct arizona_priv *info, int *reading,
*/
info->hpdet_res[info->num_hpdet_res++] = *reading;
-#ifdef CONFIG_GPIOLIB_LEGACY
/* Only check the mic directly if we didn't already ID it */
- if (id_gpio && info->num_hpdet_res == 1) {
+ if (info->hpdet_id_gpio && info->num_hpdet_res == 1) {
dev_dbg(arizona->dev, "Measuring mic\n");
regmap_update_bits(arizona->regmap,
@@ -486,13 +479,12 @@ static int arizona_hpdet_do_id(struct arizona_priv *info, int *reading,
ARIZONA_ACCDET_MODE_HPR |
info->micd_modes[0].src);
- gpio_set_value_cansleep(id_gpio, 1);
+ gpiod_set_value_cansleep(info->hpdet_id_gpio, 1);
regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
ARIZONA_HP_POLL, ARIZONA_HP_POLL);
return -EAGAIN;
}
-#endif
/* OK, got both. Now, compare... */
dev_dbg(arizona->dev, "HPDET measured %d %d\n",
@@ -514,7 +506,7 @@ static int arizona_hpdet_do_id(struct arizona_priv *info, int *reading,
/*
* If we measure the mic as high impedance
*/
- if (!id_gpio || info->hpdet_res[1] > 50) {
+ if (!info->hpdet_id_gpio || info->hpdet_res[1] > 50) {
dev_dbg(arizona->dev, "Detected mic\n");
*mic = true;
info->detecting = true;
@@ -533,9 +525,6 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
{
struct arizona_priv *info = data;
struct arizona *arizona = info->arizona;
-#ifdef CONFIG_GPIOLIB_LEGACY
- int id_gpio = arizona->pdata.hpdet_id_gpio;
-#endif
int ret, reading, state, report;
bool mic = false;
@@ -591,10 +580,8 @@ done:
arizona_extcon_hp_clamp(info, false);
-#ifdef CONFIG_GPIOLIB_LEGACY
- if (id_gpio)
- gpio_set_value_cansleep(id_gpio, 0);
-#endif
+ if (info->hpdet_id_gpio)
+ gpiod_set_value_cansleep(info->hpdet_id_gpio, 0);
/* If we have a mic then reenable MICDET */
if (state && (mic || info->mic))
@@ -1325,58 +1312,33 @@ int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev)
regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);
-#ifdef CONFIG_GPIOLIB_LEGACY
- if (pdata->micd_pol_gpio > 0) {
- if (info->micd_modes[0].gpio)
- mode = GPIOF_OUT_INIT_HIGH;
- else
- mode = GPIOF_OUT_INIT_LOW;
-
- ret = devm_gpio_request_one(dev, pdata->micd_pol_gpio,
- mode, "MICD polarity");
- if (ret != 0) {
- dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
- pdata->micd_pol_gpio, ret);
- return ret;
- }
-
- info->micd_pol_gpio = gpio_to_desc(pdata->micd_pol_gpio);
- } else
-#endif
- {
- if (info->micd_modes[0].gpio)
- mode = GPIOD_OUT_HIGH;
- else
- mode = GPIOD_OUT_LOW;
+ if (info->micd_modes[0].gpio)
+ mode = GPIOD_OUT_HIGH;
+ else
+ mode = GPIOD_OUT_LOW;
- /* We can't use devm here because we need to do the get
- * against the MFD device, as that is where the of_node
- * will reside, but if we devm against that the GPIO
- * will not be freed if the extcon driver is unloaded.
- */
- info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
- "wlf,micd-pol",
- mode);
- if (IS_ERR(info->micd_pol_gpio)) {
- ret = PTR_ERR(info->micd_pol_gpio);
- dev_err_probe(arizona->dev, ret, "getting microphone polarity GPIO\n");
- return ret;
- }
+ /* We can't use devm here because we need to do the get
+ * against the MFD device, as that is where the of_node
+ * will reside, but if we devm against that the GPIO
+ * will not be freed if the extcon driver is unloaded.
+ */
+ info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
+ "wlf,micd-pol",
+ mode);
+ if (IS_ERR(info->micd_pol_gpio)) {
+ ret = PTR_ERR(info->micd_pol_gpio);
+ dev_err_probe(arizona->dev, ret, "getting microphone polarity GPIO\n");
+ return ret;
}
-#ifdef CONFIG_GPIOLIB_LEGACY
- if (arizona->pdata.hpdet_id_gpio > 0) {
- ret = devm_gpio_request_one(dev, arizona->pdata.hpdet_id_gpio,
- GPIOF_OUT_INIT_LOW,
- "HPDET");
- if (ret != 0) {
- dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
- arizona->pdata.hpdet_id_gpio, ret);
- gpiod_put(info->micd_pol_gpio);
- return ret;
- }
+ info->hpdet_id_gpio = gpiod_get_optional(arizona->dev,
+ "wlf,hpdet-id-gpio",
+ mode);
+ if (IS_ERR(info->hpdet_id_gpio)) {
+ ret = PTR_ERR(info->hpdet_id_gpio);
+ dev_err_probe(arizona->dev, ret, "getting headphone detect ID GPIO\n");
+ return ret;
}
-#endif
return 0;
}
@@ -1385,6 +1347,7 @@ EXPORT_SYMBOL_GPL(arizona_jack_codec_dev_probe);
int arizona_jack_codec_dev_remove(struct arizona_priv *info)
{
gpiod_put(info->micd_pol_gpio);
+ gpiod_put(info->hpdet_id_gpio);
return 0;
}
EXPORT_SYMBOL_GPL(arizona_jack_codec_dev_remove);
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index ecd8890eefc1..0703182d87b3 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -100,6 +100,7 @@ struct arizona_priv {
struct snd_soc_jack *jack;
struct regulator *micvdd;
struct gpio_desc *micd_pol_gpio;
+ struct gpio_desc *hpdet_id_gpio;
u16 last_jackdet;
diff --git a/sound/soc/codecs/aw87390.c b/sound/soc/codecs/aw87390.c
index 613daccca3af..37ca42a25889 100644
--- a/sound/soc/codecs/aw87390.c
+++ b/sound/soc/codecs/aw87390.c
@@ -544,8 +544,7 @@ static int aw87390_i2c_probe(struct i2c_client *i2c)
const struct snd_soc_component_driver *priv;
int ret;
- ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C);
- if (!ret)
+ if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed\n");
aw87390 = devm_kzalloc(&i2c->dev, sizeof(*aw87390), GFP_KERNEL);
diff --git a/sound/soc/codecs/aw88081.c b/sound/soc/codecs/aw88081.c
index fbd1fd12381a..8c5bb3ea0227 100644
--- a/sound/soc/codecs/aw88081.c
+++ b/sound/soc/codecs/aw88081.c
@@ -1253,8 +1253,7 @@ static int aw88081_i2c_probe(struct i2c_client *i2c)
struct aw88081 *aw88081;
int ret;
- ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C);
- if (!ret)
+ if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed");
aw88081 = devm_kzalloc(&i2c->dev, sizeof(*aw88081), GFP_KERNEL);
diff --git a/sound/soc/codecs/aw88166.c b/sound/soc/codecs/aw88166.c
index daee4de9e3b0..ea277a940c44 100644
--- a/sound/soc/codecs/aw88166.c
+++ b/sound/soc/codecs/aw88166.c
@@ -1574,18 +1574,22 @@ static int aw88166_dev_init(struct aw88166 *aw88166, struct aw_container *aw_cfg
static int aw88166_request_firmware_file(struct aw88166 *aw88166)
{
const struct firmware *cont = NULL;
+ const char *fw_name;
int ret;
aw88166->aw_pa->fw_status = AW88166_DEV_FW_FAILED;
- ret = request_firmware(&cont, AW88166_ACF_FILE, aw88166->aw_pa->dev);
+ if (device_property_read_string(aw88166->aw_pa->dev, "firmware-name", &fw_name) < 0)
+ fw_name = AW88166_ACF_FILE;
+
+ ret = request_firmware(&cont, fw_name, aw88166->aw_pa->dev);
if (ret) {
- dev_err(aw88166->aw_pa->dev, "request [%s] failed!\n", AW88166_ACF_FILE);
+ dev_err(aw88166->aw_pa->dev, "request [%s] failed!\n", fw_name);
return ret;
}
dev_dbg(aw88166->aw_pa->dev, "loaded %s - size: %zu\n",
- AW88166_ACF_FILE, cont ? cont->size : 0);
+ fw_name, cont ? cont->size : 0);
aw88166->aw_cfg = devm_kzalloc(aw88166->aw_pa->dev,
struct_size(aw88166->aw_cfg, data, cont->size), GFP_KERNEL);
@@ -1599,7 +1603,7 @@ static int aw88166_request_firmware_file(struct aw88166 *aw88166)
ret = aw88395_dev_load_acf_check(aw88166->aw_pa, aw88166->aw_cfg);
if (ret) {
- dev_err(aw88166->aw_pa->dev, "load [%s] failed!\n", AW88166_ACF_FILE);
+ dev_err(aw88166->aw_pa->dev, "load [%s] failed!\n", fw_name);
return ret;
}
diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c
index 43c03d3cb252..a6805d5405cd 100644
--- a/sound/soc/codecs/aw88261.c
+++ b/sound/soc/codecs/aw88261.c
@@ -1094,17 +1094,22 @@ static int aw88261_dev_init(struct aw88261 *aw88261, struct aw_container *aw_cfg
static int aw88261_request_firmware_file(struct aw88261 *aw88261)
{
const struct firmware *cont = NULL;
+ const char *fw_name;
int ret;
aw88261->aw_pa->fw_status = AW88261_DEV_FW_FAILED;
- ret = request_firmware(&cont, AW88261_ACF_FILE, aw88261->aw_pa->dev);
+ ret = device_property_read_string(aw88261->aw_pa->dev, "firmware-name", &fw_name);
+ if (ret)
+ fw_name = AW88261_ACF_FILE;
+
+ ret = request_firmware(&cont, fw_name, aw88261->aw_pa->dev);
if (ret)
return dev_err_probe(aw88261->aw_pa->dev, ret,
- "load [%s] failed!", AW88261_ACF_FILE);
+ "load [%s] failed!", fw_name);
dev_info(aw88261->aw_pa->dev, "loaded %s - size: %zu\n",
- AW88261_ACF_FILE, cont ? cont->size : 0);
+ fw_name, cont ? cont->size : 0);
aw88261->aw_cfg = devm_kzalloc(aw88261->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL);
if (!aw88261->aw_cfg) {
@@ -1117,7 +1122,7 @@ static int aw88261_request_firmware_file(struct aw88261 *aw88261)
ret = aw88395_dev_load_acf_check(aw88261->aw_pa, aw88261->aw_cfg);
if (ret) {
- dev_err(aw88261->aw_pa->dev, "load [%s] failed !", AW88261_ACF_FILE);
+ dev_err(aw88261->aw_pa->dev, "load [%s] failed !", fw_name);
return ret;
}
@@ -1237,8 +1242,7 @@ static int aw88261_i2c_probe(struct i2c_client *i2c)
struct aw88261 *aw88261;
int ret;
- ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C);
- if (!ret)
+ if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed");
aw88261 = devm_kzalloc(&i2c->dev, sizeof(*aw88261), GFP_KERNEL);
diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c
index f78a85b89d95..7dc5a7c3ca96 100644
--- a/sound/soc/codecs/cros_ec_codec.c
+++ b/sound/soc/codecs/cros_ec_codec.c
@@ -948,7 +948,7 @@ static const struct snd_soc_component_driver wov_component_driver = {
.hw_params = wov_pcm_hw_params,
.hw_free = wov_pcm_hw_free,
.pointer = wov_pcm_pointer,
- .pcm_construct = wov_pcm_new,
+ .pcm_new = wov_pcm_new,
};
static int cros_ec_codec_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/cs-amp-lib-test.c b/sound/soc/codecs/cs-amp-lib-test.c
index 2b1529343f11..636d0f3198b8 100644
--- a/sound/soc/codecs/cs-amp-lib-test.c
+++ b/sound/soc/codecs/cs-amp-lib-test.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/pci_ids.h>
-#include <linux/platform_device.h>
#include <linux/random.h>
#include <sound/cs-amp-lib.h>
diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c
index 8b131975143d..b34b1f5f121f 100644
--- a/sound/soc/codecs/cs-amp-lib.c
+++ b/sound/soc/codecs/cs-amp-lib.c
@@ -716,6 +716,8 @@ int cs_amp_get_vendor_spkid(struct device *dev)
{
int i, ret;
+ KUNIT_STATIC_STUB_REDIRECT(cs_amp_get_vendor_spkid, dev);
+
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE) &&
!IS_ENABLED(CONFIG_SND_SOC_CS_AMP_LIB_TEST_HOOKS))
return -ENOENT;
diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c
index ee56dfceedeb..b2a076706c79 100644
--- a/sound/soc/codecs/cs35l41.c
+++ b/sound/soc/codecs/cs35l41.c
@@ -1404,6 +1404,7 @@ static int cs35l41_runtime_suspend(struct device *dev)
if (!cs35l41->dsp.preloaded || !cs35l41->dsp.cs_dsp.running)
return 0;
+ wm_adsp_hibernate(&cs35l41->dsp, true);
cs35l41_enter_hibernate(dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type);
regcache_cache_only(cs35l41->regmap, true);
@@ -1432,10 +1433,14 @@ static int cs35l41_runtime_resume(struct device *dev)
cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap);
ret = regcache_sync(cs35l41->regmap);
cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
+
+ wm_adsp_hibernate(&cs35l41->dsp, false);
+
if (ret) {
dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret);
return ret;
}
+
cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg);
return 0;
diff --git a/sound/soc/codecs/cs35l45.c b/sound/soc/codecs/cs35l45.c
index 7aa558d6362f..a032bb23b4ac 100644
--- a/sound/soc/codecs/cs35l45.c
+++ b/sound/soc/codecs/cs35l45.c
@@ -984,6 +984,7 @@ static int cs35l45_runtime_suspend(struct device *dev)
if (!cs35l45->dsp.preloaded || !cs35l45->dsp.cs_dsp.running)
return 0;
+ wm_adsp_hibernate(&cs35l45->dsp, true);
cs35l45_enter_hibernate(cs35l45);
regcache_cache_only(cs35l45->regmap, true);
@@ -1014,6 +1015,8 @@ static int cs35l45_runtime_resume(struct device *dev)
if (ret != 0)
dev_warn(cs35l45->dev, "regcache_sync failed: %d\n", ret);
+ wm_adsp_hibernate(&cs35l45->dsp, false);
+
/* Clear global error status */
regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK);
regmap_set_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK);
diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c
index 30b3192d6ce9..9dc47fec1ea0 100644
--- a/sound/soc/codecs/cs35l56-sdw.c
+++ b/sound/soc/codecs/cs35l56-sdw.c
@@ -14,6 +14,7 @@
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_registers.h>
#include <linux/soundwire/sdw_type.h>
+#include <linux/string_choices.h>
#include <linux/swab.h>
#include <linux/types.h>
#include <linux/workqueue.h>
@@ -340,6 +341,14 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral)
struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
struct sdw_slave_prop *prop = &peripheral->prop;
struct sdw_dpn_prop *ports;
+ u8 clock_stop_1 = false;
+ int ret;
+
+ ret = fwnode_property_read_u8(dev_fwnode(cs35l56->base.dev),
+ "mipi-sdw-clock-stop-mode1-supported",
+ &clock_stop_1);
+ if (ret == 0)
+ prop->clk_stop_mode1 = !!clock_stop_1;
ports = devm_kcalloc(cs35l56->base.dev, 2, sizeof(*ports), GFP_KERNEL);
if (!ports)
@@ -363,6 +372,9 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral)
ports[1].ch_prep_timeout = 10;
prop->src_dpn_prop = &ports[1];
+ dev_dbg(&peripheral->dev, "clock stop mode 1 supported: %s\n",
+ str_yes_no(prop->clk_stop_mode1));
+
return 0;
}
@@ -374,6 +386,7 @@ static int cs35l56_sdw_update_status(struct sdw_slave *peripheral,
switch (status) {
case SDW_SLAVE_ATTACHED:
dev_dbg(cs35l56->base.dev, "%s: ATTACHED\n", __func__);
+ cs35l56->sdw_in_clock_stop_1 = false;
if (cs35l56->sdw_attached)
break;
@@ -399,25 +412,35 @@ static int __maybe_unused cs35l56_sdw_clk_stop(struct sdw_slave *peripheral,
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
- dev_dbg(cs35l56->base.dev, "%s: mode:%d type:%d\n", __func__, mode, type);
+ dev_dbg(cs35l56->base.dev, "%s: clock_stop_mode%d stage:%d\n", __func__, mode, type);
- return 0;
+ switch (type) {
+ case SDW_CLK_POST_PREPARE:
+ if (mode == SDW_CLK_STOP_MODE1)
+ cs35l56->sdw_in_clock_stop_1 = true;
+ else
+ cs35l56->sdw_in_clock_stop_1 = false;
+ return 0;
+ default:
+ return 0;
+ }
}
static const struct sdw_slave_ops cs35l56_sdw_ops = {
.read_prop = cs35l56_sdw_read_prop,
.interrupt_callback = cs35l56_sdw_interrupt,
.update_status = cs35l56_sdw_update_status,
-#ifdef DEBUG
.clk_stop = cs35l56_sdw_clk_stop,
-#endif
};
static int __maybe_unused cs35l56_sdw_handle_unattach(struct cs35l56_private *cs35l56)
{
struct sdw_slave *peripheral = cs35l56->sdw_peripheral;
- if (peripheral->unattach_request) {
+ dev_dbg(cs35l56->base.dev, "attached:%u unattach_request:%u in_clock_stop_1:%u\n",
+ cs35l56->sdw_attached, peripheral->unattach_request, cs35l56->sdw_in_clock_stop_1);
+
+ if (cs35l56->sdw_in_clock_stop_1 || peripheral->unattach_request) {
/* Cannot access registers until bus is re-initialized. */
dev_dbg(cs35l56->base.dev, "Wait for initialization_complete\n");
if (!wait_for_completion_timeout(&peripheral->initialization_complete,
@@ -427,6 +450,7 @@ static int __maybe_unused cs35l56_sdw_handle_unattach(struct cs35l56_private *cs
}
peripheral->unattach_request = 0;
+ cs35l56->sdw_in_clock_stop_1 = false;
/*
* Don't call regcache_mark_dirty(), we can't be sure that the
diff --git a/sound/soc/codecs/cs35l56-shared-test.c b/sound/soc/codecs/cs35l56-shared-test.c
index 94db02aef7dc..cfe7938065f9 100644
--- a/sound/soc/codecs/cs35l56-shared-test.c
+++ b/sound/soc/codecs/cs35l56-shared-test.c
@@ -11,15 +11,23 @@
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/device/faux.h>
+#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/random.h>
#include <linux/regmap.h>
#include <linux/seq_buf.h>
#include <sound/cs35l56.h>
+struct cs35l56_shared_test_mock_gpio {
+ unsigned int pin_state;
+ struct gpio_chip chip;
+};
+
struct cs35l56_shared_test_priv {
struct kunit *test;
struct faux_device *amp_dev;
+ struct faux_device *gpio_dev;
+ struct cs35l56_shared_test_mock_gpio *gpio_priv;
struct regmap *registers;
struct cs35l56_base *cs35l56_base;
u8 applied_pad_pull_state[CS35L56_MAX_GPIO];
@@ -37,6 +45,94 @@ KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destroy,
KUNIT_DEFINE_ACTION_WRAPPER(regmap_exit_wrapper, regmap_exit, struct regmap *)
+KUNIT_DEFINE_ACTION_WRAPPER(device_remove_software_node_wrapper,
+ device_remove_software_node,
+ struct device *)
+
+static int cs35l56_shared_test_mock_gpio_get_direction(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_IN;
+}
+
+static int cs35l56_shared_test_mock_gpio_direction_in(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ return 0;
+}
+
+static int cs35l56_shared_test_mock_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct cs35l56_shared_test_mock_gpio *gpio_priv = gpiochip_get_data(chip);
+
+ return !!(gpio_priv->pin_state & BIT(offset));
+}
+
+static const struct gpio_chip cs35l56_shared_test_mock_gpio_chip = {
+ .label = "cs35l56_shared_test_mock_gpio",
+ .owner = THIS_MODULE,
+ .get_direction = cs35l56_shared_test_mock_gpio_get_direction,
+ .direction_input = cs35l56_shared_test_mock_gpio_direction_in,
+ .get = cs35l56_shared_test_mock_gpio_get,
+ .base = -1,
+ .ngpio = 32,
+};
+
+/* software_node referencing the gpio driver */
+static const struct software_node cs35l56_shared_test_mock_gpio_swnode = {
+ .name = "cs35l56_shared_test_mock_gpio",
+};
+
+static int cs35l56_shared_test_mock_gpio_probe(struct faux_device *fdev)
+{
+ struct cs35l56_shared_test_mock_gpio *gpio_priv;
+ struct device *dev = &fdev->dev;
+ int ret;
+
+ gpio_priv = devm_kzalloc(dev, sizeof(*gpio_priv), GFP_KERNEL);
+ if (!gpio_priv)
+ return -ENOMEM;
+
+ ret = device_add_software_node(dev, &cs35l56_shared_test_mock_gpio_swnode);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, device_remove_software_node_wrapper, dev);
+ if (ret)
+ return ret;
+
+ /* GPIO core modifies our struct gpio_chip so use a copy */
+ gpio_priv->chip = cs35l56_shared_test_mock_gpio_chip;
+ gpio_priv->chip.parent = dev;
+ ret = devm_gpiochip_add_data(dev, &gpio_priv->chip, gpio_priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add gpiochip\n");
+
+ dev_set_drvdata(dev, gpio_priv);
+
+ return 0;
+}
+
+static struct faux_device_ops cs35l56_shared_test_mock_gpio_drv = {
+ .probe = cs35l56_shared_test_mock_gpio_probe,
+};
+
+static void _cs35l56_shared_test_create_dummy_gpio(struct kunit *test)
+{
+ struct cs35l56_shared_test_priv *priv = test->priv;
+
+ priv->gpio_dev = faux_device_create("cs35l56_shared_test_mock_gpio", NULL,
+ &cs35l56_shared_test_mock_gpio_drv);
+ KUNIT_ASSERT_NOT_NULL(test, priv->gpio_dev);
+ KUNIT_ASSERT_EQ(test, 0,
+ kunit_add_action_or_reset(test,
+ faux_device_destroy_wrapper,
+ priv->gpio_dev));
+
+ priv->gpio_priv = dev_get_drvdata(&priv->gpio_dev->dev);
+ KUNIT_ASSERT_NOT_NULL(test, priv->gpio_priv);
+}
+
static const struct regmap_config cs35l56_shared_test_mock_registers_regmap = {
.reg_bits = 32,
.val_bits = 32,
@@ -410,6 +506,109 @@ static void cs35l56_shared_test_onchip_speaker_id_not_defined(struct kunit *test
KUNIT_EXPECT_EQ(test, cs35l56_read_onchip_spkid(cs35l56_base), -ENOENT);
}
+/* simulate cs_amp_get_vendor_spkid() reading a vendor-specific ID of 1 */
+static int cs35l56_shared_test_get_vendor_spkid_1(struct device *dev)
+{
+ return 1;
+}
+
+static void cs35l56_shared_test_get_speaker_id_vendor(struct kunit *test)
+{
+ struct cs35l56_shared_test_priv *priv = test->priv;
+
+ /* Hook cs_amp_get_vendor_spkid() to return an ID of 1 */
+ kunit_activate_static_stub(test, cs_amp_get_vendor_spkid,
+ cs35l56_shared_test_get_vendor_spkid_1);
+
+ KUNIT_EXPECT_EQ(test, cs35l56_get_speaker_id(priv->cs35l56_base), 1);
+}
+
+static void cs35l56_shared_test_get_speaker_id_property(struct kunit *test)
+{
+ struct cs35l56_shared_test_priv *priv = test->priv;
+ const struct property_entry dev_props[] = {
+ PROPERTY_ENTRY_U32("cirrus,speaker-id", 2),
+ { }
+ };
+ const struct software_node dev_node = SOFTWARE_NODE("SPK1", dev_props, NULL);
+
+ KUNIT_ASSERT_EQ(test, device_add_software_node(priv->cs35l56_base->dev, &dev_node), 0);
+ KUNIT_ASSERT_EQ(test, 0,
+ kunit_add_action_or_reset(test,
+ device_remove_software_node_wrapper,
+ priv->cs35l56_base->dev));
+
+ KUNIT_EXPECT_EQ(test, cs35l56_get_speaker_id(priv->cs35l56_base), 2);
+}
+
+/*
+ * Create software nodes equivalent to ACPI structure
+ *
+ * Device(GSPK) {
+ * Name(_DSD, ...) {
+ * Package() {
+ * cs-gpios {
+ * GPIO, n, 0,
+ * ...
+ * }
+ * }
+ */
+static void _cs35l56_shared_test_create_spkid_swnode(struct kunit *test,
+ struct device *dev,
+ const struct software_node_ref_args *args,
+ int num_args)
+{
+ struct cs35l56_shared_test_priv *priv = test->priv;
+ const struct property_entry props_template[] = {
+ PROPERTY_ENTRY_REF_ARRAY_LEN("spk-id-gpios", args, num_args),
+ { }
+ };
+ struct property_entry *props;
+ struct software_node *node;
+
+ props = kunit_kzalloc(test, sizeof(props_template), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, props);
+ memcpy(props, props_template, sizeof(props_template));
+
+ node = kunit_kzalloc(test, sizeof(*node), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, node);
+ *node = SOFTWARE_NODE("GSPK", props, NULL);
+
+ KUNIT_ASSERT_EQ(test, device_add_software_node(dev, node), 0);
+ KUNIT_ASSERT_EQ(test, 0,
+ kunit_add_action_or_reset(test,
+ device_remove_software_node_wrapper,
+ priv->cs35l56_base->dev));
+}
+
+static void cs35l56_shared_test_get_speaker_id_from_host_gpio(struct kunit *test)
+{
+ const struct cs35l56_shared_test_param *param = test->param_value;
+ struct cs35l56_shared_test_priv *priv = test->priv;
+ struct cs35l56_base *cs35l56_base = priv->cs35l56_base;
+ struct software_node_ref_args *ref;
+ int i;
+
+ if (!IS_REACHABLE(CONFIG_GPIOLIB)) {
+ kunit_skip(test, "Requires CONFIG_GPIOLIB");
+ return;
+ }
+
+ _cs35l56_shared_test_create_dummy_gpio(test);
+
+ ref = kunit_kcalloc(test, ARRAY_SIZE(param->spkid_gpios), sizeof(*ref), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ref);
+
+ for (i = 0; param->spkid_gpios[i] >= 0; i++) {
+ ref[i] = SOFTWARE_NODE_REFERENCE(&cs35l56_shared_test_mock_gpio_swnode,
+ param->spkid_gpios[i], 0);
+ }
+ _cs35l56_shared_test_create_spkid_swnode(test, cs35l56_base->dev, ref, i);
+
+ priv->gpio_priv->pin_state = param->gpio_status;
+ KUNIT_EXPECT_EQ(test, cs35l56_get_speaker_id(priv->cs35l56_base), param->spkid);
+}
+
static int cs35l56_shared_test_case_regmap_init(struct kunit *test,
const struct regmap_config *regmap_config)
{
@@ -602,6 +801,40 @@ KUNIT_ARRAY_PARAM(cs35l56_shared_test_onchip_spkid_pull,
cs35l56_shared_test_onchip_spkid_pull_cases,
cs35l56_shared_test_gpio_param_desc);
+/* Note: spk-id-gpios property bit order is LSbit...MSbit */
+static const struct cs35l56_shared_test_param cs35l56_shared_test_host_gpio_spkid_cases[] = {
+ { .spkid_gpios = { 0, -1 }, .gpio_status = 0, .spkid = 0 },
+ { .spkid_gpios = { 0, -1 }, .gpio_status = ~BIT(0), .spkid = 0 },
+ { .spkid_gpios = { 0, -1 }, .gpio_status = BIT(0), .spkid = 1 },
+
+ { .spkid_gpios = { 6, -1 }, .gpio_status = 0, .spkid = 0 },
+ { .spkid_gpios = { 6, -1 }, .gpio_status = ~BIT(6), .spkid = 0 },
+ { .spkid_gpios = { 6, -1 }, .gpio_status = BIT(6), .spkid = 1 },
+
+ { .spkid_gpios = { 6, 0, -1 }, .gpio_status = 0, .spkid = 0 },
+ { .spkid_gpios = { 6, 0, -1 }, .gpio_status = ~(BIT(0) | BIT(6)), .spkid = 0 },
+ { .spkid_gpios = { 6, 0, -1 }, .gpio_status = BIT(6), .spkid = 1 },
+ { .spkid_gpios = { 6, 0, -1 }, .gpio_status = BIT(0), .spkid = 2 },
+ { .spkid_gpios = { 6, 0, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 },
+
+ { .spkid_gpios = { 0, 6, -1 }, .gpio_status = 0, .spkid = 0 },
+ { .spkid_gpios = { 0, 6, -1 }, .gpio_status = ~(BIT(6) | BIT(0)), .spkid = 0 },
+ { .spkid_gpios = { 0, 6, -1 }, .gpio_status = BIT(0), .spkid = 1 },
+ { .spkid_gpios = { 0, 6, -1 }, .gpio_status = BIT(6), .spkid = 2 },
+ { .spkid_gpios = { 0, 6, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 },
+
+ { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = 0, .spkid = 0 },
+ { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = BIT(0), .spkid = 1 },
+ { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = BIT(6), .spkid = 2 },
+ { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = BIT(6) | BIT(0), .spkid = 3 },
+ { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = BIT(2), .spkid = 4 },
+ { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = BIT(2) | BIT(0), .spkid = 5 },
+ { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = BIT(2) | BIT(6), .spkid = 6 },
+ { .spkid_gpios = { 0, 6, 2, -1 }, .gpio_status = BIT(2) | BIT(6) | BIT(0), .spkid = 7 },
+};
+KUNIT_ARRAY_PARAM(cs35l56_shared_test_host_gpio_spkid, cs35l56_shared_test_host_gpio_spkid_cases,
+ cs35l56_shared_test_gpio_param_desc);
+
static struct kunit_case cs35l56_shared_test_cases[] = {
/* Tests for speaker id */
KUNIT_CASE_PARAM(cs35l56_shared_test_mock_gpio_status_selftest,
@@ -616,6 +849,13 @@ static struct kunit_case cs35l56_shared_test_cases[] = {
cs35l56_shared_test_onchip_spkid_pull_gen_params),
KUNIT_CASE(cs35l56_shared_test_stash_onchip_spkid_pins_reject_invalid),
KUNIT_CASE(cs35l56_shared_test_onchip_speaker_id_not_defined),
+
+ KUNIT_CASE(cs35l56_shared_test_get_speaker_id_vendor),
+ KUNIT_CASE(cs35l56_shared_test_get_speaker_id_property),
+ KUNIT_CASE_PARAM_ATTR(cs35l56_shared_test_get_speaker_id_from_host_gpio,
+ cs35l56_shared_test_host_gpio_spkid_gen_params,
+ { KUNIT_SPEED_SLOW }),
+
{ }
};
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index af87ebae98cb..e05d975ba794 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -1185,6 +1185,15 @@ ssize_t cs35l56_calibrate_debugfs_write(struct cs35l56_base *cs35l56_base,
}
EXPORT_SYMBOL_NS_GPL(cs35l56_calibrate_debugfs_write, "SND_SOC_CS35L56_SHARED");
+int cs35l56_factory_calibrate(struct cs35l56_base *cs35l56_base)
+{
+ if (!IS_ENABLED(CONFIG_SND_SOC_CS35L56_CAL_PERFORM_CTRL))
+ return -ENXIO;
+
+ return cs35l56_perform_calibration(cs35l56_base);
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_factory_calibrate, "SND_SOC_CS35L56_SHARED");
+
ssize_t cs35l56_cal_ambient_debugfs_write(struct cs35l56_base *cs35l56_base,
const char __user *from, size_t count,
loff_t *ppos)
diff --git a/sound/soc/codecs/cs35l56-test.c b/sound/soc/codecs/cs35l56-test.c
index b6c8c08e3ade..124fe5e75500 100644
--- a/sound/soc/codecs/cs35l56-test.c
+++ b/sound/soc/codecs/cs35l56-test.c
@@ -74,6 +74,78 @@ static const char *cs35l56_test_devm_get_vendor_specific_variant_id_none(struct
return ERR_PTR(-ENOENT);
}
+static void cs35l56_test_system_name_from_ssid(struct kunit *test)
+{
+ struct cs35l56_test_priv *priv = test->priv;
+ struct cs35l56_private *cs35l56 = priv->cs35l56_priv;
+
+ cs35l56->speaker_id = -1;
+ snd_soc_card_set_pci_ssid(cs35l56->component->card, 0x12b4, 0xa7c8);
+
+ KUNIT_EXPECT_EQ(test, cs35l56_get_firmware_uid(cs35l56), 0);
+ KUNIT_EXPECT_EQ(test, cs35l56_set_fw_name(cs35l56->component), 0);
+ KUNIT_EXPECT_STREQ(test, cs35l56->dsp.system_name, "12b4a7c8");
+}
+
+static void cs35l56_test_system_name_from_ssid_and_spkid(struct kunit *test)
+{
+ struct cs35l56_test_priv *priv = test->priv;
+ struct cs35l56_private *cs35l56 = priv->cs35l56_priv;
+
+ cs35l56->speaker_id = 1;
+ snd_soc_card_set_pci_ssid(cs35l56->component->card, 0x12b4, 0xa7c8);
+
+ KUNIT_EXPECT_EQ(test, cs35l56_get_firmware_uid(cs35l56), 0);
+ KUNIT_EXPECT_EQ(test, cs35l56_set_fw_name(cs35l56->component), 0);
+ KUNIT_EXPECT_STREQ(test, cs35l56->dsp.system_name, "12b4a7c8-spkid1");
+}
+
+static void cs35l56_test_system_name_from_property(struct kunit *test)
+{
+ struct cs35l56_test_priv *priv = test->priv;
+ struct cs35l56_private *cs35l56 = priv->cs35l56_priv;
+ const struct property_entry dev_props[] = {
+ PROPERTY_ENTRY_STRING("cirrus,firmware-uid", "acme"),
+ { }
+ };
+ const struct software_node dev_node = SOFTWARE_NODE("SPK1", dev_props, NULL);
+
+ cs35l56->speaker_id = -1;
+
+ KUNIT_ASSERT_EQ(test, device_add_software_node(cs35l56->base.dev, &dev_node), 0);
+ KUNIT_ASSERT_EQ(test, 0,
+ kunit_add_action_or_reset(test,
+ device_remove_software_node_wrapper,
+ cs35l56->base.dev));
+
+ KUNIT_EXPECT_EQ(test, cs35l56_get_firmware_uid(cs35l56), 0);
+ KUNIT_EXPECT_EQ(test, cs35l56_set_fw_name(cs35l56->component), 0);
+ KUNIT_EXPECT_STREQ(test, cs35l56->dsp.system_name, "acme");
+}
+
+static void cs35l56_test_system_name_from_property_and_spkid(struct kunit *test)
+{
+ struct cs35l56_test_priv *priv = test->priv;
+ struct cs35l56_private *cs35l56 = priv->cs35l56_priv;
+ const struct property_entry dev_props[] = {
+ PROPERTY_ENTRY_STRING("cirrus,firmware-uid", "acme"),
+ { }
+ };
+ const struct software_node dev_node = SOFTWARE_NODE("SPK1", dev_props, NULL);
+
+ cs35l56->speaker_id = 1;
+
+ KUNIT_ASSERT_EQ(test, device_add_software_node(cs35l56->base.dev, &dev_node), 0);
+ KUNIT_ASSERT_EQ(test, 0,
+ kunit_add_action_or_reset(test,
+ device_remove_software_node_wrapper,
+ cs35l56->base.dev));
+
+ KUNIT_EXPECT_EQ(test, cs35l56_get_firmware_uid(cs35l56), 0);
+ KUNIT_EXPECT_EQ(test, cs35l56_set_fw_name(cs35l56->component), 0);
+ KUNIT_EXPECT_STREQ(test, cs35l56->dsp.system_name, "acme-spkid1");
+}
+
static void cs35l56_test_l56_b0_suffix_sdw(struct kunit *test)
{
struct cs35l56_test_priv *priv = test->priv;
@@ -292,18 +364,17 @@ static void cs35l56_test_parse_xu_onchip_spkid(struct kunit *test)
struct cs35l56_test_priv *priv = test->priv;
struct cs35l56_private *cs35l56 = priv->cs35l56_priv;
struct software_node *ext0_node;
- int num_gpios = 0;
- int num_pulls = 0;
+ int num_gpios, num_pulls;
int i;
- for (i = 0; i < ARRAY_SIZE(param->spkid_gpios); i++, num_gpios++) {
- if (param->spkid_gpios[i] < 0)
+ for (num_gpios = 0; num_gpios < ARRAY_SIZE(param->spkid_gpios); num_gpios++) {
+ if (param->spkid_gpios[num_gpios] < 0)
break;
}
KUNIT_ASSERT_LE(test, num_gpios, ARRAY_SIZE(cs35l56->base.onchip_spkid_gpios));
- for (i = 0; i < ARRAY_SIZE(param->spkid_pulls); i++, num_pulls++) {
- if (param->spkid_pulls[i] < 0)
+ for (num_pulls = 0; num_pulls < ARRAY_SIZE(param->spkid_pulls); num_pulls++) {
+ if (param->spkid_pulls[num_pulls] < 0)
break;
}
KUNIT_ASSERT_LE(test, num_pulls, ARRAY_SIZE(cs35l56->base.onchip_spkid_pulls));
@@ -541,18 +612,28 @@ static void cs35l56_test_gpio_param_desc(const struct cs35l56_test_param *param,
}
static const struct cs35l56_test_param cs35l56_test_onchip_spkid_cases[] = {
+ { .spkid_gpios = { 1, -1 }, .spkid_pulls = { -1, -1 }, },
+ { .spkid_gpios = { 1, -1 }, .spkid_pulls = { -1, -1 }, },
{ .spkid_gpios = { 1, -1 }, .spkid_pulls = { 1, -1 }, },
{ .spkid_gpios = { 1, -1 }, .spkid_pulls = { 2, -1 }, },
+ { .spkid_gpios = { 7, -1 }, .spkid_pulls = { -1, -1 }, },
+ { .spkid_gpios = { 7, -1 }, .spkid_pulls = { -1, -1 }, },
{ .spkid_gpios = { 7, -1 }, .spkid_pulls = { 1, -1 }, },
{ .spkid_gpios = { 7, -1 }, .spkid_pulls = { 2, -1 }, },
+ { .spkid_gpios = { 1, 7, -1 }, .spkid_pulls = { -1, -1, -1 }, },
+ { .spkid_gpios = { 1, 7, -1 }, .spkid_pulls = { -1, -1, -1 }, },
{ .spkid_gpios = { 1, 7, -1 }, .spkid_pulls = { 1, 1, -1 }, },
{ .spkid_gpios = { 1, 7, -1 }, .spkid_pulls = { 2, 2, -1 }, },
+ { .spkid_gpios = { 7, 1, -1 }, .spkid_pulls = { -1, -1, -1 }, },
+ { .spkid_gpios = { 7, 1, -1 }, .spkid_pulls = { -1, -1, -1 }, },
{ .spkid_gpios = { 7, 1, -1 }, .spkid_pulls = { 1, 1, -1 }, },
{ .spkid_gpios = { 7, 1, -1 }, .spkid_pulls = { 2, 2, -1 }, },
+ { .spkid_gpios = { 3, 7, 1, -1 }, .spkid_pulls = { -1, -1, -1, -1 }, },
+ { .spkid_gpios = { 3, 7, 1, -1 }, .spkid_pulls = { -1, -1, -1, -1 }, },
{ .spkid_gpios = { 3, 7, 1, -1 }, .spkid_pulls = { 1, 1, 1, -1 }, },
{ .spkid_gpios = { 3, 7, 1, -1 }, .spkid_pulls = { 2, 2, 2, -1 }, },
};
@@ -586,6 +667,10 @@ KUNIT_ARRAY_PARAM(cs35l56_test_type_rev_all, cs35l56_test_type_rev_all_param_cas
cs35l56_test_type_rev_param_desc);
static struct kunit_case cs35l56_test_cases_soundwire[] = {
+ KUNIT_CASE(cs35l56_test_system_name_from_ssid),
+ KUNIT_CASE(cs35l56_test_system_name_from_ssid_and_spkid),
+ KUNIT_CASE(cs35l56_test_system_name_from_property),
+ KUNIT_CASE(cs35l56_test_system_name_from_property_and_spkid),
KUNIT_CASE(cs35l56_test_l56_b0_suffix_sdw),
KUNIT_CASE_PARAM(cs35l56_test_suffix_sdw, cs35l56_test_type_rev_ex_b0_gen_params),
KUNIT_CASE_PARAM(cs35l56_test_ssidexv2_suffix_sdw,
@@ -603,6 +688,10 @@ static struct kunit_case cs35l56_test_cases_soundwire[] = {
};
static struct kunit_case cs35l56_test_cases_not_soundwire[] = {
+ KUNIT_CASE(cs35l56_test_system_name_from_ssid),
+ KUNIT_CASE(cs35l56_test_system_name_from_ssid_and_spkid),
+ KUNIT_CASE(cs35l56_test_system_name_from_property),
+ KUNIT_CASE(cs35l56_test_system_name_from_property_and_spkid),
KUNIT_CASE_PARAM(cs35l56_test_suffix_i2cspi, cs35l56_test_type_rev_all_gen_params),
KUNIT_CASE_PARAM(cs35l56_test_ssidexv2_suffix_i2cspi,
cs35l56_test_type_rev_all_gen_params),
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index 37909a319f88..378017fcea10 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -1109,6 +1109,88 @@ static int cs35l56_cal_data_ctl_set(struct snd_kcontrol *kcontrol,
return 1;
}
+static int cs35l56_cal_ambient_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = cs35l56->ambient_ctl_value;
+
+ return 0;
+}
+
+static int cs35l56_cal_ambient_ctl_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm;
+ int temperature = ucontrol->value.integer.value[0];
+ int ret;
+
+ if (temperature == cs35l56->ambient_ctl_value)
+ return 0;
+
+ if ((temperature < 0) || (temperature > 40))
+ return -EINVAL;
+
+ dapm = cs35l56_power_up_for_cal(cs35l56);
+ if (IS_ERR(dapm))
+ return PTR_ERR(dapm);
+
+ ret = cs_amp_write_ambient_temp(&cs35l56->dsp.cs_dsp,
+ cs35l56->base.calibration_controls,
+ temperature);
+ cs35l56_power_down_after_cal(cs35l56);
+
+ if (ret)
+ return ret;
+
+ cs35l56->ambient_ctl_value = temperature;
+
+ return 1;
+}
+
+static int cs35l56_calibrate_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /*
+ * Allow reading because of user-side libraries that assume all
+ * controls are readable. But always return false to prevent dumb
+ * save-restore tools like alsactl accidentically triggering a
+ * factory calibration when they restore.
+ */
+ ucontrol->value.integer.value[0] = 0;
+
+ return 0;
+}
+
+static int cs35l56_calibrate_ctl_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm;
+ int ret;
+
+ if (ucontrol->value.integer.value[0] == 0)
+ return 0;
+
+ dapm = cs35l56_power_up_for_cal(cs35l56);
+ if (IS_ERR(dapm))
+ return PTR_ERR(dapm);
+
+ snd_soc_dapm_mutex_lock(dapm);
+ ret = cs35l56_factory_calibrate(&cs35l56->base);
+ snd_soc_dapm_mutex_unlock(dapm);
+ cs35l56_power_down_after_cal(cs35l56);
+ if (ret < 0)
+ return ret;
+
+ return 1;
+}
+
static const struct snd_kcontrol_new cs35l56_cal_data_restore_controls[] = {
SND_SOC_BYTES_E("CAL_DATA", 0, sizeof(struct cirrus_amp_cal_data) / sizeof(u32),
cs35l56_cal_data_ctl_get, cs35l56_cal_data_ctl_set),
@@ -1117,6 +1199,14 @@ static const struct snd_kcontrol_new cs35l56_cal_data_restore_controls[] = {
SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE),
};
+static const struct snd_kcontrol_new cs35l56_cal_perform_controls[] = {
+ SOC_SINGLE_EXT("CAL_AMBIENT", SND_SOC_NOPM, 0, 40, 0,
+ cs35l56_cal_ambient_ctl_get, cs35l56_cal_ambient_ctl_set),
+ SOC_SINGLE_BOOL_EXT_ACC("Calibrate Switch", 0,
+ cs35l56_calibrate_ctl_get, cs35l56_calibrate_ctl_set,
+ SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_VOLATILE),
+};
+
VISIBLE_IF_KUNIT int cs35l56_set_fw_suffix(struct cs35l56_private *cs35l56)
{
unsigned short vendor, device;
@@ -1290,6 +1380,12 @@ static int cs35l56_component_probe(struct snd_soc_component *component)
ARRAY_SIZE(cs35l56_cal_data_restore_controls));
}
+ if (!ret && IS_ENABLED(CONFIG_SND_SOC_CS35L56_CAL_PERFORM_CTRL)) {
+ ret = snd_soc_add_component_controls(component,
+ cs35l56_cal_perform_controls,
+ ARRAY_SIZE(cs35l56_cal_perform_controls));
+ }
+
if (ret)
return dev_err_probe(cs35l56->base.dev, ret, "unable to add controls\n");
@@ -1669,7 +1765,7 @@ VISIBLE_IF_KUNIT int cs35l56_process_xu_properties(struct cs35l56_private *cs35l
}
EXPORT_SYMBOL_IF_KUNIT(cs35l56_process_xu_properties);
-static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56)
+VISIBLE_IF_KUNIT int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56)
{
struct device *dev = cs35l56->base.dev;
const char *prop;
@@ -1694,6 +1790,7 @@ static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56)
return 0;
}
+EXPORT_SYMBOL_IF_KUNIT(cs35l56_get_firmware_uid);
/*
* Some SoundWire laptops have a spk-id-gpios property but it points to
diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h
index 691f857d0bd8..cd71b23b2a3a 100644
--- a/sound/soc/codecs/cs35l56.h
+++ b/sound/soc/codecs/cs35l56.h
@@ -42,6 +42,7 @@ struct cs35l56_private {
bool sdw_irq_no_unmask;
bool soft_resetting;
bool sdw_attached;
+ bool sdw_in_clock_stop_1;
struct completion init_completion;
int speaker_id;
@@ -53,6 +54,8 @@ struct cs35l56_private {
bool sysclk_set;
u8 sdw_link_num;
u8 sdw_unique_id;
+
+ u8 ambient_ctl_value;
};
static inline struct cs35l56_private *cs35l56_private_from_base(struct cs35l56_base *cs35l56_base)
@@ -78,6 +81,7 @@ void cs35l56_remove(struct cs35l56_private *cs35l56);
int cs35l56_set_fw_suffix(struct cs35l56_private *cs35l56);
int cs35l56_set_fw_name(struct snd_soc_component *component);
int cs35l56_process_xu_properties(struct cs35l56_private *cs35l56);
+int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56);
#endif
#endif /* ifndef CS35L56_H */
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 3139f03cd42b..a48980e746ff 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -1,12 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* CS4270 ALSA SoC (ASoC) codec driver
*
* Author: Timur Tabi <timur@freescale.com>
*
- * Copyright 2007-2009 Freescale Semiconductor, Inc. This file is licensed
- * under the terms of the GNU General Public License version 2. This
- * program is licensed "as is" without any warranty of any kind, whether
- * express or implied.
+ * Copyright 2007-2009 Freescale Semiconductor, Inc.
*
* This is an ASoC device driver for the Cirrus Logic CS4270 codec.
*
diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c
index fd02d8a57e0f..f0d6ff0b2976 100644
--- a/sound/soc/codecs/cs42l43.c
+++ b/sound/soc/codecs/cs42l43.c
@@ -45,12 +45,25 @@ static SOC_VALUE_ENUM_SINGLE_DECL(cs42l43_##name##_enum, reg, \
static const struct snd_kcontrol_new cs42l43_##name##_mux = \
SOC_DAPM_ENUM("Route", cs42l43_##name##_enum)
+#define CS42L43B_DECL_MUX(name, reg) \
+static SOC_VALUE_ENUM_SINGLE_DECL(cs42l43_##name##_enum, reg, \
+ 0, CS42L43_MIXER_SRC_MASK, \
+ cs42l43b_mixer_texts, cs42l43b_mixer_values); \
+static const struct snd_kcontrol_new cs42l43_##name##_mux = \
+ SOC_DAPM_ENUM("Route", cs42l43_##name##_enum)
+
#define CS42L43_DECL_MIXER(name, reg) \
CS42L43_DECL_MUX(name##_in1, reg); \
CS42L43_DECL_MUX(name##_in2, reg + 0x4); \
CS42L43_DECL_MUX(name##_in3, reg + 0x8); \
CS42L43_DECL_MUX(name##_in4, reg + 0xC)
+#define CS42L43B_DECL_MIXER(name, reg) \
+ CS42L43B_DECL_MUX(name##_in1, reg); \
+ CS42L43B_DECL_MUX(name##_in2, reg + 0x4); \
+ CS42L43B_DECL_MUX(name##_in3, reg + 0x8); \
+ CS42L43B_DECL_MUX(name##_in4, reg + 0xC)
+
#define CS42L43_DAPM_MUX(name_str, name) \
SND_SOC_DAPM_MUX(name_str " Input", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_mux)
@@ -99,11 +112,23 @@ static const struct snd_kcontrol_new cs42l43_##name##_mux = \
{ name_str, "EQ1", "EQ" }, \
{ name_str, "EQ2", "EQ" }
+#define CS42L43B_BASE_ROUTES(name_str) \
+ { name_str, "Decimator 5", "Decimator 5" }, \
+ { name_str, "Decimator 6", "Decimator 6" }, \
+ { name_str, "ISRC1 DEC3", "ISRC1DEC3" }, \
+ { name_str, "ISRC1 DEC4", "ISRC1DEC4" }, \
+ { name_str, "ISRC2 DEC3", "ISRC2DEC3" }, \
+ { name_str, "ISRC2 DEC4", "ISRC2DEC4" }
+
#define CS42L43_MUX_ROUTES(name_str, widget) \
{ widget, NULL, name_str " Input" }, \
{ name_str " Input", NULL, "Mixer Core" }, \
CS42L43_BASE_ROUTES(name_str " Input")
+#define CS42L43B_MUX_ROUTES(name_str, widget) \
+ CS42L43_MUX_ROUTES(name_str, widget), \
+ CS42L43B_BASE_ROUTES(name_str " Input")
+
#define CS42L43_MIXER_ROUTES(name_str, widget) \
{ name_str " Mixer", NULL, name_str " Input 1" }, \
{ name_str " Mixer", NULL, name_str " Input 2" }, \
@@ -116,6 +141,13 @@ static const struct snd_kcontrol_new cs42l43_##name##_mux = \
CS42L43_BASE_ROUTES(name_str " Input 3"), \
CS42L43_BASE_ROUTES(name_str " Input 4")
+#define CS42L43B_MIXER_ROUTES(name_str, widget) \
+ CS42L43_MIXER_ROUTES(name_str, widget), \
+ CS42L43B_BASE_ROUTES(name_str " Input 1"), \
+ CS42L43B_BASE_ROUTES(name_str " Input 2"), \
+ CS42L43B_BASE_ROUTES(name_str " Input 3"), \
+ CS42L43B_BASE_ROUTES(name_str " Input 4")
+
#define CS42L43_MIXER_VOLUMES(name_str, base) \
SOC_SINGLE_RANGE_TLV(name_str " Input 1 Volume", base, \
CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
@@ -300,6 +332,7 @@ static int cs42l43_startup(struct snd_pcm_substream *substream, struct snd_soc_d
struct snd_soc_component *component = dai->component;
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
struct cs42l43 *cs42l43 = priv->core;
+ int ret;
int provider = !dai->id || !!regmap_test_bits(cs42l43->regmap,
CS42L43_ASP_CLK_CONFIG2,
CS42L43_ASP_MASTER_MODE_MASK);
@@ -309,6 +342,14 @@ static int cs42l43_startup(struct snd_pcm_substream *substream, struct snd_soc_d
else
priv->constraint.mask = CS42L43_CONSUMER_RATE_MASK;
+ if (cs42l43->variant_id == CS42L43_DEVID_VAL && (dai->id == 3 || dai->id == 4)) {
+ ret = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ 1, 2);
+ if (ret < 0)
+ return ret;
+ }
+
return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&priv->constraint);
@@ -590,12 +631,25 @@ static int cs42l43_dai_probe(struct snd_soc_dai *dai)
"Decimator 2 Switch",
"Decimator 3 Switch",
"Decimator 4 Switch",
+ "Decimator 5 Switch",
+ "Decimator 6 Switch",
};
- int i;
+ int control_size, i;
static_assert(ARRAY_SIZE(controls) == ARRAY_SIZE(priv->kctl));
- for (i = 0; i < ARRAY_SIZE(controls); i++) {
+ switch (priv->core->variant_id) {
+ case CS42L43_DEVID_VAL:
+ control_size = ARRAY_SIZE(controls) - 2; // ignore Decimator 5 and 6
+ break;
+ case CS42L43B_DEVID_VAL:
+ control_size = ARRAY_SIZE(controls);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = 0; i < control_size; i++) {
if (priv->kctl[i])
continue;
@@ -703,7 +757,7 @@ static struct snd_soc_dai_driver cs42l43_dais[] = {
.capture = {
.stream_name = "DP3 Capture",
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L43_SDW_FORMATS,
},
@@ -715,7 +769,7 @@ static struct snd_soc_dai_driver cs42l43_dais[] = {
.capture = {
.stream_name = "DP4 Capture",
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L43_SDW_FORMATS,
},
@@ -808,6 +862,10 @@ static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL3
CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL4,
CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec5_wnf_corner, CS42L43B_DECIM_HPF_WNF_CTRL5,
+ CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec6_wnf_corner, CS42L43B_DECIM_HPF_WNF_CTRL6,
+ CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
static const char * const cs42l43_hpf_corner_text[] = {
"3Hz", "12Hz", "48Hz", "96Hz",
@@ -821,6 +879,10 @@ static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL3
CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL4,
CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec5_hpf_corner, CS42L43B_DECIM_HPF_WNF_CTRL5,
+ CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec6_hpf_corner, CS42L43B_DECIM_HPF_WNF_CTRL6,
+ CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_ramp_up, CS42L43_DECIM_VOL_CTRL_CH1_CH2,
CS42L43_DECIM1_VI_RAMP_SHIFT, cs42l43_ramp_text);
@@ -839,6 +901,31 @@ static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_ramp_up, CS42L43_DECIM_VOL_CTRL_CH3_CH4
static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_ramp_down, CS42L43_DECIM_VOL_CTRL_CH3_CH4,
CS42L43_DECIM4_VD_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec1_ramp_up, CS42L43B_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM1_VI_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec1_ramp_down, CS42L43B_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM1_VD_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec2_ramp_up, CS42L43B_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM2_VI_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec2_ramp_down, CS42L43B_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM2_VD_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec3_ramp_up, CS42L43B_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM3_VI_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec3_ramp_down, CS42L43B_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM3_VD_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec4_ramp_up, CS42L43B_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM4_VI_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec4_ramp_down, CS42L43B_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM4_VD_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec5_ramp_up, CS42L43B_DECIM_VOL_CTRL_CH5_CH6,
+ CS42L43B_DECIM5_PATH1_VOL_RISE_RATE_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec5_ramp_down, CS42L43B_DECIM_VOL_CTRL_CH5_CH6,
+ CS42L43B_DECIM5_PATH1_VOL_FALL_RATE_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec6_ramp_up, CS42L43B_DECIM_VOL_CTRL_CH5_CH6,
+ CS42L43B_DECIM6_PATH1_VOL_RISE_RATE_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43b_dec6_ramp_down, CS42L43B_DECIM_VOL_CTRL_CH5_CH6,
+ CS42L43B_DECIM6_PATH1_VOL_FALL_RATE_SHIFT, cs42l43_ramp_text);
+
static DECLARE_TLV_DB_SCALE(cs42l43_speaker_tlv, -6400, 50, 0);
static SOC_ENUM_SINGLE_DECL(cs42l43_speaker_ramp_up, CS42L43_AMP1_2_VOL_RAMP,
@@ -898,6 +985,37 @@ static const unsigned int cs42l43_mixer_values[] = {
0x58, 0x59, // EQ1, 2
};
+static const char * const cs42l43b_mixer_texts[] = {
+ "None",
+ "Tone Generator 1", "Tone Generator 2",
+ "Decimator 1", "Decimator 2", "Decimator 3", "Decimator 4", "Decimator 5", "Decimator 6",
+ "ASPRX1", "ASPRX2", "ASPRX3", "ASPRX4", "ASPRX5", "ASPRX6",
+ "DP5RX1", "DP5RX2", "DP6RX1", "DP6RX2", "DP7RX1", "DP7RX2",
+ "ASRC INT1", "ASRC INT2", "ASRC INT3", "ASRC INT4",
+ "ASRC DEC1", "ASRC DEC2", "ASRC DEC3", "ASRC DEC4",
+ "ISRC1 INT1", "ISRC1 INT2",
+ "ISRC1 DEC1", "ISRC1 DEC2", "ISRC1 DEC3", "ISRC1 DEC4",
+ "ISRC2 INT1", "ISRC2 INT2",
+ "ISRC2 DEC1", "ISRC2 DEC2", "ISRC2 DEC3", "ISRC2 DEC4",
+ "EQ1", "EQ2",
+};
+
+static const unsigned int cs42l43b_mixer_values[] = {
+ 0x00, // None
+ 0x04, 0x05, // Tone Generator 1, 2
+ 0x10, 0x11, 0x80, 0x81, 0x12, 0x13, // Decimator 1, 2, 3, 4, 5, 6
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, // ASPRX1,2,3,4,5,6
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, // DP5, 6, 7RX1, 2
+ 0x40, 0x41, 0x42, 0x43, // ASRC INT1, 2, 3, 4
+ 0x44, 0x45, 0x46, 0x47, // ASRC DEC1, 2, 3, 4
+ 0x50, 0x51, // ISRC1 INT1, 2
+ 0x52, 0x53, 0x78, 0x79, // ISRC1 DEC1, 2, 3, 4
+ 0x54, 0x55, // ISRC2 INT1, 2
+ 0x56, 0x57, 0x7A, 0x7B, // ISRC2 DEC1, 2, 3, 4
+ 0x58, 0x59, // EQ1, 2
+};
+
+/* A variant */
CS42L43_DECL_MUX(asptx1, CS42L43_ASPTX1_INPUT);
CS42L43_DECL_MUX(asptx2, CS42L43_ASPTX2_INPUT);
CS42L43_DECL_MUX(asptx3, CS42L43_ASPTX3_INPUT);
@@ -946,6 +1064,63 @@ CS42L43_DECL_MIXER(amp2, CS42L43_AMP2MIX_INPUT1);
CS42L43_DECL_MIXER(amp3, CS42L43_AMP3MIX_INPUT1);
CS42L43_DECL_MIXER(amp4, CS42L43_AMP4MIX_INPUT1);
+/* B variant */
+CS42L43B_DECL_MUX(b_asptx1, CS42L43_ASPTX1_INPUT);
+CS42L43B_DECL_MUX(b_asptx2, CS42L43_ASPTX2_INPUT);
+CS42L43B_DECL_MUX(b_asptx3, CS42L43_ASPTX3_INPUT);
+CS42L43B_DECL_MUX(b_asptx4, CS42L43_ASPTX4_INPUT);
+CS42L43B_DECL_MUX(b_asptx5, CS42L43_ASPTX5_INPUT);
+CS42L43B_DECL_MUX(b_asptx6, CS42L43_ASPTX6_INPUT);
+
+CS42L43B_DECL_MUX(b_dp1tx1, CS42L43_SWIRE_DP1_CH1_INPUT);
+CS42L43B_DECL_MUX(b_dp1tx2, CS42L43_SWIRE_DP1_CH2_INPUT);
+CS42L43B_DECL_MUX(b_dp1tx3, CS42L43_SWIRE_DP1_CH3_INPUT);
+CS42L43B_DECL_MUX(b_dp1tx4, CS42L43_SWIRE_DP1_CH4_INPUT);
+CS42L43B_DECL_MUX(b_dp2tx1, CS42L43_SWIRE_DP2_CH1_INPUT);
+CS42L43B_DECL_MUX(b_dp2tx2, CS42L43_SWIRE_DP2_CH2_INPUT);
+CS42L43B_DECL_MUX(b_dp3tx1, CS42L43_SWIRE_DP3_CH1_INPUT);
+CS42L43B_DECL_MUX(b_dp3tx2, CS42L43_SWIRE_DP3_CH2_INPUT);
+CS42L43B_DECL_MUX(b_dp3tx3, CS42L43B_SWIRE_DP3_CH3_INPUT);
+CS42L43B_DECL_MUX(b_dp3tx4, CS42L43B_SWIRE_DP3_CH4_INPUT);
+CS42L43B_DECL_MUX(b_dp4tx1, CS42L43_SWIRE_DP4_CH1_INPUT);
+CS42L43B_DECL_MUX(b_dp4tx2, CS42L43_SWIRE_DP4_CH2_INPUT);
+CS42L43B_DECL_MUX(b_dp4tx3, CS42L43B_SWIRE_DP4_CH3_INPUT);
+CS42L43B_DECL_MUX(b_dp4tx4, CS42L43B_SWIRE_DP4_CH4_INPUT);
+
+CS42L43B_DECL_MUX(b_asrcint1, CS42L43_ASRC_INT1_INPUT1);
+CS42L43B_DECL_MUX(b_asrcint2, CS42L43_ASRC_INT2_INPUT1);
+CS42L43B_DECL_MUX(b_asrcint3, CS42L43_ASRC_INT3_INPUT1);
+CS42L43B_DECL_MUX(b_asrcint4, CS42L43_ASRC_INT4_INPUT1);
+CS42L43B_DECL_MUX(b_asrcdec1, CS42L43_ASRC_DEC1_INPUT1);
+CS42L43B_DECL_MUX(b_asrcdec2, CS42L43_ASRC_DEC2_INPUT1);
+CS42L43B_DECL_MUX(b_asrcdec3, CS42L43_ASRC_DEC3_INPUT1);
+CS42L43B_DECL_MUX(b_asrcdec4, CS42L43_ASRC_DEC4_INPUT1);
+
+CS42L43B_DECL_MUX(b_isrc1int1, CS42L43_ISRC1INT1_INPUT1);
+CS42L43B_DECL_MUX(b_isrc1int2, CS42L43_ISRC1INT2_INPUT1);
+CS42L43B_DECL_MUX(b_isrc1dec1, CS42L43_ISRC1DEC1_INPUT1);
+CS42L43B_DECL_MUX(b_isrc1dec2, CS42L43_ISRC1DEC2_INPUT1);
+CS42L43B_DECL_MUX(b_isrc1dec3, CS42L43B_ISRC1DEC3_INPUT1);
+CS42L43B_DECL_MUX(b_isrc1dec4, CS42L43B_ISRC1DEC4_INPUT1);
+CS42L43B_DECL_MUX(b_isrc2int1, CS42L43_ISRC2INT1_INPUT1);
+CS42L43B_DECL_MUX(b_isrc2int2, CS42L43_ISRC2INT2_INPUT1);
+CS42L43B_DECL_MUX(b_isrc2dec1, CS42L43_ISRC2DEC1_INPUT1);
+CS42L43B_DECL_MUX(b_isrc2dec2, CS42L43_ISRC2DEC2_INPUT1);
+CS42L43B_DECL_MUX(b_isrc2dec3, CS42L43B_ISRC2DEC3_INPUT1);
+CS42L43B_DECL_MUX(b_isrc2dec4, CS42L43B_ISRC2DEC4_INPUT1);
+
+CS42L43B_DECL_MUX(b_spdif1, CS42L43_SPDIF1_INPUT1);
+CS42L43B_DECL_MUX(b_spdif2, CS42L43_SPDIF2_INPUT1);
+
+CS42L43B_DECL_MIXER(b_eq1, CS42L43_EQ1MIX_INPUT1);
+CS42L43B_DECL_MIXER(b_eq2, CS42L43_EQ2MIX_INPUT1);
+
+CS42L43B_DECL_MIXER(b_amp1, CS42L43_AMP1MIX_INPUT1);
+CS42L43B_DECL_MIXER(b_amp2, CS42L43_AMP2MIX_INPUT1);
+
+CS42L43B_DECL_MIXER(b_amp3, CS42L43_AMP3MIX_INPUT1);
+CS42L43B_DECL_MIXER(b_amp4, CS42L43_AMP4MIX_INPUT1);
+
static int cs42l43_dapm_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1174,44 +1349,6 @@ static const struct snd_kcontrol_new cs42l43_controls[] = {
SOC_ENUM("Decimator 3 HPF Corner Frequency", cs42l43_dec3_hpf_corner),
SOC_ENUM("Decimator 4 HPF Corner Frequency", cs42l43_dec4_hpf_corner),
- SOC_SINGLE_TLV("Decimator 1 Volume", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
- CS42L43_DECIM1_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
- SOC_SINGLE_EXT("Decimator 1 Switch", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
- CS42L43_DECIM1_MUTE_SHIFT, 1, 1,
- cs42l43_decim_get, cs42l43_dapm_put_volsw),
- SOC_SINGLE_TLV("Decimator 2 Volume", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
- CS42L43_DECIM2_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
- SOC_SINGLE_EXT("Decimator 2 Switch", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
- CS42L43_DECIM2_MUTE_SHIFT, 1, 1,
- cs42l43_decim_get, cs42l43_dapm_put_volsw),
- SOC_SINGLE_TLV("Decimator 3 Volume", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
- CS42L43_DECIM3_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
- SOC_SINGLE_EXT("Decimator 3 Switch", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
- CS42L43_DECIM3_MUTE_SHIFT, 1, 1,
- cs42l43_decim_get, cs42l43_dapm_put_volsw),
- SOC_SINGLE_TLV("Decimator 4 Volume", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
- CS42L43_DECIM4_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
- SOC_SINGLE_EXT("Decimator 4 Switch", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
- CS42L43_DECIM4_MUTE_SHIFT, 1, 1,
- cs42l43_decim_get, cs42l43_dapm_put_volsw),
-
- SOC_ENUM_EXT("Decimator 1 Ramp Up", cs42l43_dec1_ramp_up,
- cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
- SOC_ENUM_EXT("Decimator 1 Ramp Down", cs42l43_dec1_ramp_down,
- cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
- SOC_ENUM_EXT("Decimator 2 Ramp Up", cs42l43_dec2_ramp_up,
- cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
- SOC_ENUM_EXT("Decimator 2 Ramp Down", cs42l43_dec2_ramp_down,
- cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
- SOC_ENUM_EXT("Decimator 3 Ramp Up", cs42l43_dec3_ramp_up,
- cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
- SOC_ENUM_EXT("Decimator 3 Ramp Down", cs42l43_dec3_ramp_down,
- cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
- SOC_ENUM_EXT("Decimator 4 Ramp Up", cs42l43_dec4_ramp_up,
- cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
- SOC_ENUM_EXT("Decimator 4 Ramp Down", cs42l43_dec4_ramp_down,
- cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
-
SOC_DOUBLE_R_EXT("Speaker Digital Switch",
CS42L43_INTP_VOLUME_CTRL1, CS42L43_INTP_VOLUME_CTRL2,
CS42L43_AMP_MUTE_SHIFT, 1, 1,
@@ -1601,35 +1738,81 @@ static int cs42l43_mic_ev(struct snd_soc_dapm_widget *w,
unsigned int *val;
int ret;
- switch (w->shift) {
- case CS42L43_ADC1_EN_SHIFT:
- case CS42L43_PDM1_DIN_L_EN_SHIFT:
- reg = CS42L43_DECIM_VOL_CTRL_CH1_CH2;
- ramp = CS42L43_DECIM1_VD_RAMP_MASK;
- mute = CS42L43_DECIM1_MUTE_MASK;
- val = &priv->decim_cache[0];
- break;
- case CS42L43_ADC2_EN_SHIFT:
- case CS42L43_PDM1_DIN_R_EN_SHIFT:
- reg = CS42L43_DECIM_VOL_CTRL_CH1_CH2;
- ramp = CS42L43_DECIM2_VD_RAMP_MASK;
- mute = CS42L43_DECIM2_MUTE_MASK;
- val = &priv->decim_cache[1];
- break;
- case CS42L43_PDM2_DIN_L_EN_SHIFT:
- reg = CS42L43_DECIM_VOL_CTRL_CH3_CH4;
- ramp = CS42L43_DECIM3_VD_RAMP_MASK;
- mute = CS42L43_DECIM3_MUTE_MASK;
- val = &priv->decim_cache[2];
- break;
- case CS42L43_PDM2_DIN_R_EN_SHIFT:
- reg = CS42L43_DECIM_VOL_CTRL_CH3_CH4;
- ramp = CS42L43_DECIM4_VD_RAMP_MASK;
- mute = CS42L43_DECIM4_MUTE_MASK;
- val = &priv->decim_cache[3];
- break;
- default:
- dev_err(priv->dev, "Invalid microphone shift: %d\n", w->shift);
+ if (cs42l43->variant_id == CS42L43_DEVID_VAL) {
+ switch (w->shift) {
+ case CS42L43_ADC1_EN_SHIFT:
+ case CS42L43_PDM1_DIN_L_EN_SHIFT:
+ reg = CS42L43_DECIM_VOL_CTRL_CH1_CH2;
+ ramp = CS42L43_DECIM1_VD_RAMP_MASK;
+ mute = CS42L43_DECIM1_MUTE_MASK;
+ val = &priv->decim_cache[0];
+ break;
+ case CS42L43_ADC2_EN_SHIFT:
+ case CS42L43_PDM1_DIN_R_EN_SHIFT:
+ reg = CS42L43_DECIM_VOL_CTRL_CH1_CH2;
+ ramp = CS42L43_DECIM2_VD_RAMP_MASK;
+ mute = CS42L43_DECIM2_MUTE_MASK;
+ val = &priv->decim_cache[1];
+ break;
+ case CS42L43_PDM2_DIN_L_EN_SHIFT:
+ reg = CS42L43_DECIM_VOL_CTRL_CH3_CH4;
+ ramp = CS42L43_DECIM3_VD_RAMP_MASK;
+ mute = CS42L43_DECIM3_MUTE_MASK;
+ val = &priv->decim_cache[2];
+ break;
+ case CS42L43_PDM2_DIN_R_EN_SHIFT:
+ reg = CS42L43_DECIM_VOL_CTRL_CH3_CH4;
+ ramp = CS42L43_DECIM4_VD_RAMP_MASK;
+ mute = CS42L43_DECIM4_MUTE_MASK;
+ val = &priv->decim_cache[3];
+ break;
+ default:
+ dev_err(priv->dev, "Invalid microphone shift: %d\n", w->shift);
+ return -EINVAL;
+ }
+ } else if (cs42l43->variant_id == CS42L43B_DEVID_VAL) {
+ switch (w->shift) {
+ case CS42L43_ADC1_EN_SHIFT:
+ reg = CS42L43B_DECIM_VOL_CTRL_CH1_CH2;
+ ramp = CS42L43_DECIM1_VD_RAMP_MASK;
+ mute = CS42L43_DECIM1_MUTE_MASK;
+ val = &priv->decim_cache[0];
+ break;
+ case CS42L43_ADC2_EN_SHIFT:
+ reg = CS42L43B_DECIM_VOL_CTRL_CH1_CH2;
+ ramp = CS42L43_DECIM2_VD_RAMP_MASK;
+ mute = CS42L43_DECIM2_MUTE_MASK;
+ val = &priv->decim_cache[1];
+ break;
+ case CS42L43_PDM1_DIN_L_EN_SHIFT:
+ reg = CS42L43B_DECIM_VOL_CTRL_CH3_CH4;
+ ramp = CS42L43_DECIM3_VD_RAMP_MASK;
+ mute = CS42L43_DECIM3_MUTE_MASK;
+ val = &priv->decim_cache[2];
+ break;
+ case CS42L43_PDM1_DIN_R_EN_SHIFT:
+ reg = CS42L43B_DECIM_VOL_CTRL_CH3_CH4;
+ ramp = CS42L43_DECIM4_VD_RAMP_MASK;
+ mute = CS42L43_DECIM4_MUTE_MASK;
+ val = &priv->decim_cache[3];
+ break;
+ case CS42L43_PDM2_DIN_L_EN_SHIFT:
+ reg = CS42L43B_DECIM_VOL_CTRL_CH5_CH6;
+ ramp = CS42L43B_DECIM5_PATH1_VOL_FALL_RATE_MASK;
+ mute = CS42L43B_DECIM5_MUTE_MASK;
+ val = &priv->decim_cache[4];
+ break;
+ case CS42L43_PDM2_DIN_R_EN_SHIFT:
+ reg = CS42L43B_DECIM_VOL_CTRL_CH5_CH6;
+ ramp = CS42L43B_DECIM6_PATH1_VOL_FALL_RATE_MASK;
+ mute = CS42L43B_DECIM6_MUTE_MASK;
+ val = &priv->decim_cache[5];
+ break;
+ default:
+ dev_err(priv->dev, "Invalid microphone shift: %d\n", w->shift);
+ return -EINVAL;
+ }
+ } else {
return -EINVAL;
}
@@ -1722,11 +1905,6 @@ static const struct snd_soc_dapm_widget cs42l43_widgets[] = {
0, NULL, 0, cs42l43_mic_ev,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MUX("Decimator 1 Mode", SND_SOC_NOPM, 0, 0,
- &cs42l43_dec_mode_ctl[0]),
- SND_SOC_DAPM_MUX("Decimator 2 Mode", SND_SOC_NOPM, 0, 0,
- &cs42l43_dec_mode_ctl[1]),
-
SND_SOC_DAPM_PGA("Decimator 1", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Decimator 2", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Decimator 3", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -1871,53 +2049,6 @@ static const struct snd_soc_dapm_widget cs42l43_widgets[] = {
SND_SOC_DAPM_SUPPLY("Mixer Core", CS42L43_BLOCK_EN6, CS42L43_MIXER_EN_SHIFT,
0, NULL, 0),
- CS42L43_DAPM_MUX("ASPTX1", asptx1),
- CS42L43_DAPM_MUX("ASPTX2", asptx2),
- CS42L43_DAPM_MUX("ASPTX3", asptx3),
- CS42L43_DAPM_MUX("ASPTX4", asptx4),
- CS42L43_DAPM_MUX("ASPTX5", asptx5),
- CS42L43_DAPM_MUX("ASPTX6", asptx6),
-
- CS42L43_DAPM_MUX("DP1TX1", dp1tx1),
- CS42L43_DAPM_MUX("DP1TX2", dp1tx2),
- CS42L43_DAPM_MUX("DP1TX3", dp1tx3),
- CS42L43_DAPM_MUX("DP1TX4", dp1tx4),
- CS42L43_DAPM_MUX("DP2TX1", dp2tx1),
- CS42L43_DAPM_MUX("DP2TX2", dp2tx2),
- CS42L43_DAPM_MUX("DP3TX1", dp3tx1),
- CS42L43_DAPM_MUX("DP3TX2", dp3tx2),
- CS42L43_DAPM_MUX("DP4TX1", dp4tx1),
- CS42L43_DAPM_MUX("DP4TX2", dp4tx2),
-
- CS42L43_DAPM_MUX("ASRC INT1", asrcint1),
- CS42L43_DAPM_MUX("ASRC INT2", asrcint2),
- CS42L43_DAPM_MUX("ASRC INT3", asrcint3),
- CS42L43_DAPM_MUX("ASRC INT4", asrcint4),
- CS42L43_DAPM_MUX("ASRC DEC1", asrcdec1),
- CS42L43_DAPM_MUX("ASRC DEC2", asrcdec2),
- CS42L43_DAPM_MUX("ASRC DEC3", asrcdec3),
- CS42L43_DAPM_MUX("ASRC DEC4", asrcdec4),
-
- CS42L43_DAPM_MUX("ISRC1INT1", isrc1int1),
- CS42L43_DAPM_MUX("ISRC1INT2", isrc1int2),
- CS42L43_DAPM_MUX("ISRC1DEC1", isrc1dec1),
- CS42L43_DAPM_MUX("ISRC1DEC2", isrc1dec2),
- CS42L43_DAPM_MUX("ISRC2INT1", isrc2int1),
- CS42L43_DAPM_MUX("ISRC2INT2", isrc2int2),
- CS42L43_DAPM_MUX("ISRC2DEC1", isrc2dec1),
- CS42L43_DAPM_MUX("ISRC2DEC2", isrc2dec2),
-
- CS42L43_DAPM_MUX("SPDIF1", spdif1),
- CS42L43_DAPM_MUX("SPDIF2", spdif2),
-
- CS42L43_DAPM_MIXER("EQ1", eq1),
- CS42L43_DAPM_MIXER("EQ2", eq2),
-
- CS42L43_DAPM_MIXER("Speaker L", amp1),
- CS42L43_DAPM_MIXER("Speaker R", amp2),
-
- CS42L43_DAPM_MIXER("Headphone L", amp3),
- CS42L43_DAPM_MIXER("Headphone R", amp4),
};
static const struct snd_soc_dapm_route cs42l43_routes[] = {
@@ -1963,16 +2094,6 @@ static const struct snd_soc_dapm_route cs42l43_routes[] = {
{ "PDM2L", NULL, "PDM2_DIN" },
{ "PDM2R", NULL, "PDM2_DIN" },
- { "Decimator 1 Mode", "PDM", "PDM1L" },
- { "Decimator 1 Mode", "ADC", "ADC1" },
- { "Decimator 2 Mode", "PDM", "PDM1R" },
- { "Decimator 2 Mode", "ADC", "ADC2" },
-
- { "Decimator 1", NULL, "Decimator 1 Mode" },
- { "Decimator 2", NULL, "Decimator 2 Mode" },
- { "Decimator 3", NULL, "PDM2L" },
- { "Decimator 4", NULL, "PDM2R" },
-
{ "ASP Capture", NULL, "ASPTX1" },
{ "ASP Capture", NULL, "ASPTX2" },
{ "ASP Capture", NULL, "ASPTX3" },
@@ -2060,6 +2181,261 @@ static const struct snd_soc_dapm_route cs42l43_routes[] = {
{ "ASRC_DEC4", NULL, "ASRC_DEC" },
{ "EQ", NULL, "EQ Clock" },
+};
+
+static const struct snd_kcontrol_new cs42l43_a_controls[] = {
+ SOC_ENUM_EXT("Decimator 1 Ramp Up", cs42l43_dec1_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 1 Ramp Down", cs42l43_dec1_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 2 Ramp Up", cs42l43_dec2_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 2 Ramp Down", cs42l43_dec2_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 3 Ramp Up", cs42l43_dec3_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 3 Ramp Down", cs42l43_dec3_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 4 Ramp Up", cs42l43_dec4_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 4 Ramp Down", cs42l43_dec4_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+
+ SOC_SINGLE_TLV("Decimator 1 Volume", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM1_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 1 Switch", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM1_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+ SOC_SINGLE_TLV("Decimator 2 Volume", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM2_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 2 Switch", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM2_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+ SOC_SINGLE_TLV("Decimator 3 Volume", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM3_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 3 Switch", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM3_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+ SOC_SINGLE_TLV("Decimator 4 Volume", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM4_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 4 Switch", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM4_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+};
+
+static const struct snd_kcontrol_new cs42l43_b_controls[] = {
+ SOC_SINGLE_TLV("Decimator 1 Volume", CS42L43B_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM1_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 1 Switch", CS42L43B_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM1_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+ SOC_SINGLE_TLV("Decimator 2 Volume", CS42L43B_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM2_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 2 Switch", CS42L43B_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM2_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+ SOC_SINGLE_TLV("Decimator 3 Volume", CS42L43B_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM3_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 3 Switch", CS42L43B_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM3_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+ SOC_SINGLE_TLV("Decimator 4 Volume", CS42L43B_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM4_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 4 Switch", CS42L43B_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM4_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+ SOC_SINGLE_TLV("Decimator 5 Volume", CS42L43B_DECIM_VOL_CTRL_CH5_CH6,
+ CS42L43B_DECIM5_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 5 Switch", CS42L43B_DECIM_VOL_CTRL_CH5_CH6,
+ CS42L43B_DECIM5_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+ SOC_SINGLE_TLV("Decimator 6 Volume", CS42L43B_DECIM_VOL_CTRL_CH5_CH6,
+ CS42L43B_DECIM6_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 6 Switch", CS42L43B_DECIM_VOL_CTRL_CH5_CH6,
+ CS42L43B_DECIM6_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+
+ SOC_ENUM_EXT("Decimator 1 Ramp Up", cs42l43b_dec1_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 1 Ramp Down", cs42l43b_dec1_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 2 Ramp Up", cs42l43b_dec2_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 2 Ramp Down", cs42l43b_dec2_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 3 Ramp Up", cs42l43b_dec3_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 3 Ramp Down", cs42l43b_dec3_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 4 Ramp Up", cs42l43b_dec4_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 4 Ramp Down", cs42l43b_dec4_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 5 Ramp Up", cs42l43b_dec5_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 5 Ramp Down", cs42l43b_dec5_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 6 Ramp Up", cs42l43b_dec6_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 6 Ramp Down", cs42l43b_dec6_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+
+ SOC_SINGLE("Decimator 5 WNF Switch", CS42L43B_DECIM_HPF_WNF_CTRL5,
+ CS42L43_DECIM_WNF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Decimator 6 WNF Switch", CS42L43B_DECIM_HPF_WNF_CTRL6,
+ CS42L43_DECIM_WNF_EN_SHIFT, 1, 0),
+
+ SOC_ENUM("Decimator 5 WNF Corner Frequency", cs42l43b_dec5_wnf_corner),
+ SOC_ENUM("Decimator 6 WNF Corner Frequency", cs42l43b_dec6_wnf_corner),
+
+ SOC_SINGLE("Decimator 5 HPF Switch", CS42L43B_DECIM_HPF_WNF_CTRL5,
+ CS42L43_DECIM_HPF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Decimator 6 HPF Switch", CS42L43B_DECIM_HPF_WNF_CTRL6,
+ CS42L43_DECIM_HPF_EN_SHIFT, 1, 0),
+
+ SOC_ENUM("Decimator 5 HPF Corner Frequency", cs42l43b_dec5_hpf_corner),
+ SOC_ENUM("Decimator 6 HPF Corner Frequency", cs42l43b_dec6_hpf_corner),
+};
+
+static const struct snd_soc_dapm_widget cs42l43_a_widgets[] = {
+ SND_SOC_DAPM_MUX("Decimator 1 Mode", SND_SOC_NOPM, 0, 0,
+ &cs42l43_dec_mode_ctl[0]),
+ SND_SOC_DAPM_MUX("Decimator 2 Mode", SND_SOC_NOPM, 0, 0,
+ &cs42l43_dec_mode_ctl[1]),
+ CS42L43_DAPM_MUX("ASPTX1", asptx1),
+ CS42L43_DAPM_MUX("ASPTX2", asptx2),
+ CS42L43_DAPM_MUX("ASPTX3", asptx3),
+ CS42L43_DAPM_MUX("ASPTX4", asptx4),
+ CS42L43_DAPM_MUX("ASPTX5", asptx5),
+ CS42L43_DAPM_MUX("ASPTX6", asptx6),
+
+ CS42L43_DAPM_MUX("DP1TX1", dp1tx1),
+ CS42L43_DAPM_MUX("DP1TX2", dp1tx2),
+ CS42L43_DAPM_MUX("DP1TX3", dp1tx3),
+ CS42L43_DAPM_MUX("DP1TX4", dp1tx4),
+ CS42L43_DAPM_MUX("DP2TX1", dp2tx1),
+ CS42L43_DAPM_MUX("DP2TX2", dp2tx2),
+ CS42L43_DAPM_MUX("DP3TX1", dp3tx1),
+ CS42L43_DAPM_MUX("DP3TX2", dp3tx2),
+ CS42L43_DAPM_MUX("DP4TX1", dp4tx1),
+ CS42L43_DAPM_MUX("DP4TX2", dp4tx2),
+
+ CS42L43_DAPM_MUX("ASRC INT1", asrcint1),
+ CS42L43_DAPM_MUX("ASRC INT2", asrcint2),
+ CS42L43_DAPM_MUX("ASRC INT3", asrcint3),
+ CS42L43_DAPM_MUX("ASRC INT4", asrcint4),
+ CS42L43_DAPM_MUX("ASRC DEC1", asrcdec1),
+ CS42L43_DAPM_MUX("ASRC DEC2", asrcdec2),
+ CS42L43_DAPM_MUX("ASRC DEC3", asrcdec3),
+ CS42L43_DAPM_MUX("ASRC DEC4", asrcdec4),
+
+ CS42L43_DAPM_MUX("ISRC1INT1", isrc1int1),
+ CS42L43_DAPM_MUX("ISRC1INT2", isrc1int2),
+ CS42L43_DAPM_MUX("ISRC1DEC1", isrc1dec1),
+ CS42L43_DAPM_MUX("ISRC1DEC2", isrc1dec2),
+ CS42L43_DAPM_MUX("ISRC2INT1", isrc2int1),
+ CS42L43_DAPM_MUX("ISRC2INT2", isrc2int2),
+ CS42L43_DAPM_MUX("ISRC2DEC1", isrc2dec1),
+ CS42L43_DAPM_MUX("ISRC2DEC2", isrc2dec2),
+
+ CS42L43_DAPM_MUX("SPDIF1", spdif1),
+ CS42L43_DAPM_MUX("SPDIF2", spdif2),
+
+ CS42L43_DAPM_MIXER("EQ1", eq1),
+ CS42L43_DAPM_MIXER("EQ2", eq2),
+
+ CS42L43_DAPM_MIXER("Speaker L", amp1),
+ CS42L43_DAPM_MIXER("Speaker R", amp2),
+
+ CS42L43_DAPM_MIXER("Headphone L", amp3),
+ CS42L43_DAPM_MIXER("Headphone R", amp4),
+};
+
+static const struct snd_soc_dapm_widget cs42l43_b_widgets[] = {
+ SND_SOC_DAPM_AIF_OUT("DP3TX3", NULL, 2, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP3TX4", NULL, 3, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP4TX3", NULL, 2, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP4TX4", NULL, 3, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_PGA("Decimator 5", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Decimator 6", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("ISRC1DEC3", CS42L43_ISRC1_CTRL,
+ CS42L43B_ISRC_DEC3_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC1DEC4", CS42L43_ISRC1_CTRL,
+ CS42L43B_ISRC_DEC4_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC2DEC3", CS42L43_ISRC2_CTRL,
+ CS42L43B_ISRC_DEC3_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC2DEC4", CS42L43_ISRC2_CTRL,
+ CS42L43B_ISRC_DEC4_EN_SHIFT, 0, NULL, 0),
+
+ CS42L43_DAPM_MUX("ASPTX1", b_asptx1),
+ CS42L43_DAPM_MUX("ASPTX2", b_asptx2),
+ CS42L43_DAPM_MUX("ASPTX3", b_asptx3),
+ CS42L43_DAPM_MUX("ASPTX4", b_asptx4),
+ CS42L43_DAPM_MUX("ASPTX5", b_asptx5),
+ CS42L43_DAPM_MUX("ASPTX6", b_asptx6),
+
+ CS42L43_DAPM_MUX("DP1TX1", b_dp1tx1),
+ CS42L43_DAPM_MUX("DP1TX2", b_dp1tx2),
+ CS42L43_DAPM_MUX("DP1TX3", b_dp1tx3),
+ CS42L43_DAPM_MUX("DP1TX4", b_dp1tx4),
+ CS42L43_DAPM_MUX("DP2TX1", b_dp2tx1),
+ CS42L43_DAPM_MUX("DP2TX2", b_dp2tx2),
+ CS42L43_DAPM_MUX("DP3TX1", b_dp3tx1),
+ CS42L43_DAPM_MUX("DP3TX2", b_dp3tx2),
+ CS42L43_DAPM_MUX("DP3TX3", b_dp3tx3),
+ CS42L43_DAPM_MUX("DP3TX4", b_dp3tx4),
+ CS42L43_DAPM_MUX("DP4TX1", b_dp4tx1),
+ CS42L43_DAPM_MUX("DP4TX2", b_dp4tx2),
+ CS42L43_DAPM_MUX("DP4TX3", b_dp4tx3),
+ CS42L43_DAPM_MUX("DP4TX4", b_dp4tx4),
+
+ CS42L43_DAPM_MUX("ASRC INT1", b_asrcint1),
+ CS42L43_DAPM_MUX("ASRC INT2", b_asrcint2),
+ CS42L43_DAPM_MUX("ASRC INT3", b_asrcint3),
+ CS42L43_DAPM_MUX("ASRC INT4", b_asrcint4),
+ CS42L43_DAPM_MUX("ASRC DEC1", b_asrcdec1),
+ CS42L43_DAPM_MUX("ASRC DEC2", b_asrcdec2),
+ CS42L43_DAPM_MUX("ASRC DEC3", b_asrcdec3),
+ CS42L43_DAPM_MUX("ASRC DEC4", b_asrcdec4),
+
+ CS42L43_DAPM_MUX("ISRC1INT1", b_isrc1int1),
+ CS42L43_DAPM_MUX("ISRC1INT2", b_isrc1int2),
+ CS42L43_DAPM_MUX("ISRC1DEC1", b_isrc1dec1),
+ CS42L43_DAPM_MUX("ISRC1DEC2", b_isrc1dec2),
+ CS42L43_DAPM_MUX("ISRC1DEC3", b_isrc1dec3),
+ CS42L43_DAPM_MUX("ISRC1DEC4", b_isrc1dec4),
+ CS42L43_DAPM_MUX("ISRC2INT1", b_isrc2int1),
+ CS42L43_DAPM_MUX("ISRC2INT2", b_isrc2int2),
+ CS42L43_DAPM_MUX("ISRC2DEC1", b_isrc2dec1),
+ CS42L43_DAPM_MUX("ISRC2DEC2", b_isrc2dec2),
+ CS42L43_DAPM_MUX("ISRC2DEC3", b_isrc2dec3),
+ CS42L43_DAPM_MUX("ISRC2DEC4", b_isrc2dec4),
+
+ CS42L43_DAPM_MUX("SPDIF1", b_spdif1),
+ CS42L43_DAPM_MUX("SPDIF2", b_spdif2),
+
+ CS42L43_DAPM_MIXER("EQ1", b_eq1),
+ CS42L43_DAPM_MIXER("EQ2", b_eq2),
+
+ CS42L43_DAPM_MIXER("Speaker L", b_amp1),
+ CS42L43_DAPM_MIXER("Speaker R", b_amp2),
+
+ CS42L43_DAPM_MIXER("Headphone L", b_amp3),
+ CS42L43_DAPM_MIXER("Headphone R", b_amp4),
+};
+
+static const struct snd_soc_dapm_route cs42l43_a_routes[] = {
+ { "Decimator 1 Mode", "PDM", "PDM1L" },
+ { "Decimator 1 Mode", "ADC", "ADC1" },
+ { "Decimator 2 Mode", "PDM", "PDM1R" },
+ { "Decimator 2 Mode", "ADC", "ADC2" },
+
+ { "Decimator 1", NULL, "Decimator 1 Mode" },
+ { "Decimator 2", NULL, "Decimator 2 Mode" },
+ { "Decimator 3", NULL, "PDM2L" },
+ { "Decimator 4", NULL, "PDM2R" },
CS42L43_MUX_ROUTES("ASPTX1", "ASPTX1"),
CS42L43_MUX_ROUTES("ASPTX2", "ASPTX2"),
@@ -2110,6 +2486,81 @@ static const struct snd_soc_dapm_route cs42l43_routes[] = {
CS42L43_MIXER_ROUTES("Headphone R", "HP"),
};
+static const struct snd_soc_dapm_route cs42l43_b_routes[] = {
+ { "Decimator 1", NULL, "ADC1" },
+ { "Decimator 2", NULL, "ADC2" },
+ { "Decimator 3", NULL, "PDM1L" },
+ { "Decimator 4", NULL, "PDM1R" },
+ { "Decimator 5", NULL, "PDM2L" },
+ { "Decimator 6", NULL, "PDM2R" },
+
+ { "DP3 Capture", NULL, "DP3TX3" },
+ { "DP3 Capture", NULL, "DP3TX4" },
+ { "DP4 Capture", NULL, "DP4TX3" },
+ { "DP4 Capture", NULL, "DP4TX4" },
+
+ { "ISRC1DEC3", NULL, "ISRC1" },
+ { "ISRC1DEC4", NULL, "ISRC1" },
+ { "ISRC2DEC3", NULL, "ISRC2" },
+ { "ISRC2DEC4", NULL, "ISRC2" },
+
+ CS42L43B_MUX_ROUTES("ASPTX1", "ASPTX1"),
+ CS42L43B_MUX_ROUTES("ASPTX2", "ASPTX2"),
+ CS42L43B_MUX_ROUTES("ASPTX3", "ASPTX3"),
+ CS42L43B_MUX_ROUTES("ASPTX4", "ASPTX4"),
+ CS42L43B_MUX_ROUTES("ASPTX5", "ASPTX5"),
+ CS42L43B_MUX_ROUTES("ASPTX6", "ASPTX6"),
+
+ CS42L43B_MUX_ROUTES("DP1TX1", "DP1TX1"),
+ CS42L43B_MUX_ROUTES("DP1TX2", "DP1TX2"),
+ CS42L43B_MUX_ROUTES("DP1TX3", "DP1TX3"),
+ CS42L43B_MUX_ROUTES("DP1TX4", "DP1TX4"),
+ CS42L43B_MUX_ROUTES("DP2TX1", "DP2TX1"),
+ CS42L43B_MUX_ROUTES("DP2TX2", "DP2TX2"),
+ CS42L43B_MUX_ROUTES("DP3TX1", "DP3TX1"),
+ CS42L43B_MUX_ROUTES("DP3TX2", "DP3TX2"),
+ CS42L43B_MUX_ROUTES("DP3TX3", "DP3TX3"),
+ CS42L43B_MUX_ROUTES("DP3TX4", "DP3TX4"),
+ CS42L43B_MUX_ROUTES("DP4TX1", "DP4TX1"),
+ CS42L43B_MUX_ROUTES("DP4TX2", "DP4TX2"),
+ CS42L43B_MUX_ROUTES("DP4TX3", "DP4TX3"),
+ CS42L43B_MUX_ROUTES("DP4TX4", "DP4TX4"),
+
+ CS42L43B_MUX_ROUTES("ASRC INT1", "ASRC_INT1"),
+ CS42L43B_MUX_ROUTES("ASRC INT2", "ASRC_INT2"),
+ CS42L43B_MUX_ROUTES("ASRC INT3", "ASRC_INT3"),
+ CS42L43B_MUX_ROUTES("ASRC INT4", "ASRC_INT4"),
+ CS42L43B_MUX_ROUTES("ASRC DEC1", "ASRC_DEC1"),
+ CS42L43B_MUX_ROUTES("ASRC DEC2", "ASRC_DEC2"),
+ CS42L43B_MUX_ROUTES("ASRC DEC3", "ASRC_DEC3"),
+ CS42L43B_MUX_ROUTES("ASRC DEC4", "ASRC_DEC4"),
+
+ CS42L43B_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+ CS42L43B_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+ CS42L43B_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+ CS42L43B_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+ CS42L43B_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"),
+ CS42L43B_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"),
+ CS42L43B_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+ CS42L43B_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+ CS42L43B_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+ CS42L43B_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+ CS42L43B_MUX_ROUTES("ISRC2DEC3", "ISRC2DEC3"),
+ CS42L43B_MUX_ROUTES("ISRC2DEC4", "ISRC2DEC4"),
+
+ CS42L43B_MUX_ROUTES("SPDIF1", "SPDIF"),
+ CS42L43B_MUX_ROUTES("SPDIF2", "SPDIF"),
+
+ CS42L43B_MIXER_ROUTES("EQ1", "EQ"),
+ CS42L43B_MIXER_ROUTES("EQ2", "EQ"),
+
+ CS42L43B_MIXER_ROUTES("Speaker L", "AMP1"),
+ CS42L43B_MIXER_ROUTES("Speaker R", "AMP2"),
+
+ CS42L43B_MIXER_ROUTES("Headphone L", "HP"),
+ CS42L43B_MIXER_ROUTES("Headphone R", "HP"),
+};
+
static int cs42l43_set_sysclk(struct snd_soc_component *component, int clk_id,
int src, unsigned int freq, int dir)
{
@@ -2126,8 +2577,14 @@ static int cs42l43_set_sysclk(struct snd_soc_component *component, int clk_id,
static int cs42l43_component_probe(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ unsigned int num_controls, num_widgets, num_routes;
+ const struct snd_soc_dapm_widget *widgets;
+ const struct snd_kcontrol_new *controls;
+ const struct snd_soc_dapm_route *routes;
struct cs42l43 *cs42l43 = priv->core;
+ int ret;
snd_soc_component_init_regmap(component, cs42l43->regmap);
@@ -2139,6 +2596,39 @@ static int cs42l43_component_probe(struct snd_soc_component *component)
priv->component = component;
priv->constraint = cs42l43_constraint;
+ switch (cs42l43->variant_id) {
+ case CS42L43_DEVID_VAL:
+ controls = cs42l43_a_controls;
+ num_controls = ARRAY_SIZE(cs42l43_a_controls);
+ widgets = cs42l43_a_widgets;
+ num_widgets = ARRAY_SIZE(cs42l43_a_widgets);
+ routes = cs42l43_a_routes;
+ num_routes = ARRAY_SIZE(cs42l43_a_routes);
+ break;
+ case CS42L43B_DEVID_VAL:
+ controls = cs42l43_b_controls;
+ num_controls = ARRAY_SIZE(cs42l43_b_controls);
+ widgets = cs42l43_b_widgets;
+ num_widgets = ARRAY_SIZE(cs42l43_b_widgets);
+ routes = cs42l43_b_routes;
+ num_routes = ARRAY_SIZE(cs42l43_b_routes);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = snd_soc_add_component_controls(component, controls, num_controls);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_new_controls(dapm, widgets, num_widgets);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, routes, num_routes);
+ if (ret)
+ return ret;
+
return 0;
}
diff --git a/sound/soc/codecs/cs42l43.h b/sound/soc/codecs/cs42l43.h
index b2fa2cd1d99f..fd50feb26ae9 100644
--- a/sound/soc/codecs/cs42l43.h
+++ b/sound/soc/codecs/cs42l43.h
@@ -61,7 +61,7 @@ struct cs42l43_codec {
unsigned int refclk_freq;
struct completion pll_ready;
- unsigned int decim_cache[4];
+ unsigned int decim_cache[6];
unsigned int adc_ena;
unsigned int hp_ena;
@@ -103,7 +103,7 @@ struct cs42l43_codec {
bool hp_ilimited;
int hp_ilimit_count;
- struct snd_kcontrol *kctl[5];
+ struct snd_kcontrol *kctl[7];
};
#if IS_REACHABLE(CONFIG_SND_SOC_CS42L43_SDW)
diff --git a/sound/soc/codecs/cs42l84.c b/sound/soc/codecs/cs42l84.c
index 1e1307a16f81..e590a43559e4 100644
--- a/sound/soc/codecs/cs42l84.c
+++ b/sound/soc/codecs/cs42l84.c
@@ -357,8 +357,11 @@ struct cs42l84_pll_params {
* Common PLL Settings for given BCLK
*/
static const struct cs42l84_pll_params pll_ratio_table[] = {
+ { 2822400, 1, 0, 0x40, 0x000000, 0x03, 0x10, 11289600},
{ 3072000, 1, 0, 0x40, 0x000000, 0x03, 0x10, 12288000},
+ { 5644800, 1, 0, 0x40, 0x000000, 0x03, 0x10, 11289600},
{ 6144000, 1, 1, 0x40, 0x000000, 0x03, 0x10, 12288000},
+ { 11289600, 0, 0, 0, 0, 0, 0, 11289600},
{ 12288000, 0, 0, 0, 0, 0, 0, 12288000},
{ 24576000, 1, 3, 0x40, 0x000000, 0x03, 0x10, 12288000},
};
@@ -408,11 +411,18 @@ static int cs42l84_pll_config(struct snd_soc_component *component)
CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI,
FIELD_PREP(CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI, fsync >> 7));
- /* Save what the MCLK will be */
+ /*
+ * MCLK values are binned into 12 or 24 MHz regions. If MCLK is exactly
+ * 12 or 24 MHz, the high bit of CCM_CTL1_MCLK_F is set. If MCLK
+ * is in the region of 24 MHz, the low bit is set. This seemingly
+ * corresponds to CS42L42's documented INTERNAL_FS and MCLKDIV
+ * behaviour respectively.
+ */
switch (pll_ratio_table[i].mclk_int) {
case 12000000:
cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_12MHZ;
break;
+ case 11289600:
case 12288000:
cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_12_288KHZ;
break;
@@ -670,14 +680,18 @@ static struct snd_soc_dai_driver cs42l84_dai = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000,
+ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
.formats = CS42L84_FORMATS,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 1,
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000,
+ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
.formats = CS42L84_FORMATS,
},
.symmetric_rate = 1,
diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c
index 039b3ecb3b9b..0faca384073a 100644
--- a/sound/soc/codecs/cs42xx8-i2c.c
+++ b/sound/soc/codecs/cs42xx8-i2c.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Cirrus Logic CS42448/CS42888 Audio CODEC DAI I2C driver
*
* Copyright (C) 2014 Freescale Semiconductor, Inc.
*
* Author: Nicolin Chen <Guangyu.Chen@freescale.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
*/
#include <linux/i2c.h>
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
index d14538c49b97..12fe9b3e2525 100644
--- a/sound/soc/codecs/cs42xx8.c
+++ b/sound/soc/codecs/cs42xx8.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver
*
* Copyright (C) 2014 Freescale Semiconductor, Inc.
*
* Author: Nicolin Chen <Guangyu.Chen@freescale.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
*/
#include <linux/clk.h>
@@ -43,6 +40,7 @@ struct cs42xx8_priv {
struct clk *clk;
bool slave_mode;
+ bool is_tdm_mode;
unsigned long sysclk;
u32 tx_channels;
struct gpio_desc *gpiod_reset;
@@ -217,6 +215,8 @@ static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
u32 val;
+ cs42xx8->is_tdm_mode = false;
+
/* Set DAI format */
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_LEFT_J:
@@ -230,6 +230,7 @@ static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
break;
case SND_SOC_DAIFMT_DSP_A:
val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM;
+ cs42xx8->is_tdm_mode = true;
break;
default:
dev_err(component->dev, "unsupported dai format\n");
@@ -253,6 +254,11 @@ static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL;
}
+ if (cs42xx8->is_tdm_mode && !cs42xx8->slave_mode) {
+ dev_err(component->dev, "TDM mode is supported only in slave mode\n");
+ return -EINVAL;
+ }
+
return 0;
}
@@ -335,6 +341,19 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
cs42xx8->rate[tx] = params_rate(params);
+ if (cs42xx8->is_tdm_mode) {
+ if (cs42xx8->sysclk < 256 * cs42xx8->rate[tx]) {
+ dev_err(component->dev, "Unsupported sysclk in TDM mode\n");
+ return -EINVAL;
+ }
+
+ if (!tx && cs42xx8->rate[tx] > 100000) {
+ dev_err(component->dev,
+ "ADC does not support Quad-Speed Mode in TDM mode\n");
+ return -EINVAL;
+ }
+ }
+
mask = CS42XX8_FUNCMOD_MFREQ_MASK;
val = cs42xx8_ratios[i].mfreq;
diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h
index 342389e8b1a8..4087c91471d1 100644
--- a/sound/soc/codecs/cs42xx8.h
+++ b/sound/soc/codecs/cs42xx8.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* cs42xx8.h - Cirrus Logic CS42448/CS42888 Audio CODEC driver header file
*
* Copyright (C) 2014 Freescale Semiconductor, Inc.
*
* Author: Nicolin Chen <Guangyu.Chen@freescale.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
*/
#ifndef _CS42XX8_H
diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c
index d9d932a78b71..0b3b108aaeee 100644
--- a/sound/soc/codecs/da7219-aad.c
+++ b/sound/soc/codecs/da7219-aad.c
@@ -924,6 +924,7 @@ static void da7219_aad_handle_gnd_switch_time(struct snd_soc_component *componen
* Suspend/Resume
*/
+#ifdef CONFIG_PM
void da7219_aad_suspend(struct snd_soc_component *component)
{
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
@@ -981,7 +982,7 @@ void da7219_aad_resume(struct snd_soc_component *component)
enable_irq(da7219_aad->irq);
}
-
+#endif
/*
* Init/Exit
diff --git a/sound/soc/codecs/da7219-aad.h b/sound/soc/codecs/da7219-aad.h
index fbfbf3e67918..ea5b81819247 100644
--- a/sound/soc/codecs/da7219-aad.h
+++ b/sound/soc/codecs/da7219-aad.h
@@ -209,8 +209,13 @@ struct da7219_aad_priv {
void da7219_aad_jack_det(struct snd_soc_component *component, struct snd_soc_jack *jack);
/* Suspend/Resume */
+#ifdef CONFIG_PM
void da7219_aad_suspend(struct snd_soc_component *component);
void da7219_aad_resume(struct snd_soc_component *component);
+#else
+static inline void da7219_aad_suspend(struct snd_soc_component *component) { }
+static inline void da7219_aad_resume(struct snd_soc_component *component) { }
+#endif
/* Init/Exit */
int da7219_aad_init(struct snd_soc_component *component);
diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c
index 39cebaa167be..8a7d26a08c03 100644
--- a/sound/soc/codecs/jz4725b.c
+++ b/sound/soc/codecs/jz4725b.c
@@ -160,7 +160,6 @@ enum {
struct jz_icdc {
struct regmap *regmap;
void __iomem *base;
- struct clk *clk;
};
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_adc_tlv, 0, 150, 0);
@@ -405,8 +404,6 @@ static int jz4725b_codec_dev_probe(struct snd_soc_component *component)
struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
struct regmap *map = icdc->regmap;
- clk_prepare_enable(icdc->clk);
-
/* Write CONFIGn (n=1 to 8) bits.
* The value 0x0f is specified in the datasheet as a requirement.
*/
@@ -418,16 +415,8 @@ static int jz4725b_codec_dev_probe(struct snd_soc_component *component)
return 0;
}
-static void jz4725b_codec_dev_remove(struct snd_soc_component *component)
-{
- struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
-
- clk_disable_unprepare(icdc->clk);
-}
-
static const struct snd_soc_component_driver jz4725b_codec = {
.probe = jz4725b_codec_dev_probe,
- .remove = jz4725b_codec_dev_remove,
.set_bias_level = jz4725b_codec_set_bias_level,
.controls = jz4725b_codec_controls,
.num_controls = ARRAY_SIZE(jz4725b_codec_controls),
@@ -618,6 +607,7 @@ static int jz4725b_codec_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct jz_icdc *icdc;
+ struct clk *clk;
int ret;
icdc = devm_kzalloc(dev, sizeof(*icdc), GFP_KERNEL);
@@ -633,9 +623,9 @@ static int jz4725b_codec_probe(struct platform_device *pdev)
if (IS_ERR(icdc->regmap))
return PTR_ERR(icdc->regmap);
- icdc->clk = devm_clk_get(&pdev->dev, "aic");
- if (IS_ERR(icdc->clk))
- return PTR_ERR(icdc->clk);
+ clk = devm_clk_get_enabled(dev, "aic");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
platform_set_drvdata(pdev, icdc);
diff --git a/sound/soc/codecs/jz4760.c b/sound/soc/codecs/jz4760.c
index 344c251be397..6846ace06415 100644
--- a/sound/soc/codecs/jz4760.c
+++ b/sound/soc/codecs/jz4760.c
@@ -163,7 +163,6 @@ struct jz_codec {
struct device *dev;
struct regmap *regmap;
void __iomem *base;
- struct clk *clk;
};
static int jz4760_codec_set_bias_level(struct snd_soc_component *codec,
@@ -602,25 +601,13 @@ static void jz4760_codec_codec_init_regs(struct snd_soc_component *codec)
static int jz4760_codec_codec_probe(struct snd_soc_component *codec)
{
- struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
-
- clk_prepare_enable(jz_codec->clk);
-
jz4760_codec_codec_init_regs(codec);
return 0;
}
-static void jz4760_codec_codec_remove(struct snd_soc_component *codec)
-{
- struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
-
- clk_disable_unprepare(jz_codec->clk);
-}
-
static const struct snd_soc_component_driver jz4760_codec_soc_codec_dev = {
.probe = jz4760_codec_codec_probe,
- .remove = jz4760_codec_codec_remove,
.set_bias_level = jz4760_codec_set_bias_level,
.controls = jz4760_codec_snd_controls,
.num_controls = ARRAY_SIZE(jz4760_codec_snd_controls),
@@ -818,6 +805,7 @@ static int jz4760_codec_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct jz_codec *codec;
+ struct clk *clk;
int ret;
codec = devm_kzalloc(dev, sizeof(*codec), GFP_KERNEL);
@@ -835,9 +823,9 @@ static int jz4760_codec_probe(struct platform_device *pdev)
if (IS_ERR(codec->regmap))
return PTR_ERR(codec->regmap);
- codec->clk = devm_clk_get(dev, "aic");
- if (IS_ERR(codec->clk))
- return PTR_ERR(codec->clk);
+ clk = devm_clk_get_enabled(dev, "aic");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
platform_set_drvdata(pdev, codec);
diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c
index 6b86d47028d7..be1ecdcc737b 100644
--- a/sound/soc/codecs/jz4770.c
+++ b/sound/soc/codecs/jz4770.c
@@ -179,7 +179,6 @@ struct jz_codec {
struct device *dev;
struct regmap *regmap;
void __iomem *base;
- struct clk *clk;
};
static int jz4770_codec_set_bias_level(struct snd_soc_component *codec,
@@ -634,25 +633,13 @@ static void jz4770_codec_codec_init_regs(struct snd_soc_component *codec)
static int jz4770_codec_codec_probe(struct snd_soc_component *codec)
{
- struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
-
- clk_prepare_enable(jz_codec->clk);
-
jz4770_codec_codec_init_regs(codec);
return 0;
}
-static void jz4770_codec_codec_remove(struct snd_soc_component *codec)
-{
- struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
-
- clk_disable_unprepare(jz_codec->clk);
-}
-
static const struct snd_soc_component_driver jz4770_codec_soc_codec_dev = {
.probe = jz4770_codec_codec_probe,
- .remove = jz4770_codec_codec_remove,
.set_bias_level = jz4770_codec_set_bias_level,
.controls = jz4770_codec_snd_controls,
.num_controls = ARRAY_SIZE(jz4770_codec_snd_controls),
@@ -865,6 +852,7 @@ static int jz4770_codec_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct jz_codec *codec;
+ struct clk *clk;
int ret;
codec = devm_kzalloc(dev, sizeof(*codec), GFP_KERNEL);
@@ -882,9 +870,9 @@ static int jz4770_codec_probe(struct platform_device *pdev)
if (IS_ERR(codec->regmap))
return PTR_ERR(codec->regmap);
- codec->clk = devm_clk_get(dev, "aic");
- if (IS_ERR(codec->clk))
- return PTR_ERR(codec->clk);
+ clk = devm_clk_get_enabled(dev, "aic");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
platform_set_drvdata(pdev, codec);
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
index ff58805e97d1..65f095c47191 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -1015,10 +1015,8 @@ static int max98390_i2c_probe(struct i2c_client *i2c)
struct i2c_adapter *adapter = i2c->adapter;
struct gpio_desc *reset_gpio;
- ret = i2c_check_functionality(adapter,
- I2C_FUNC_SMBUS_BYTE
- | I2C_FUNC_SMBUS_BYTE_DATA);
- if (!ret) {
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&i2c->dev, "I2C check functionality failed\n");
return -ENXIO;
}
diff --git a/sound/soc/codecs/max98520.c b/sound/soc/codecs/max98520.c
index 2bf8976c1828..5bc3d95ade5a 100644
--- a/sound/soc/codecs/max98520.c
+++ b/sound/soc/codecs/max98520.c
@@ -681,8 +681,8 @@ static int max98520_i2c_probe(struct i2c_client *i2c)
struct max98520_priv *max98520;
struct i2c_adapter *adapter = to_i2c_adapter(i2c->dev.parent);
- ret = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA);
- if (!ret) {
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&i2c->dev, "I2C check functionality failed\n");
return -ENXIO;
}
diff --git a/sound/soc/codecs/nau8315.c b/sound/soc/codecs/nau8315.c
index 125742601f88..9ac2048ff0b0 100644
--- a/sound/soc/codecs/nau8315.c
+++ b/sound/soc/codecs/nau8315.c
@@ -11,7 +11,6 @@
#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/sound/soc/codecs/peb2466.c b/sound/soc/codecs/peb2466.c
index f1ee42af264b..2d5163c15d0d 100644
--- a/sound/soc/codecs/peb2466.c
+++ b/sound/soc/codecs/peb2466.c
@@ -517,18 +517,21 @@ static const struct snd_kcontrol_new peb2466_ch3_out_mix_controls[] = {
SOC_DAPM_SINGLE("Voice Switch", PEB2466_CR2(3), 0, 1, 0)
};
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(peb2466_gain_p_tlv, -600, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(peb2466_gain_c_tlv, 0, 600);
+
static const struct snd_kcontrol_new peb2466_controls[] = {
/* Attenuators */
- SOC_SINGLE("DAC0 -6dB Playback Switch", PEB2466_CR3(0), 2, 1, 0),
- SOC_SINGLE("DAC1 -6dB Playback Switch", PEB2466_CR3(1), 2, 1, 0),
- SOC_SINGLE("DAC2 -6dB Playback Switch", PEB2466_CR3(2), 2, 1, 0),
- SOC_SINGLE("DAC3 -6dB Playback Switch", PEB2466_CR3(3), 2, 1, 0),
+ SOC_SINGLE_TLV("DAC0 -6dB Playback Volume", PEB2466_CR3(0), 2, 1, 1, peb2466_gain_p_tlv),
+ SOC_SINGLE_TLV("DAC1 -6dB Playback Volume", PEB2466_CR3(1), 2, 1, 1, peb2466_gain_p_tlv),
+ SOC_SINGLE_TLV("DAC2 -6dB Playback Volume", PEB2466_CR3(2), 2, 1, 1, peb2466_gain_p_tlv),
+ SOC_SINGLE_TLV("DAC3 -6dB Playback Volume", PEB2466_CR3(3), 2, 1, 1, peb2466_gain_p_tlv),
/* Amplifiers */
- SOC_SINGLE("ADC0 +6dB Capture Switch", PEB2466_CR3(0), 3, 1, 0),
- SOC_SINGLE("ADC1 +6dB Capture Switch", PEB2466_CR3(1), 3, 1, 0),
- SOC_SINGLE("ADC2 +6dB Capture Switch", PEB2466_CR3(2), 3, 1, 0),
- SOC_SINGLE("ADC3 +6dB Capture Switch", PEB2466_CR3(3), 3, 1, 0),
+ SOC_SINGLE_TLV("ADC0 +6dB Capture Volume", PEB2466_CR3(0), 3, 1, 0, peb2466_gain_c_tlv),
+ SOC_SINGLE_TLV("ADC1 +6dB Capture Volume", PEB2466_CR3(1), 3, 1, 0, peb2466_gain_c_tlv),
+ SOC_SINGLE_TLV("ADC2 +6dB Capture Volume", PEB2466_CR3(2), 3, 1, 0, peb2466_gain_c_tlv),
+ SOC_SINGLE_TLV("ADC3 +6dB Capture Volume", PEB2466_CR3(3), 3, 1, 0, peb2466_gain_c_tlv),
/* Tone generators */
SOC_ENUM_EXT("DAC0 TG1 Freq", peb2466_tg_freq[0][0],
diff --git a/sound/soc/codecs/rt1318.c b/sound/soc/codecs/rt1318.c
index 01c58b15fd91..a80643099644 100644
--- a/sound/soc/codecs/rt1318.c
+++ b/sound/soc/codecs/rt1318.c
@@ -18,7 +18,6 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
-#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index 8bb7e8497c72..b0aeeab26bd9 100644
--- a/sound/soc/codecs/rt1320-sdw.c
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -1013,13 +1013,34 @@ static void rt1320_set_advancemode(struct rt1320_sdw_priv *rt1320)
struct device *dev = &rt1320->sdw_slave->dev;
struct rt1320_datafixpoint r0_data[2];
unsigned short l_advancegain, r_advancegain;
+ FwPara_Get_HwSwGain audDriverDataHwSwGain = {0};
+ unsigned int HwAdvGain = 0;
int ret;
+ /* Get new hardware advance gain by ID 1300 */
+ ret = rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 1300,
+ &audDriverDataHwSwGain, sizeof(audDriverDataHwSwGain));
+ if (ret == 0) {
+ HwAdvGain = audDriverDataHwSwGain.HwAdvGain;
+ dev_dbg(dev, "%s, HwAdvGain=%d\n", __func__, HwAdvGain);
+ dev_dbg(dev, "%s, HwBasGain=%d\n", __func__, audDriverDataHwSwGain.HwBasGain);
+ dev_dbg(dev, "%s, SwAdvGain=%d\n", __func__, audDriverDataHwSwGain.SwAdvGain);
+ dev_dbg(dev, "%s, SwBasGain=%d\n", __func__, audDriverDataHwSwGain.SwBasGain);
+ } else {
+ dev_dbg(dev, "%s: param 1300 not supported, ret=%d\n", __func__, ret);
+ }
+
/* Get advance gain/r0 */
rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 6, &r0_data[0], sizeof(struct rt1320_datafixpoint));
rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 7, &r0_data[1], sizeof(struct rt1320_datafixpoint));
- l_advancegain = r0_data[0].advancegain;
- r_advancegain = r0_data[1].advancegain;
+
+ if (HwAdvGain != 0) {
+ l_advancegain = HwAdvGain & 0xffff;
+ r_advancegain = (HwAdvGain >> 16) & 0xffff;
+ } else {
+ l_advancegain = r0_data[0].advancegain;
+ r_advancegain = r0_data[1].advancegain;
+ }
dev_dbg(dev, "%s, LR advanceGain=0x%x 0x%x\n", __func__, l_advancegain, r_advancegain);
/* set R0 and enable protection by SetParameter id 6, 7 */
@@ -2486,6 +2507,45 @@ static int rt1320_rae_update_put(struct snd_kcontrol *kcontrol,
return 0;
}
+static int rt1320_brown_out_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ int ret, changed = 0;
+
+ if (!rt1320->hw_init)
+ return 0;
+
+ ret = pm_runtime_resume(component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ if (rt1320->brown_out != ucontrol->value.integer.value[0]) {
+ changed = 1;
+ rt1320->brown_out = ucontrol->value.integer.value[0];
+ }
+
+ if (rt1320->brown_out == 0)
+ regmap_write(rt1320->regmap, 0xdb03, 0x00);
+ else
+ regmap_write(rt1320->regmap, 0xdb03, 0xf0);
+
+
+ return changed;
+}
+
+static int rt1320_brown_out_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = rt1320->brown_out;
+
+ return 0;
+}
+
static int rt1320_r0_temperature_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -2545,6 +2605,8 @@ static const struct snd_kcontrol_new rt1320_snd_controls[] = {
rt1320_r0_temperature_get, rt1320_r0_temperature_put),
SOC_SINGLE_EXT("RAE Update", SND_SOC_NOPM, 0, 1, 0,
rt1320_rae_update_get, rt1320_rae_update_put),
+ SOC_SINGLE_EXT("Brown Out Switch", SND_SOC_NOPM, 0, 1, 0,
+ rt1320_brown_out_get, rt1320_brown_out_put),
};
static const struct snd_kcontrol_new rt1320_spk_l_dac =
@@ -2904,6 +2966,7 @@ static int rt1320_sdw_init(struct device *dev, struct regmap *regmap,
rt1320->fu_dapm_mute = true;
rt1320->fu_mixer_mute[0] = rt1320->fu_mixer_mute[1] =
rt1320->fu_mixer_mute[2] = rt1320->fu_mixer_mute[3] = true;
+ rt1320->brown_out = 1;
INIT_WORK(&rt1320->load_dspfw_work, rt1320_load_dspfw_work);
diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h
index 5a9f496dd848..a7b573883dd0 100644
--- a/sound/soc/codecs/rt1320-sdw.h
+++ b/sound/soc/codecs/rt1320-sdw.h
@@ -121,6 +121,19 @@ struct rt1320_datafixpoint {
int invrs;
};
+typedef struct FwPara_HwSwGain {
+ unsigned int SwAdvGain;
+ unsigned int SwBasGain;
+ unsigned int HwAdvGain;
+ unsigned int HwBasGain;
+ unsigned int reserve0;
+ unsigned int reserve1;
+ unsigned int reserve2;
+ unsigned int reserve3;
+ unsigned int reserve4;
+ unsigned int reserve5;
+} __attribute__((packed)) FwPara_Get_HwSwGain;
+
struct rt1320_paramcmd {
unsigned char moudleid;
unsigned char commandtype;
@@ -159,6 +172,7 @@ struct rt1320_sdw_priv {
bool hw_init;
bool first_hw_init;
int version_id;
+ int brown_out;
unsigned int dev_id;
bool fu_dapm_mute;
bool fu_mixer_mute[4];
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 54d84581ec47..199507d12841 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -303,7 +303,7 @@ static const struct snd_soc_component_driver rt5514_spi_component = {
.hw_params = rt5514_spi_hw_params,
.hw_free = rt5514_spi_hw_free,
.pointer = rt5514_spi_pcm_pointer,
- .pcm_construct = rt5514_spi_pcm_new,
+ .pcm_new = rt5514_spi_pcm_new,
.legacy_dai_naming = 1,
};
diff --git a/sound/soc/codecs/rt5575.c b/sound/soc/codecs/rt5575.c
index c5525ad195ee..24e41af29689 100644
--- a/sound/soc/codecs/rt5575.c
+++ b/sound/soc/codecs/rt5575.c
@@ -339,7 +339,6 @@ MODULE_DEVICE_TABLE(of, rt5575_of_match);
static struct i2c_driver rt5575_i2c_driver = {
.driver = {
.name = "rt5575",
- .owner = THIS_MODULE,
.of_match_table = rt5575_of_match,
},
.probe = rt5575_i2c_probe,
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index db2222e6f2e7..f6c6294e1588 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -1838,6 +1838,11 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
unsigned int pll_bit = 0;
int ret;
+ if (!freq) {
+ rt5640->sysclk = 0;
+ return 0;
+ }
+
switch (clk_id) {
case RT5640_SCLK_S_MCLK:
ret = clk_set_rate(rt5640->mclk, freq);
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
index 885edcf0a3a5..1bcafd5f4468 100644
--- a/sound/soc/codecs/rt5677-spi.c
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -404,7 +404,7 @@ static const struct snd_soc_component_driver rt5677_spi_dai_component = {
.hw_free = rt5677_spi_hw_free,
.prepare = rt5677_spi_prepare,
.pointer = rt5677_spi_pcm_pointer,
- .pcm_construct = rt5677_spi_pcm_new,
+ .pcm_new = rt5677_spi_pcm_new,
.legacy_dai_naming = 1,
};
@@ -624,12 +624,19 @@ static const struct acpi_device_id rt5677_spi_acpi_id[] = {
MODULE_DEVICE_TABLE(acpi, rt5677_spi_acpi_id);
#endif
+static const struct spi_device_id rt5677_spi_ids[] = {
+ { "rt5677", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, rt5677_spi_ids);
+
static struct spi_driver rt5677_spi_driver = {
.driver = {
.name = DRV_NAME,
.acpi_match_table = ACPI_PTR(rt5677_spi_acpi_id),
},
.probe = rt5677_spi_probe,
+ .id_table = rt5677_spi_ids,
};
module_spi_driver(rt5677_spi_driver);
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index d46385249867..60a93c3fe2e7 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -5204,10 +5204,17 @@ MODULE_DEVICE_TABLE(of, rt5677_of_match);
static const struct acpi_device_id rt5677_acpi_match[] = {
{ "10EC5677", RT5677 },
{ "RT5677CE", RT5677 },
+ { "10EC5677", RT5677 },
{ }
};
MODULE_DEVICE_TABLE(acpi, rt5677_acpi_match);
+static const struct i2c_device_id rt5677_i2c_id[] = {
+ { "rt5677", RT5677 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
+
static void rt5677_read_device_properties(struct rt5677_priv *rt5677,
struct device *dev)
{
@@ -5529,9 +5536,17 @@ static int rt5677_init_irq(struct i2c_client *i2c)
return ret;
}
+static const struct acpi_gpio_params rt5677_acpi_reset_gpios = {0, 0, true};
+static const struct acpi_gpio_params rt5677_acpi_ldo2_gpios = {1, 0, false};
+
+static const struct acpi_gpio_mapping rt5677_acpi_gpios[] = {
+ { "realtek,reset-gpios", &rt5677_acpi_reset_gpios, 1 },
+ { "realtek,pow-ldo2-gpios", &rt5677_acpi_ldo2_gpios, 1 },
+ {},
+};
+
static int rt5677_i2c_probe(struct i2c_client *i2c)
{
- struct device *dev = &i2c->dev;
struct rt5677_priv *rt5677;
int ret;
unsigned int val;
@@ -5546,10 +5561,13 @@ static int rt5677_i2c_probe(struct i2c_client *i2c)
INIT_DELAYED_WORK(&rt5677->dsp_work, rt5677_dsp_work);
i2c_set_clientdata(i2c, rt5677);
- rt5677->type = (enum rt5677_type)(uintptr_t)device_get_match_data(dev);
+ rt5677->type = (enum rt5677_type)(uintptr_t)i2c_get_match_data(i2c);
if (rt5677->type == 0)
return -EINVAL;
+ if (devm_acpi_dev_add_driver_gpios(rt5677->dev, rt5677_acpi_gpios))
+ dev_warn(rt5677->dev, "Unable to add GPIO mapping table\n");
+
rt5677_read_device_properties(rt5677, &i2c->dev);
/* pow-ldo2 and reset are optional. The codec pins may be statically
@@ -5563,14 +5581,21 @@ static int rt5677_i2c_probe(struct i2c_client *i2c)
dev_err(&i2c->dev, "Failed to request POW_LDO2: %d\n", ret);
return ret;
}
+
rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev,
- "realtek,reset", GPIOD_OUT_LOW);
+ "realtek,reset", GPIOD_OUT_HIGH);
+
if (IS_ERR(rt5677->reset_pin)) {
ret = PTR_ERR(rt5677->reset_pin);
dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret);
return ret;
}
+ if (rt5677->reset_pin) {
+ msleep(1);
+ gpiod_set_value_cansleep(rt5677->reset_pin, 0);
+ }
+
if (rt5677->pow_ldo2 || rt5677->reset_pin) {
/* Wait a while until I2C bus becomes available. The datasheet
* does not specify the exact we should wait but startup
@@ -5596,7 +5621,13 @@ static int rt5677_i2c_probe(struct i2c_client *i2c)
return ret;
}
- regmap_read(rt5677->regmap, RT5677_VENDOR_ID2, &val);
+ ret = regmap_read(rt5677->regmap, RT5677_VENDOR_ID2, &val);
+ if (ret) {
+ dev_err(&i2c->dev,
+ "Failed to read ID register: %d\n", ret);
+ return -ENODEV;
+ }
+
if (val != RT5677_DEVICE_ID) {
dev_err(&i2c->dev,
"Device with ID register %#x is not rt5677\n", val);
@@ -5665,6 +5696,7 @@ static struct i2c_driver rt5677_i2c_driver = {
.of_match_table = rt5677_of_match,
.acpi_match_table = rt5677_acpi_match,
},
+ .id_table = rt5677_i2c_id,
.probe = rt5677_i2c_probe,
.remove = rt5677_i2c_remove,
};
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h
index d67ebae067d9..876f7674015c 100644
--- a/sound/soc/codecs/rt5677.h
+++ b/sound/soc/codecs/rt5677.h
@@ -421,7 +421,7 @@
#define RT5677_DAC3_R_VOL_MASK (0xff)
#define RT5677_DAC3_R_VOL_SFT 0
-/* DAC3 Digital Volume (0x19) */
+/* DAC1 Digital Volume (0x19) */
#define RT5677_DAC1_L_VOL_MASK (0xff << 8)
#define RT5677_DAC1_L_VOL_SFT 8
#define RT5677_DAC1_R_VOL_MASK (0xff)
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index 8c3b2652b02e..946aa6a4e57c 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ASoC codec driver for spear platform
*
@@ -5,10 +6,6 @@
*
* Copyright (C) 2012 ST Microelectronics
* Rajeev Kumar <rajeevkumar.linux@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
*/
#include <linux/clk.h>
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index 43449d7c2584..80206c2e0946 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -487,7 +487,7 @@ static int tas2552_runtime_suspend(struct device *dev)
regcache_cache_only(tas2552->regmap, true);
regcache_mark_dirty(tas2552->regmap);
- gpiod_set_value(tas2552->enable_gpio, 0);
+ gpiod_set_value_cansleep(tas2552->enable_gpio, 0);
return 0;
}
@@ -496,7 +496,7 @@ static int tas2552_runtime_resume(struct device *dev)
{
struct tas2552_data *tas2552 = dev_get_drvdata(dev);
- gpiod_set_value(tas2552->enable_gpio, 1);
+ gpiod_set_value_cansleep(tas2552->enable_gpio, 1);
tas2552_sw_shutdown(tas2552, 0);
@@ -583,7 +583,7 @@ static int tas2552_component_probe(struct snd_soc_component *component)
return ret;
}
- gpiod_set_value(tas2552->enable_gpio, 1);
+ gpiod_set_value_cansleep(tas2552->enable_gpio, 1);
ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0) {
@@ -608,7 +608,7 @@ static int tas2552_component_probe(struct snd_soc_component *component)
probe_fail:
pm_runtime_put_noidle(component->dev);
- gpiod_set_value(tas2552->enable_gpio, 0);
+ gpiod_set_value_cansleep(tas2552->enable_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies),
tas2552->supplies);
@@ -621,7 +621,7 @@ static void tas2552_component_remove(struct snd_soc_component *component)
pm_runtime_put(component->dev);
- gpiod_set_value(tas2552->enable_gpio, 0);
+ gpiod_set_value_cansleep(tas2552->enable_gpio, 0);
};
#ifdef CONFIG_PM
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 36e25e48b354..423b7073b302 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -44,6 +44,11 @@ struct tas2764_priv {
bool dac_powered;
bool unmuted;
+
+ struct {
+ int tx_mode;
+ unsigned int tx_mask;
+ } idle_slot_config;
};
#include "tas2764-quirks.h"
@@ -509,11 +514,101 @@ static int tas2764_set_dai_tdm_slot(struct snd_soc_dai *dai,
return 0;
}
+static int tas2764_write_sdout_idle_mask(struct tas2764_priv *tas2764, u32 mask)
+{
+ struct snd_soc_component *component = tas2764->component;
+ int i, ret;
+
+ /* Hardware supports up to 64 slots, but we don't */
+ for (i = 0; i < 4; i++) {
+ ret = snd_soc_component_write(component,
+ TAS2764_SDOUT_HIZ_1 + i,
+ (mask >> (i * 8)) & 0xff);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tas2764_set_dai_tdm_idle(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int tx_mode, int rx_mode)
+{
+ struct snd_soc_component *component = dai->component;
+ struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ /* We don't support setting anything on SDIN */
+ if (rx_mode)
+ return -EOPNOTSUPP;
+
+ if (tas2764->idle_slot_config.tx_mask == tx_mask &&
+ tas2764->idle_slot_config.tx_mode == tx_mode)
+ return 0;
+
+ switch (tx_mode) {
+ case SND_SOC_DAI_TDM_IDLE_ZERO:
+ if (!tx_mask)
+ return -EINVAL;
+
+ ret = tas2764_write_sdout_idle_mask(tas2764, tx_mask);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_component_update_bits(component,
+ TAS2764_SDOUT_HIZ_9,
+ TAS2764_SDOUT_HIZ_9_FORCE_0_EN,
+ TAS2764_SDOUT_HIZ_9_FORCE_0_EN);
+ if (ret < 0)
+ return ret;
+
+ tas2764->idle_slot_config.tx_mask = tx_mask;
+ tas2764->idle_slot_config.tx_mode = tx_mode;
+ break;
+ case SND_SOC_DAI_TDM_IDLE_HIZ:
+ case SND_SOC_DAI_TDM_IDLE_OFF:
+ /* HiZ mode does not support a slot mask */
+ ret = tas2764_write_sdout_idle_mask(tas2764, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_component_update_bits(component,
+ TAS2764_SDOUT_HIZ_9,
+ TAS2764_SDOUT_HIZ_9_FORCE_0_EN, 0);
+ if (ret < 0)
+ return ret;
+
+ tas2764->idle_slot_config.tx_mask = 0;
+ tas2764->idle_slot_config.tx_mode = tx_mode;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+/* The SDOUT idle slot mask must be cropped based on the BCLK ratio */
+static int tas2764_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+ struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(dai->component);
+
+ if (!tas2764->idle_slot_config.tx_mask)
+ return 0;
+
+ tas2764->idle_slot_config.tx_mask &= GENMASK((ratio / 8) - 1, 0);
+
+ return tas2764_write_sdout_idle_mask(tas2764, tas2764->idle_slot_config.tx_mask);
+}
+
static const struct snd_soc_dai_ops tas2764_dai_ops = {
.mute_stream = tas2764_mute,
.hw_params = tas2764_hw_params,
.set_fmt = tas2764_set_fmt,
+ .set_bclk_ratio = tas2764_set_bclk_ratio,
.set_tdm_slot = tas2764_set_dai_tdm_slot,
+ .set_tdm_idle = tas2764_set_dai_tdm_idle,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/tas2764.h b/sound/soc/codecs/tas2764.h
index 538290ed3d92..4494bc4889dc 100644
--- a/sound/soc/codecs/tas2764.h
+++ b/sound/soc/codecs/tas2764.h
@@ -126,4 +126,15 @@
#define TAS2764_BOP_CFG0 TAS2764_REG(0X0, 0x1d)
+#define TAS2764_SDOUT_HIZ_1 TAS2764_REG(0x1, 0x3d)
+#define TAS2764_SDOUT_HIZ_2 TAS2764_REG(0x1, 0x3e)
+#define TAS2764_SDOUT_HIZ_3 TAS2764_REG(0x1, 0x3f)
+#define TAS2764_SDOUT_HIZ_4 TAS2764_REG(0x1, 0x40)
+#define TAS2764_SDOUT_HIZ_5 TAS2764_REG(0x1, 0x41)
+#define TAS2764_SDOUT_HIZ_6 TAS2764_REG(0x1, 0x42)
+#define TAS2764_SDOUT_HIZ_7 TAS2764_REG(0x1, 0x43)
+#define TAS2764_SDOUT_HIZ_8 TAS2764_REG(0x1, 0x44)
+#define TAS2764_SDOUT_HIZ_9 TAS2764_REG(0x1, 0x45)
+#define TAS2764_SDOUT_HIZ_9_FORCE_0_EN BIT(7)
+
#endif /* __TAS2764__ */
diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index 6f878b01716f..d4d7d056141b 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -492,11 +492,86 @@ static int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai,
return 0;
}
+static int tas2770_set_dai_tdm_idle(struct snd_soc_dai *dai,
+ unsigned int tx_mask,
+ unsigned int rx_mask,
+ int tx_mode, int rx_mode)
+{
+ struct snd_soc_component *component = dai->component;
+ struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ /* We don't support setting anything for SDIN */
+ if (rx_mode)
+ return -EOPNOTSUPP;
+
+ if (tas2770->idle_tx_mode == tx_mode)
+ return 0;
+
+ switch (tx_mode) {
+ case SND_SOC_DAI_TDM_IDLE_PULLDOWN:
+ ret = snd_soc_component_update_bits(component, TAS2770_DIN_PD,
+ TAS2770_DIN_PD_SDOUT,
+ TAS2770_DIN_PD_SDOUT);
+ if (ret)
+ return ret;
+
+ break;
+ case SND_SOC_DAI_TDM_IDLE_ZERO:
+ ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+ TAS2770_TDM_CFG_REG4_TX_KEEPER,
+ TAS2770_TDM_CFG_REG4_TX_KEEPER);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+ TAS2770_TDM_CFG_REG4_TX_FILL, 0);
+ if (ret)
+ return ret;
+
+ break;
+ case SND_SOC_DAI_TDM_IDLE_HIZ:
+ ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+ TAS2770_TDM_CFG_REG4_TX_KEEPER,
+ TAS2770_TDM_CFG_REG4_TX_KEEPER);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+ TAS2770_TDM_CFG_REG4_TX_FILL,
+ TAS2770_TDM_CFG_REG4_TX_FILL);
+ if (ret)
+ return ret;
+
+ break;
+ case SND_SOC_DAI_TDM_IDLE_OFF:
+ ret = snd_soc_component_update_bits(component, TAS2770_DIN_PD,
+ TAS2770_DIN_PD_SDOUT, 0);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
+ TAS2770_TDM_CFG_REG4_TX_KEEPER, 0);
+ if (ret)
+ return ret;
+
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ tas2770->idle_tx_mode = tx_mode;
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops tas2770_dai_ops = {
.mute_stream = tas2770_mute,
.hw_params = tas2770_hw_params,
.set_fmt = tas2770_set_fmt,
.set_tdm_slot = tas2770_set_dai_tdm_slot,
+ .set_tdm_idle = tas2770_set_dai_tdm_idle,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/tas2770.h b/sound/soc/codecs/tas2770.h
index 3fd2e7003c50..102040b6bdf8 100644
--- a/sound/soc/codecs/tas2770.h
+++ b/sound/soc/codecs/tas2770.h
@@ -67,6 +67,14 @@
#define TAS2770_TDM_CFG_REG3_RXS_SHIFT 0x4
#define TAS2770_TDM_CFG_REG3_30_MASK GENMASK(3, 0)
#define TAS2770_TDM_CFG_REG3_30_SHIFT 0
+ /* TDM Configuration Reg4 */
+#define TAS2770_TDM_CFG_REG4 TAS2770_REG(0X0, 0x0E)
+#define TAS2770_TDM_CFG_REG4_TX_LSB_CFG BIT(7)
+#define TAS2770_TDM_CFG_REG4_TX_KEEPER_CFG BIT(6)
+#define TAS2770_TDM_CFG_REG4_TX_KEEPER BIT(5)
+#define TAS2770_TDM_CFG_REG4_TX_FILL BIT(4)
+#define TAS2770_TDM_CFG_REG4_TX_OFFSET_MASK GENMASK(3, 1)
+#define TAS2770_TDM_CFG_REG4_TX_EDGE_FALLING BIT(0)
/* TDM Configuration Reg5 */
#define TAS2770_TDM_CFG_REG5 TAS2770_REG(0X0, 0x0F)
#define TAS2770_TDM_CFG_REG5_VSNS_MASK BIT(6)
@@ -115,6 +123,9 @@
#define TAS2770_TEMP_LSB TAS2770_REG(0X0, 0x2A)
/* Interrupt Configuration */
#define TAS2770_INT_CFG TAS2770_REG(0X0, 0x30)
+ /* Data In Pull-Down */
+#define TAS2770_DIN_PD TAS2770_REG(0X0, 0x31)
+#define TAS2770_DIN_PD_SDOUT BIT(7)
/* Misc IRQ */
#define TAS2770_MISC_IRQ TAS2770_REG(0X0, 0x32)
/* Clock Configuration */
@@ -146,6 +157,7 @@ struct tas2770_priv {
int pdm_slot;
bool dac_powered;
bool unmuted;
+ int idle_tx_mode;
};
#endif /* __TAS2770__ */
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 41b89fcc69c3..c593f9da0c5b 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -121,29 +121,28 @@ static const struct i2c_device_id tasdevice_id[] = {
{ "tas5830", TAS5830 },
{}
};
-MODULE_DEVICE_TABLE(i2c, tasdevice_id);
#ifdef CONFIG_OF
static const struct of_device_id tasdevice_of_match[] = {
- { .compatible = "ti,tas2020" },
- { .compatible = "ti,tas2118" },
- { .compatible = "ti,tas2120" },
- { .compatible = "ti,tas2320" },
- { .compatible = "ti,tas2563" },
- { .compatible = "ti,tas2568" },
- { .compatible = "ti,tas2570" },
- { .compatible = "ti,tas2572" },
- { .compatible = "ti,tas2574" },
- { .compatible = "ti,tas2781" },
- { .compatible = "ti,tas5802" },
- { .compatible = "ti,tas5806m" },
- { .compatible = "ti,tas5806md" },
- { .compatible = "ti,tas5815" },
- { .compatible = "ti,tas5822" },
- { .compatible = "ti,tas5825" },
- { .compatible = "ti,tas5827" },
- { .compatible = "ti,tas5828" },
- { .compatible = "ti,tas5830" },
+ { .compatible = "ti,tas2020", .data = &tasdevice_id[TAS2020] },
+ { .compatible = "ti,tas2118", .data = &tasdevice_id[TAS2118] },
+ { .compatible = "ti,tas2120", .data = &tasdevice_id[TAS2120] },
+ { .compatible = "ti,tas2320", .data = &tasdevice_id[TAS2320] },
+ { .compatible = "ti,tas2563", .data = &tasdevice_id[TAS2563] },
+ { .compatible = "ti,tas2568", .data = &tasdevice_id[TAS2568] },
+ { .compatible = "ti,tas2570", .data = &tasdevice_id[TAS2570] },
+ { .compatible = "ti,tas2572", .data = &tasdevice_id[TAS2572] },
+ { .compatible = "ti,tas2574", .data = &tasdevice_id[TAS2574] },
+ { .compatible = "ti,tas2781", .data = &tasdevice_id[TAS2781] },
+ { .compatible = "ti,tas5802", .data = &tasdevice_id[TAS5802] },
+ { .compatible = "ti,tas5806m", .data = &tasdevice_id[TAS5806M] },
+ { .compatible = "ti,tas5806md", .data = &tasdevice_id[TAS5806MD] },
+ { .compatible = "ti,tas5815", .data = &tasdevice_id[TAS5815] },
+ { .compatible = "ti,tas5822", .data = &tasdevice_id[TAS5822] },
+ { .compatible = "ti,tas5825", .data = &tasdevice_id[TAS5825] },
+ { .compatible = "ti,tas5827", .data = &tasdevice_id[TAS5827] },
+ { .compatible = "ti,tas5828", .data = &tasdevice_id[TAS5828] },
+ { .compatible = "ti,tas5830", .data = &tasdevice_id[TAS5830] },
{},
};
MODULE_DEVICE_TABLE(of, tasdevice_of_match);
@@ -2023,15 +2022,12 @@ static void tasdevice_parse_dt(struct tasdevice_priv *tas_priv)
if (IS_ERR(tas_priv->reset))
dev_err(tas_priv->dev, "%s Can't get reset GPIO\n",
__func__);
-
- strscpy(tas_priv->dev_name, tasdevice_id[tas_priv->chip_id].name,
- sizeof(tas_priv->dev_name));
}
static int tasdevice_i2c_probe(struct i2c_client *i2c)
{
- const struct acpi_device_id *acpi_id;
struct tasdevice_priv *tas_priv;
+ struct i2c_device_id *id_data;
int ret;
tas_priv = tasdevice_kzalloc(i2c);
@@ -2041,20 +2037,23 @@ static int tasdevice_i2c_probe(struct i2c_client *i2c)
dev_set_drvdata(&i2c->dev, tas_priv);
if (ACPI_HANDLE(&i2c->dev)) {
- acpi_id = acpi_match_device(i2c->dev.driver->acpi_match_table,
- &i2c->dev);
- if (!acpi_id) {
- dev_err(&i2c->dev, "No driver data\n");
- ret = -EINVAL;
- goto err;
- }
- tas_priv->chip_id = acpi_id->driver_data;
+ id_data = (struct i2c_device_id *)
+ acpi_device_get_match_data(&i2c->dev);
tas_priv->isacpi = true;
} else {
- tas_priv->chip_id = (uintptr_t)i2c_get_match_data(i2c);
+ id_data = (struct i2c_device_id *)i2c_get_match_data(i2c);
tas_priv->isacpi = false;
}
+ if (!id_data) {
+ dev_err(&i2c->dev, "No driver data\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ tas_priv->chip_id = (uintptr_t)id_data->driver_data;
+ strscpy(tas_priv->dev_name, id_data->name, sizeof(tas_priv->dev_name));
+
tasdevice_parse_dt(tas_priv);
ret = tasdevice_init(tas_priv);
@@ -2086,25 +2085,25 @@ static void tasdevice_i2c_remove(struct i2c_client *client)
#ifdef CONFIG_ACPI
static const struct acpi_device_id tasdevice_acpi_match[] = {
- { "TXNW2020", TAS2020 },
- { "TXNW2118", TAS2118 },
- { "TXNW2120", TAS2120 },
- { "TXNW2320", TAS2320 },
- { "TXNW2563", TAS2563 },
- { "TXNW2568", TAS2568 },
- { "TXNW2570", TAS2570 },
- { "TXNW2572", TAS2572 },
- { "TXNW2574", TAS2574 },
- { "TXNW2781", TAS2781 },
- { "TXNW5802", TAS5802 },
- { "TXNW806M", TAS5806M },
- { "TXNW806D", TAS5806MD },
- { "TXNW5815", TAS5815 },
- { "TXNW5822", TAS5822 },
- { "TXNW5825", TAS5825 },
- { "TXNW5827", TAS5827 },
- { "TXNW5828", TAS5828 },
- { "TXNW5830", TAS5830 },
+ { "TXNW2020", (kernel_ulong_t)&tasdevice_id[TAS2020] },
+ { "TXNW2118", (kernel_ulong_t)&tasdevice_id[TAS2118] },
+ { "TXNW2120", (kernel_ulong_t)&tasdevice_id[TAS2120] },
+ { "TXNW2320", (kernel_ulong_t)&tasdevice_id[TAS2320] },
+ { "TXNW2563", (kernel_ulong_t)&tasdevice_id[TAS2563] },
+ { "TXNW2568", (kernel_ulong_t)&tasdevice_id[TAS2568] },
+ { "TXNW2570", (kernel_ulong_t)&tasdevice_id[TAS2570] },
+ { "TXNW2572", (kernel_ulong_t)&tasdevice_id[TAS2572] },
+ { "TXNW2574", (kernel_ulong_t)&tasdevice_id[TAS2574] },
+ { "TXNW2781", (kernel_ulong_t)&tasdevice_id[TAS2781] },
+ { "TXNW5802", (kernel_ulong_t)&tasdevice_id[TAS5802] },
+ { "TXNW806M", (kernel_ulong_t)&tasdevice_id[TAS5806M] },
+ { "TXNW806D", (kernel_ulong_t)&tasdevice_id[TAS5806MD] },
+ { "TXNW5815", (kernel_ulong_t)&tasdevice_id[TAS5815] },
+ { "TXNW5822", (kernel_ulong_t)&tasdevice_id[TAS5822] },
+ { "TXNW5825", (kernel_ulong_t)&tasdevice_id[TAS5825] },
+ { "TXNW5827", (kernel_ulong_t)&tasdevice_id[TAS5827] },
+ { "TXNW5828", (kernel_ulong_t)&tasdevice_id[TAS5828] },
+ { "TXNW5830", (kernel_ulong_t)&tasdevice_id[TAS5830] },
{},
};
@@ -2121,7 +2120,6 @@ static struct i2c_driver tasdevice_i2c_driver = {
},
.probe = tasdevice_i2c_probe,
.remove = tasdevice_i2c_remove,
- .id_table = tasdevice_id,
};
module_i2c_driver(tasdevice_i2c_driver);
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 605da1259fc6..223c49dfc450 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -91,7 +91,6 @@ struct tlv320dac33_priv {
int mode1_latency; /* latency caused by the i2c writes in
* us */
u8 burst_bclkdiv; /* BCLK divider value in burst mode */
- u8 *reg_cache;
unsigned int burst_rate; /* Interface speed in Burst modes */
int keep_bclk; /* Keep the BCLK continuously running
@@ -108,6 +107,8 @@ struct tlv320dac33_priv {
enum dac33_state state;
struct i2c_client *i2c;
+
+ u8 reg_cache[];
};
static const u8 dac33_reg[DAC33_CACHEREGNUM] = {
@@ -1477,15 +1478,12 @@ static int dac33_i2c_probe(struct i2c_client *client)
struct tlv320dac33_priv *dac33;
int ret, i;
- dac33 = devm_kzalloc(&client->dev, sizeof(struct tlv320dac33_priv),
+ dac33 = devm_kzalloc(&client->dev, struct_size(dac33, reg_cache, ARRAY_SIZE(dac33_reg)),
GFP_KERNEL);
if (dac33 == NULL)
return -ENOMEM;
- dac33->reg_cache = devm_kmemdup_array(&client->dev, dac33_reg, ARRAY_SIZE(dac33_reg),
- sizeof(dac33_reg[0]), GFP_KERNEL);
- if (!dac33->reg_cache)
- return -ENOMEM;
+ memcpy(dac33->reg_cache, dac33_reg, ARRAY_SIZE(dac33_reg));
dac33->i2c = client;
mutex_init(&dac33->mutex);
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
index 5ce0db9326fd..5a7beeadb009 100644
--- a/sound/soc/codecs/ts3a227e.c
+++ b/sound/soc/codecs/ts3a227e.c
@@ -5,7 +5,6 @@
* Copyright (C) 2014 Google, Inc.
*/
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/input.h>
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 9e9c540a45ca..55c83d95bfba 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -16,16 +16,19 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/errno.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/i2c.h>
+#include <linux/property.h>
#include <linux/workqueue.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/tlv.h>
-#include <sound/uda1380.h>
+
+#define UDA1380_DAC_CLK_SYSCLK 0
+#define UDA1380_DAC_CLK_WSPLL 1
#include "uda1380.h"
@@ -36,6 +39,8 @@ struct uda1380_priv {
struct work_struct work;
struct i2c_client *i2c;
u16 *reg_cache;
+ struct gpio_desc *power;
+ struct gpio_desc *reset;
};
/*
@@ -95,6 +100,8 @@ static int uda1380_write(struct snd_soc_component *component, unsigned int reg,
{
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
u8 data[3];
+ unsigned int val;
+ int ret;
/* data is
* data[0] is register offset
@@ -113,21 +120,38 @@ static int uda1380_write(struct snd_soc_component *component, unsigned int reg,
if (!snd_soc_component_active(component) && (reg >= UDA1380_MVOL))
return 0;
pr_debug("uda1380: hw write %x val %x\n", reg, value);
- if (i2c_master_send(uda1380->i2c, data, 3) == 3) {
- unsigned int val;
- i2c_master_send(uda1380->i2c, data, 1);
- i2c_master_recv(uda1380->i2c, data, 2);
- val = (data[0]<<8) | data[1];
- if (val != value) {
- pr_debug("uda1380: READ BACK VAL %x\n",
- (data[0]<<8) | data[1]);
- return -EIO;
- }
- if (reg >= 0x10)
- clear_bit(reg - 0x10, &uda1380_cache_dirty);
- return 0;
- } else
+
+ ret = i2c_master_send(uda1380->i2c, data, 3);
+ if (ret != 3) {
+ int err = ret < 0 ? ret : -EIO;
+ dev_err(component->dev, "write failed: %pe\n", ERR_PTR(err));
+ return err;
+ }
+
+ ret = i2c_master_send(uda1380->i2c, data, 1);
+ if (ret != 1) {
+ int err = ret < 0 ? ret : -EIO;
+ dev_err(component->dev, "send address failed: %pe\n", ERR_PTR(err));
+ return err;
+}
+
+ ret = i2c_master_recv(uda1380->i2c, data, 2);
+ if (ret != 2) {
+ int err = ret < 0 ? ret : -EIO;
+ dev_err(component->dev, "read failed: %pe\n", ERR_PTR(err));
+ return err;
+ }
+
+ val = (data[0] << 8) | data[1];
+ if (val != value) {
+ dev_err(component->dev, "read back val %x (expected %x)\n", val, value);
return -EIO;
+ }
+
+ if (reg >= 0x10)
+ clear_bit(reg - 0x10, &uda1380_cache_dirty);
+
+ return 0;
}
static void uda1380_sync_cache(struct snd_soc_component *component)
@@ -150,13 +174,12 @@ static void uda1380_sync_cache(struct snd_soc_component *component)
static int uda1380_reset(struct snd_soc_component *component)
{
- struct uda1380_platform_data *pdata = component->dev->platform_data;
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
- if (gpio_is_valid(pdata->gpio_reset)) {
- gpio_set_value(pdata->gpio_reset, 1);
+ if (uda1380->reset) {
+ gpiod_set_value(uda1380->reset, 1);
mdelay(1);
- gpio_set_value(pdata->gpio_reset, 0);
+ gpiod_set_value(uda1380->reset, 0);
} else {
u8 data[3];
@@ -589,9 +612,9 @@ static int uda1380_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
int pm = uda1380_read_reg_cache(component, UDA1380_PM);
int reg;
- struct uda1380_platform_data *pdata = component->dev->platform_data;
switch (level) {
case SND_SOC_BIAS_ON:
@@ -601,8 +624,8 @@ static int uda1380_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_OFF) {
- if (gpio_is_valid(pdata->gpio_power)) {
- gpio_set_value(pdata->gpio_power, 1);
+ if (uda1380->power) {
+ gpiod_set_value(uda1380->power, 1);
mdelay(1);
uda1380_reset(component);
}
@@ -612,10 +635,10 @@ static int uda1380_set_bias_level(struct snd_soc_component *component,
uda1380_write(component, UDA1380_PM, 0x0);
break;
case SND_SOC_BIAS_OFF:
- if (!gpio_is_valid(pdata->gpio_power))
+ if (!uda1380->power)
break;
- gpio_set_value(pdata->gpio_power, 0);
+ gpiod_set_value(uda1380->power, 0);
/* Mark mixer regs cache dirty to sync them with
* codec regs on power on.
@@ -694,13 +717,12 @@ static struct snd_soc_dai_driver uda1380_dai[] = {
static int uda1380_probe(struct snd_soc_component *component)
{
- struct uda1380_platform_data *pdata =component->dev->platform_data;
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
int ret;
uda1380->component = component;
- if (!gpio_is_valid(pdata->gpio_power)) {
+ if (!uda1380->power) {
ret = uda1380_reset(component);
if (ret)
return ret;
@@ -709,7 +731,7 @@ static int uda1380_probe(struct snd_soc_component *component)
INIT_WORK(&uda1380->work, uda1380_flush_work);
/* set clock input */
- switch (pdata->dac_clk) {
+ switch (uda1380->dac_clk) {
case UDA1380_DAC_CLK_SYSCLK:
uda1380_write_reg_cache(component, UDA1380_CLK, 0);
break;
@@ -741,31 +763,31 @@ static const struct snd_soc_component_driver soc_component_dev_uda1380 = {
static int uda1380_i2c_probe(struct i2c_client *i2c)
{
- struct uda1380_platform_data *pdata = i2c->dev.platform_data;
+ struct device *dev = &i2c->dev;
struct uda1380_priv *uda1380;
int ret;
- if (!pdata)
- return -EINVAL;
-
uda1380 = devm_kzalloc(&i2c->dev, sizeof(struct uda1380_priv),
GFP_KERNEL);
if (uda1380 == NULL)
return -ENOMEM;
- if (gpio_is_valid(pdata->gpio_reset)) {
- ret = devm_gpio_request_one(&i2c->dev, pdata->gpio_reset,
- GPIOF_OUT_INIT_LOW, "uda1380 reset");
- if (ret)
- return ret;
- }
-
- if (gpio_is_valid(pdata->gpio_power)) {
- ret = devm_gpio_request_one(&i2c->dev, pdata->gpio_power,
- GPIOF_OUT_INIT_LOW, "uda1380 power");
- if (ret)
- return ret;
- }
+ uda1380->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(uda1380->reset))
+ return dev_err_probe(dev, PTR_ERR(uda1380->reset),
+ "error obtaining reset GPIO\n");
+ gpiod_set_consumer_name(uda1380->reset, "uda1380 reset");
+
+ uda1380->power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
+ if (IS_ERR(uda1380->power))
+ return dev_err_probe(dev, PTR_ERR(uda1380->power),
+ "error obtaining power GPIO\n");
+ gpiod_set_consumer_name(uda1380->power, "uda1380 power");
+
+ /* This is just some default */
+ uda1380->dac_clk = UDA1380_DAC_CLK_SYSCLK;
+ if (device_property_match_string(dev, "dac-clk", "wspll") >= 0)
+ uda1380->dac_clk = UDA1380_DAC_CLK_WSPLL;
uda1380->reg_cache = devm_kmemdup_array(&i2c->dev, uda1380_reg, ARRAY_SIZE(uda1380_reg),
sizeof(uda1380_reg[0]), GFP_KERNEL);
diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c
index 13d07296916f..62ca22ea0f3b 100644
--- a/sound/soc/codecs/wcd-clsh-v2.c
+++ b/sound/soc/codecs/wcd-clsh-v2.c
@@ -848,9 +848,6 @@ int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl,
{
struct snd_soc_component *comp = ctrl->comp;
- if (nstate == ctrl->state)
- return 0;
-
if (!wcd_clsh_is_state_valid(nstate)) {
dev_err(comp->dev, "Class-H not a valid new state:\n");
return -EINVAL;
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 640e43ee1975..e3ca5ca6de3d 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -3907,7 +3907,7 @@ static irqreturn_t wcd9335_slimbus_irq(int irq, void *data)
{
struct wcd9335_codec *wcd = data;
unsigned long status = 0;
- int i, j, port_id;
+ unsigned int i, j, port_id;
unsigned int val, int_val = 0;
irqreturn_t ret = IRQ_NONE;
bool tx;
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 2e23848e1dce..a637e22c3929 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -7,6 +7,8 @@
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*/
+#include <kunit/static_stub.h>
+#include <kunit/visibility.h>
#include <linux/array_size.h>
#include <linux/cleanup.h>
#include <linux/ctype.h>
@@ -72,7 +74,7 @@ static const struct cs_dsp_client_ops wm_adsp2_client_ops;
#define WM_ADSP_NUM_FW 13
-static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
+static const char * const wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
[WM_ADSP_FW_MBC_VSS] = "MBC/VSS",
[WM_ADSP_FW_HIFI] = "MasterHiFi",
[WM_ADSP_FW_TX] = "Tx",
@@ -316,6 +318,17 @@ struct wm_coeff_ctl {
struct work_struct work;
};
+#if IS_ENABLED(CONFIG_KUNIT)
+const char *wm_adsp_get_fwf_name_by_index(int index)
+{
+ if (index < ARRAY_SIZE(wm_adsp_fw))
+ return wm_adsp_fw[index].file;
+
+ return NULL;
+}
+EXPORT_SYMBOL_IF_KUNIT(wm_adsp_get_fwf_name_by_index);
+#endif
+
int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -704,21 +717,30 @@ int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
}
EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
-static void wm_adsp_release_firmware_files(struct wm_adsp *dsp,
- const struct firmware *wmfw_firmware,
- char *wmfw_filename,
- const struct firmware *coeff_firmware,
- char *coeff_filename)
+VISIBLE_IF_KUNIT void wm_adsp_release_firmware_files(struct wm_adsp_fw_files *fw)
+{
+ KUNIT_STATIC_STUB_REDIRECT(wm_adsp_release_firmware_files, fw);
+
+ release_firmware(fw->wmfw.firmware);
+ kfree(fw->wmfw.filename);
+
+ release_firmware(fw->coeff.firmware);
+ kfree(fw->coeff.filename);
+}
+EXPORT_SYMBOL_IF_KUNIT(wm_adsp_release_firmware_files);
+
+VISIBLE_IF_KUNIT int wm_adsp_firmware_request(const struct firmware **firmware,
+ const char *filename,
+ struct device *dev)
{
- release_firmware(wmfw_firmware);
- kfree(wmfw_filename);
+ KUNIT_STATIC_STUB_REDIRECT(wm_adsp_firmware_request, firmware, filename, dev);
- release_firmware(coeff_firmware);
- kfree(coeff_filename);
+ return firmware_request_nowarn(firmware, filename, dev);
}
+EXPORT_SYMBOL_IF_KUNIT(wm_adsp_firmware_request);
static int wm_adsp_request_firmware_file(struct wm_adsp *dsp,
- const struct firmware **firmware, char **filename,
+ struct wm_adsp_fw_file *fw,
const char *dir, const char *system_name,
const char *asoc_component_prefix,
const char *filetype)
@@ -726,7 +748,7 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp,
struct cs_dsp *cs_dsp = &dsp->cs_dsp;
const char *fwf;
char *s, c;
- int ret = 0;
+ int ret;
if (dsp->fwf_name)
fwf = dsp->fwf_name;
@@ -734,119 +756,128 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp,
fwf = dsp->cs_dsp.name;
if (system_name && asoc_component_prefix)
- *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, dsp->part,
- fwf, wm_adsp_fw[dsp->fw].file, system_name,
- asoc_component_prefix, filetype);
+ fw->filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, dsp->part,
+ fwf, wm_adsp_fw[dsp->fw].file, system_name,
+ asoc_component_prefix, filetype);
else if (system_name)
- *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, dsp->part,
- fwf, wm_adsp_fw[dsp->fw].file, system_name,
- filetype);
+ fw->filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, dsp->part,
+ fwf, wm_adsp_fw[dsp->fw].file, system_name,
+ filetype);
else
- *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, dsp->part, fwf,
- wm_adsp_fw[dsp->fw].file, filetype);
+ fw->filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, dsp->part, fwf,
+ wm_adsp_fw[dsp->fw].file, filetype);
- if (*filename == NULL)
+ if (!fw->filename)
return -ENOMEM;
/*
- * Make sure that filename is lower-case and any non alpha-numeric
- * characters except full stop and forward slash are replaced with
- * hyphens.
+ * Make sure that filename after dir is lower-case and any non-alpha-numeric
+ * characters except full-stop are replaced with hyphens.
*/
- s = *filename;
+ s = fw->filename + strlen(dir);
while (*s) {
c = *s;
if (isalnum(c))
*s = tolower(c);
- else if ((c != '.') && (c != '/'))
+ else if (c != '.')
*s = '-';
s++;
}
- ret = firmware_request_nowarn(firmware, *filename, cs_dsp->dev);
- if (ret != 0) {
- adsp_dbg(dsp, "Failed to request '%s'\n", *filename);
- kfree(*filename);
- *filename = NULL;
+ ret = wm_adsp_firmware_request(&fw->firmware, fw->filename, cs_dsp->dev);
+ if (ret < 0) {
+ adsp_dbg(dsp, "Failed to request '%s': %d\n", fw->filename, ret);
+ kfree(fw->filename);
+ fw->filename = NULL;
+ if (ret != -ENOENT)
+ return ret;
} else {
- adsp_dbg(dsp, "Found '%s'\n", *filename);
+ adsp_dbg(dsp, "Found '%s'\n", fw->filename);
}
- return ret;
+ return 0;
}
static const char * const cirrus_dir = "cirrus/";
-static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
- const struct firmware **wmfw_firmware,
- char **wmfw_filename,
- const struct firmware **coeff_firmware,
- char **coeff_filename)
+VISIBLE_IF_KUNIT int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
+ struct wm_adsp_fw_files *fw)
{
const char *system_name = dsp->system_name;
const char *suffix = dsp->component->name_prefix;
+ bool require_bin_suffix = false;
int ret = 0;
if (dsp->fwf_suffix)
suffix = dsp->fwf_suffix;
- if (system_name && suffix) {
- if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
- cirrus_dir, system_name,
- suffix, "wmfw")) {
- wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
- cirrus_dir, system_name,
- suffix, "bin");
- return 0;
- }
- }
-
if (system_name) {
- if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
- cirrus_dir, system_name,
- NULL, "wmfw")) {
- if (suffix)
- wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
- cirrus_dir, system_name,
- suffix, "bin");
-
- if (!*coeff_firmware)
- wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
- cirrus_dir, system_name,
- NULL, "bin");
- return 0;
- }
- }
+ ret = wm_adsp_request_firmware_file(dsp, &fw->wmfw,
+ cirrus_dir, system_name,
+ suffix, "wmfw");
+ if (ret < 0)
+ goto err;
- /* Check system-specific bin without wmfw before falling back to generic */
- if (dsp->wmfw_optional && system_name) {
- if (suffix)
- wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
- cirrus_dir, system_name,
- suffix, "bin");
+ if (suffix) {
+ if (fw->wmfw.firmware) {
+ require_bin_suffix = true;
+ } else {
+ /* Fallback to name without suffix */
+ ret = wm_adsp_request_firmware_file(dsp, &fw->wmfw,
+ cirrus_dir, system_name,
+ NULL, "wmfw");
+ if (ret < 0)
+ goto err;
+ }
+ }
- if (!*coeff_firmware)
- wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
- cirrus_dir, system_name,
- NULL, "bin");
+ /* Look for matching .bin file */
+ if (fw->wmfw.firmware || dsp->wmfw_optional) {
+ ret = wm_adsp_request_firmware_file(dsp, &fw->coeff,
+ cirrus_dir, system_name,
+ suffix, "bin");
+ if (ret < 0)
+ goto err;
+
+ if (suffix && !fw->coeff.firmware && !require_bin_suffix) {
+ /* Fallback to name without suffix */
+ ret = wm_adsp_request_firmware_file(dsp,
+ &fw->coeff,
+ cirrus_dir, system_name,
+ NULL, "bin");
+ if (ret < 0)
+ goto err;
+ }
+ }
- if (*coeff_firmware)
+ if (fw->wmfw.firmware || (dsp->wmfw_optional && fw->coeff.firmware))
return 0;
}
/* Check legacy location */
- if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
- "", NULL, NULL, "wmfw")) {
- wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
- "", NULL, NULL, "bin");
+ ret = wm_adsp_request_firmware_file(dsp, &fw->wmfw, "", NULL, NULL, "wmfw");
+ if (ret < 0)
+ goto err;
+
+ if (fw->wmfw.firmware) {
+ ret = wm_adsp_request_firmware_file(dsp, &fw->coeff, "", NULL, NULL, "bin");
+ if (ret < 0)
+ goto err;
+
return 0;
}
/* Fall back to generic wmfw and optional matching bin */
- ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
+ ret = wm_adsp_request_firmware_file(dsp, &fw->wmfw,
cirrus_dir, NULL, NULL, "wmfw");
- if (!ret || dsp->wmfw_optional) {
- wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
- cirrus_dir, NULL, NULL, "bin");
+ if (ret < 0)
+ goto err;
+
+ if (fw->wmfw.firmware || dsp->wmfw_optional) {
+ ret = wm_adsp_request_firmware_file(dsp, &fw->coeff,
+ cirrus_dir, NULL, NULL, "bin");
+ if (ret < 0)
+ goto err;
+
return 0;
}
@@ -855,8 +886,13 @@ static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
dsp->fwf_name ? dsp->fwf_name : dsp->cs_dsp.name,
wm_adsp_fw[dsp->fw].file, system_name, suffix);
- return -ENOENT;
+ ret = -ENOENT;
+err:
+ wm_adsp_release_firmware_files(fw);
+
+ return ret;
}
+EXPORT_SYMBOL_IF_KUNIT(wm_adsp_request_firmware_files);
static int wm_adsp_common_init(struct wm_adsp *dsp)
{
@@ -887,30 +923,23 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
struct wm_adsp *dsp = &dsps[w->shift];
+ struct wm_adsp_fw_files fw = { 0 };
int ret = 0;
- char *wmfw_filename = NULL;
- const struct firmware *wmfw_firmware = NULL;
- char *coeff_filename = NULL;
- const struct firmware *coeff_firmware = NULL;
dsp->component = component;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- ret = wm_adsp_request_firmware_files(dsp,
- &wmfw_firmware, &wmfw_filename,
- &coeff_firmware, &coeff_filename);
+ ret = wm_adsp_request_firmware_files(dsp, &fw);
if (ret)
break;
ret = cs_dsp_adsp1_power_up(&dsp->cs_dsp,
- wmfw_firmware, wmfw_filename,
- coeff_firmware, coeff_filename,
+ fw.wmfw.firmware, fw.wmfw.filename,
+ fw.coeff.firmware, fw.coeff.filename,
wm_adsp_fw_text[dsp->fw]);
- wm_adsp_release_firmware_files(dsp,
- wmfw_firmware, wmfw_filename,
- coeff_firmware, coeff_filename);
+ wm_adsp_release_firmware_files(&fw);
break;
case SND_SOC_DAPM_PRE_PMD:
cs_dsp_adsp1_power_down(&dsp->cs_dsp);
@@ -986,34 +1015,27 @@ EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware)
{
+ struct wm_adsp_fw_files fw = { 0 };
int ret = 0;
- char *wmfw_filename = NULL;
- const struct firmware *wmfw_firmware = NULL;
- char *coeff_filename = NULL;
- const struct firmware *coeff_firmware = NULL;
if (load_firmware) {
- ret = wm_adsp_request_firmware_files(dsp,
- &wmfw_firmware, &wmfw_filename,
- &coeff_firmware, &coeff_filename);
+ ret = wm_adsp_request_firmware_files(dsp, &fw);
if (ret)
return ret;
}
- if (dsp->bin_mandatory && !coeff_firmware) {
+ if (dsp->bin_mandatory && !fw.coeff.firmware) {
ret = -ENOENT;
goto err;
}
ret = cs_dsp_power_up(&dsp->cs_dsp,
- wmfw_firmware, wmfw_filename,
- coeff_firmware, coeff_filename,
+ fw.wmfw.firmware, fw.wmfw.filename,
+ fw.coeff.firmware, fw.coeff.filename,
wm_adsp_fw_text[dsp->fw]);
err:
- wm_adsp_release_firmware_files(dsp,
- wmfw_firmware, wmfw_filename,
- coeff_firmware, coeff_filename);
+ wm_adsp_release_firmware_files(&fw);
return ret;
}
@@ -1100,6 +1122,12 @@ void wm_adsp_stop(struct wm_adsp *dsp)
}
EXPORT_SYMBOL_GPL(wm_adsp_stop);
+void wm_adsp_hibernate(struct wm_adsp *dsp, bool hibernate)
+{
+ cs_dsp_hibernate(&dsp->cs_dsp, hibernate);
+}
+EXPORT_SYMBOL_GPL(wm_adsp_hibernate);
+
int wm_adsp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 8035fda71f8d..8922732479c2 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -79,6 +79,16 @@ struct wm_adsp {
SOC_ENUM_EXT(dspname " Firmware", wm_adsp_fw_enum[num], \
wm_adsp_fw_get, wm_adsp_fw_put)
+struct wm_adsp_fw_file {
+ const struct firmware *firmware;
+ char *filename;
+};
+
+struct wm_adsp_fw_files {
+ struct wm_adsp_fw_file wmfw;
+ struct wm_adsp_fw_file coeff;
+};
+
extern const struct soc_enum wm_adsp_fw_enum[];
int wm_adsp1_init(struct wm_adsp *dsp);
@@ -103,6 +113,7 @@ irqreturn_t wm_halo_wdt_expire(int irq, void *data);
int wm_adsp_run(struct wm_adsp *dsp);
void wm_adsp_stop(struct wm_adsp *dsp);
+void wm_adsp_hibernate(struct wm_adsp *dsp, bool hibernate);
int wm_adsp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
@@ -142,4 +153,13 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
unsigned int alg, void *buf, size_t len);
+#if IS_ENABLED(CONFIG_KUNIT)
+const char *wm_adsp_get_fwf_name_by_index(int index);
+void wm_adsp_release_firmware_files(struct wm_adsp_fw_files *fw);
+int wm_adsp_firmware_request(const struct firmware **firmware,
+ const char *filename,
+ struct device *dev);
+int wm_adsp_request_firmware_files(struct wm_adsp *dsp, struct wm_adsp_fw_files *fw);
+#endif
+
#endif
diff --git a/sound/soc/codecs/wm_adsp_fw_find_test.c b/sound/soc/codecs/wm_adsp_fw_find_test.c
new file mode 100644
index 000000000000..d0c7fb30a95d
--- /dev/null
+++ b/sound/soc/codecs/wm_adsp_fw_find_test.c
@@ -0,0 +1,1223 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Test cases for wm_adsp library.
+//
+// Copyright (C) 2025 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <kunit/device.h>
+#include <kunit/static_stub.h>
+#include <kunit/test.h>
+#include <linux/slab.h>
+#include "wm_adsp.h"
+
+KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *);
+
+struct wm_adsp_fw_find_test {
+ struct wm_adsp dsp;
+
+ struct wm_adsp_fw_files found_fw;
+ char searched_fw_files[768];
+};
+
+struct wm_adsp_fw_find_test_params {
+ const char *part;
+ const char *dsp_name;
+ const char *fwf_name;
+ const char *system_name;
+ const char *alsa_name;
+ bool wmfw_optional;
+ bool bin_mandatory;
+
+ /* If non-NULL this file should be returned as "found" */
+ const char *expect_wmfw;
+
+ /* If non-NULL this file should be returned as "found" */
+ const char *expect_bin;
+
+ /* Space-separated list of filenames in expected order of searching */
+ const char *expected_searches;
+
+ /* NULL-terminated array of pointers to filenames to simulate directory content */
+ const char * const *dir_files;
+};
+
+/* Dummy struct firmware to return from wm_adsp_request_firmware_files */
+static const struct firmware wm_adsp_find_test_dummy_firmware;
+
+/* Simple lookup of a filename in a list of names */
+static int wm_adsp_fw_find_test_firmware_request_simple_stub(const struct firmware **firmware,
+ const char *filename,
+ struct device *dev)
+{
+ struct kunit *test = kunit_get_current_test();
+ const struct wm_adsp_fw_find_test_params *params = test->param_value;
+ int i;
+
+ /* Non-parameterized test? */
+ if (!params)
+ return -ENOENT;
+
+ if (!params->dir_files)
+ return -ENOENT;
+
+ for (i = 0; params->dir_files[i]; i++) {
+ if (strcmp(params->dir_files[i], filename) == 0) {
+ *firmware = &wm_adsp_find_test_dummy_firmware;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+static void wm_adsp_fw_find_test_pick_file(struct kunit *test)
+{
+ struct wm_adsp_fw_find_test *priv = test->priv;
+ const struct wm_adsp_fw_find_test_params *params = test->param_value;
+ struct wm_adsp *dsp = &priv->dsp;
+ int i, ret;
+
+ /* Concatenate string of dir content for error messages */
+ for (i = 0; params->dir_files[i]; i++) {
+ strlcat(priv->searched_fw_files, params->dir_files[i],
+ sizeof(priv->searched_fw_files));
+ strlcat(priv->searched_fw_files, ";",
+ sizeof(priv->searched_fw_files));
+ }
+
+ dsp->cs_dsp.name = params->dsp_name;
+ dsp->part = params->part;
+ dsp->fwf_name = params->fwf_name;
+ dsp->system_name = params->system_name;
+ dsp->component->name_prefix = params->alsa_name;
+ dsp->wmfw_optional = params->wmfw_optional;
+ dsp->bin_mandatory = params->bin_mandatory;
+
+ kunit_activate_static_stub(test,
+ wm_adsp_firmware_request,
+ wm_adsp_fw_find_test_firmware_request_simple_stub);
+
+ ret = wm_adsp_request_firmware_files(dsp, &priv->found_fw);
+ kunit_deactivate_static_stub(test, wm_adsp_firmware_request);
+ KUNIT_EXPECT_EQ_MSG(test, ret,
+ (params->expect_wmfw || params->expect_bin) ? 0 : -ENOENT,
+ "%s\n", priv->searched_fw_files);
+
+ KUNIT_EXPECT_EQ_MSG(test, !!priv->found_fw.wmfw.filename, !!params->expect_wmfw,
+ "%s\n", priv->searched_fw_files);
+ KUNIT_EXPECT_EQ_MSG(test, !!priv->found_fw.coeff.filename, !!params->expect_bin,
+ "%s\n", priv->searched_fw_files);
+
+ if (params->expect_wmfw) {
+ KUNIT_EXPECT_STREQ_MSG(test, priv->found_fw.wmfw.filename, params->expect_wmfw,
+ "%s\n", priv->searched_fw_files);
+ }
+
+ if (params->expect_bin) {
+ KUNIT_EXPECT_STREQ_MSG(test, priv->found_fw.coeff.filename, params->expect_bin,
+ "%s\n", priv->searched_fw_files);
+ }
+}
+
+static int wm_adsp_fw_find_test_firmware_request_stub(const struct firmware **firmware,
+ const char *filename,
+ struct device *dev)
+{
+ struct kunit *test = kunit_get_current_test();
+ const struct wm_adsp_fw_find_test_params *params = test->param_value;
+ struct wm_adsp_fw_find_test *priv = test->priv;
+
+ /*
+ * Searches are accumulated as a single string of space-separated names.
+ * The list of expected searches are stored the same way in
+ * struct wm_adsp_fw_find_test_params. This allows for comparision using
+ * a simple KUNIT_EXPECT_STREQ(), which avoids the risk of bugs in a
+ * more complex custom comparison.
+ */
+ if (priv->searched_fw_files[0] != '\0')
+ strlcat(priv->searched_fw_files, " ", sizeof(priv->searched_fw_files));
+
+ strlcat(priv->searched_fw_files, filename, sizeof(priv->searched_fw_files));
+
+ /* Non-parameterized test? */
+ if (!params)
+ return -ENOENT;
+
+ if (params->expect_wmfw && (strcmp(filename, params->expect_wmfw) == 0)) {
+ *firmware = &wm_adsp_find_test_dummy_firmware;
+ return 0;
+ }
+
+ if (params->expect_bin && (strcmp(filename, params->expect_bin) == 0)) {
+ *firmware = &wm_adsp_find_test_dummy_firmware;
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+static void wm_adsp_fw_find_test_search_order(struct kunit *test)
+{
+ struct wm_adsp_fw_find_test *priv = test->priv;
+ const struct wm_adsp_fw_find_test_params *params = test->param_value;
+ struct wm_adsp *dsp = &priv->dsp;
+
+ dsp->cs_dsp.name = params->dsp_name;
+ dsp->part = params->part;
+ dsp->fwf_name = params->fwf_name;
+ dsp->system_name = params->system_name;
+ dsp->component->name_prefix = params->alsa_name;
+ dsp->wmfw_optional = params->wmfw_optional;
+
+ kunit_activate_static_stub(test,
+ wm_adsp_firmware_request,
+ wm_adsp_fw_find_test_firmware_request_stub);
+
+ wm_adsp_request_firmware_files(dsp, &priv->found_fw);
+
+ kunit_deactivate_static_stub(test, wm_adsp_firmware_request);
+
+ KUNIT_EXPECT_STREQ(test, priv->searched_fw_files, params->expected_searches);
+
+ KUNIT_EXPECT_EQ(test, !!priv->found_fw.wmfw.filename, !!params->expect_wmfw);
+ if (params->expect_wmfw)
+ KUNIT_EXPECT_STREQ(test, priv->found_fw.wmfw.filename, params->expect_wmfw);
+
+ KUNIT_EXPECT_EQ(test, !!priv->found_fw.coeff.filename, !!params->expect_bin);
+ if (params->expect_bin)
+ KUNIT_EXPECT_STREQ(test, priv->found_fw.coeff.filename, params->expect_bin);
+
+ /* Either we get a filename and firmware, or neither */
+ KUNIT_EXPECT_EQ(test, !!priv->found_fw.wmfw.filename, !!priv->found_fw.wmfw.firmware);
+ KUNIT_EXPECT_EQ(test, !!priv->found_fw.coeff.filename, !!priv->found_fw.coeff.firmware);
+}
+
+static void wm_adsp_fw_find_test_find_firmware_byindex(struct kunit *test)
+{
+ struct wm_adsp_fw_find_test *priv = test->priv;
+ struct wm_adsp *dsp = &priv->dsp;
+ const char *fw_name;
+
+ dsp->cs_dsp.name = "cs1234";
+ dsp->part = "dsp1";
+ for (dsp->fw = 0;; dsp->fw++) {
+ fw_name = wm_adsp_get_fwf_name_by_index(dsp->fw);
+ if (!fw_name)
+ break;
+
+ kunit_activate_static_stub(test,
+ wm_adsp_firmware_request,
+ wm_adsp_fw_find_test_firmware_request_stub);
+
+ wm_adsp_request_firmware_files(dsp, &priv->found_fw);
+ kunit_deactivate_static_stub(test, wm_adsp_firmware_request);
+
+ KUNIT_EXPECT_NOT_NULL_MSG(test,
+ strstr(priv->searched_fw_files, fw_name),
+ "fw#%d Did not find '%s' in '%s'\n",
+ dsp->fw, fw_name, priv->searched_fw_files);
+ }
+}
+
+static int wm_adsp_fw_find_test_case_init(struct kunit *test)
+{
+ struct wm_adsp_fw_find_test *priv;
+ struct device *test_dev;
+ int ret;
+
+ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ /* Require dummy struct snd_soc_component for the alsa name prefix string */
+ priv->dsp.component = kunit_kzalloc(test, sizeof(*priv->dsp.component), GFP_KERNEL);
+ if (!priv->dsp.component)
+ return -ENOMEM;
+
+ test->priv = priv;
+
+ /* Create dummy amp device */
+ test_dev = kunit_device_register(test, "wm_adsp_test_drv");
+ if (IS_ERR(test_dev))
+ return PTR_ERR(test_dev);
+
+ priv->dsp.cs_dsp.dev = get_device(test_dev);
+ if (!priv->dsp.cs_dsp.dev)
+ return -ENODEV;
+
+ ret = kunit_add_action_or_reset(test, _put_device_wrapper, priv->dsp.cs_dsp.dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void wm_adsp_fw_find_test_case_exit(struct kunit *test)
+{
+ struct wm_adsp_fw_find_test *priv = test->priv;
+
+ /*
+ * priv->found_wmfw_firmware and priv->found_bin_firmware are
+ * dummies not allocated by the real request_firmware() call they
+ * must not be passed to release_firmware().
+ */
+ kfree(priv->found_fw.wmfw.filename);
+ kfree(priv->found_fw.coeff.filename);
+}
+
+static void wm_adsp_fw_find_test_param_desc(const struct wm_adsp_fw_find_test_params *param,
+ char *desc)
+{
+ snprintf(desc, KUNIT_PARAM_DESC_SIZE,
+ "%s %s fwf_name:%s system:%s alsa_name:%s %s expects:(%s %s)",
+ param->part, param->dsp_name,
+ param->fwf_name ? param->fwf_name : "",
+ param->system_name ? param->system_name : "",
+ param->alsa_name ? param->alsa_name : "",
+ param->wmfw_optional ? "wmfw_optional" : "",
+ param->expect_wmfw ? param->expect_wmfw : "",
+ param->expect_bin ? param->expect_bin : "");
+}
+
+/* Cases where firmware file not found. Tests full search sequence. */
+static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_full_search_cases[] = {
+ { /* system name and alsa prefix, wmfw mandatory. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ },
+ { /* system name and alsa prefix, wmfw optional. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* system name only, wmfw mandatory. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ },
+ { /* system name only, wmfw optional. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .wmfw_optional = true,
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+
+ /*
+ * TODO: Is this a bug? Device-specific bin is only allowed when there
+ * is a system_name. But if there isn't any meaningful system name on
+ * a product, why can't it load firmware files qualified by alsa prefix?
+ */
+
+ { /* Alsa prefix, wmfw mandatory. No system name so generic files only. */
+ .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ },
+ { /* Alsa prefix, wmfw optional. No system name so generic files only. */
+ .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1",
+ .wmfw_optional = true,
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+
+ { /* fwf_name, system name and alsa prefix, wmfw mandatory. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .fwf_name = "ao",
+ .expected_searches =
+ "cirrus/cs1234-ao-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-ao-mbc-vss-abc123.wmfw "
+ "cs1234-ao-mbc-vss.wmfw "
+ "cirrus/cs1234-ao-mbc-vss.wmfw",
+ },
+ { /* fwf_name, system name and alsa prefix, wmfw optional. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .fwf_name = "ao",
+ .wmfw_optional = true,
+ .expected_searches =
+ "cirrus/cs1234-ao-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-ao-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-ao-mbc-vss-abc123-amp1.bin "
+ "cirrus/cs1234-ao-mbc-vss-abc123.bin "
+ "cs1234-ao-mbc-vss.wmfw "
+ "cirrus/cs1234-ao-mbc-vss.wmfw "
+ "cirrus/cs1234-ao-mbc-vss.bin",
+ },
+};
+KUNIT_ARRAY_PARAM(wm_adsp_fw_find_full_search,
+ wm_adsp_fw_find_full_search_cases,
+ wm_adsp_fw_find_test_param_desc);
+
+/* Cases with system name and alsa prefix both given. */
+static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_system_alsaname_cases[] = {
+ { /* Fully-qualified wmfw exists. No bin */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin",
+ },
+ { /* Optional fully-qualified wmfw exists. No bin */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin",
+ },
+ { /* Fully-qualified wmfw and bin exist. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin",
+ },
+ { /* Optional fully-qualified wmfw and fully-qualified bin exist. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin",
+ },
+ { /* wmfw matches system name only. No bin */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ },
+ { /* Optional wmfw matches system name only. No bin */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ },
+ { /* wmfw matches system name only. Fully-qualified bin. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin",
+ },
+ { /* Optional wmfw matches system name only. Fully-qualified bin. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin",
+ },
+ { /* wmfw and bin match system name only. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ },
+ { /* Optional wmfw and bin match system name only. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ },
+ { /* Optional wmfw not found. bin matches fully-qualified name. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin",
+ },
+ { /* Optional wmfw not found. bin matches system name only. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ },
+ { /* No qualified wmfw. Legacy generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1",
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No qualified optional wmfw. Legacy generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No qualified wmfw. Legacy generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1",
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No qualified optional wmfw. Legacy generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No qualified or legacy wmfw. Generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No optional qualified or legacy wmfw. Generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No qualified or legacy wmfw. Generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No optional qualified or legacy wmfw. Generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No optional qualified or generic wmfw. Generic bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123-amp1.bin "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+};
+KUNIT_ARRAY_PARAM(wm_adsp_fw_find_system_alsaname,
+ wm_adsp_fw_find_system_alsaname_cases,
+ wm_adsp_fw_find_test_param_desc);
+
+/* Cases with system name but without alsa name prefix. */
+static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_system_cases[] = {
+ { /* Qualified wmfw found. No bin */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ },
+ { /* Optional qualified wmfw found. No bin */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ },
+ { /* Qualified wmfw found. Qualified bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ },
+ { /* Optional qualified wmfw found. Qualified bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ },
+ { /* Optional wmfw not found. Qualified bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .wmfw_optional = true,
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin",
+ },
+ { /* No qualified wmfw. Legacy generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No qualified optional wmfw. Legacy generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .wmfw_optional = true,
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No qualified wmfw. Legacy generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No qualified optional wmfw. Legacy generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .wmfw_optional = true,
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No qualified or legacy wmfw. Generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No optional qualified or legacy wmfw. Generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No qualified or legacy wmfw. Generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No optional qualified or legacy wmfw. Generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No optional qualified or generic wmfw. Generic bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "ABC123",
+ .wmfw_optional = true,
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc123.bin "
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+};
+KUNIT_ARRAY_PARAM(wm_adsp_fw_find_system,
+ wm_adsp_fw_find_system_cases,
+ wm_adsp_fw_find_test_param_desc);
+
+/* Cases without system name but with alsa name prefix. */
+static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_alsaname_cases[] = {
+ { /* Legacy generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1",
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* wmfw optional. Legacy generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1",
+ .wmfw_optional = true,
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* Legacy generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1",
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* wmfw optional. Legacy generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1",
+ .wmfw_optional = true,
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No legacy wmfw. Generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No legacy wmfw. Optional generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1",
+ .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No legacy wmfw. Generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No legacy wmfw. Optional generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1",
+ .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No legacy or generic wmfw. Generic bin found. */
+ .part = "cs1234", .dsp_name = "dsp1", .alsa_name = "amp1",
+ .wmfw_optional = true,
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+};
+KUNIT_ARRAY_PARAM(wm_adsp_fw_find_alsaname,
+ wm_adsp_fw_find_alsaname_cases,
+ wm_adsp_fw_find_test_param_desc);
+
+/* Cases without system name or alsa name prefix. */
+static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_noqual_cases[] = {
+ { /* Legacy generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1",
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* wmfw optional. Legacy generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1",
+ .wmfw_optional = true,
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* Legacy generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1",
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* wmfw optional. Legacy generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1",
+ .wmfw_optional = true,
+ .expect_wmfw = "cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No legacy wmfw. Generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No legacy wmfw. Optional generic wmfw found. No bin. */
+ .part = "cs1234", .dsp_name = "dsp1",
+ .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No legacy wmfw. Generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No legacy wmfw. Optional generic wmfw and bin found. */
+ .part = "cs1234", .dsp_name = "dsp1",
+ .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+ { /* No legacy or generic wmfw. Generic bin found. */
+ .part = "cs1234", .dsp_name = "dsp1",
+ .wmfw_optional = true,
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin",
+ .expected_searches =
+ "cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ },
+};
+KUNIT_ARRAY_PARAM(wm_adsp_fw_find_noqual,
+ wm_adsp_fw_find_noqual_cases,
+ wm_adsp_fw_find_test_param_desc);
+
+/*
+ * Tests for filename normalization. The system name and alsa prefix strings
+ * should be converted to lower-case and delimiters are converted to '-', except
+ * for '.' which is preserved.
+ */
+static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_normalization_cases[] = {
+ {
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "Vendor",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-vendor.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-vendor.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-vendor.bin",
+ },
+ {
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "Vendor Device",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-vendor-device.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-vendor-device.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-vendor-device.bin",
+ },
+ {
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "Vendor_Device",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-vendor-device.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-vendor-device.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-vendor-device.bin",
+ },
+ {
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "Vendor/Device",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-vendor-device.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-vendor-device.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-vendor-device.bin",
+ },
+ {
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "1234:56AB",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-1234-56ab.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-1234-56ab.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-1234-56ab.bin",
+ },
+
+ {
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "abc",
+ .alsa_name = "LEFT",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc-left.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc-left.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc-left.bin",
+ },
+ {
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "abc",
+ .alsa_name = "LEFT AMP",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc-left-amp.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc-left-amp.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc-left-amp.bin",
+ },
+ {
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "abc",
+ .alsa_name = "Left Amp",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc-left-amp.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc-left-amp.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc-left-amp.bin",
+ },
+ {
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "abc",
+ .alsa_name = "Amp_1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc-amp-1.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc-amp-1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc-amp-1.bin",
+ },
+ {
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "abc",
+ .alsa_name = "cs1234.1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc-cs1234.1.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc-cs1234.1.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc-cs1234.1.bin",
+ },
+ {
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "abc",
+ .alsa_name = "Spk/Jack",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-abc-spk-jack.wmfw",
+ .expected_searches =
+ "cirrus/cs1234-dsp1-mbc-vss-abc-spk-jack.wmfw "
+ "cirrus/cs1234-dsp1-mbc-vss-abc-spk-jack.bin",
+ },
+};
+KUNIT_ARRAY_PARAM(wm_adsp_fw_find_normalization,
+ wm_adsp_fw_find_normalization_cases,
+ wm_adsp_fw_find_test_param_desc);
+
+/*
+ * Dummy directory content for regression tests.
+ * DSP part name and system name are used to select different available
+ * files.
+ *
+ * System:
+ * WFBF1111 = wmfw and bin fully-qualified
+ * WSBF1111 = wmfw system-qualified, bin fully-qualified
+ * WSBS1111 = wmfw and bin system-qualified
+ * WFXX1111 = wmfw fully-qualified, bin not present
+ * XXBF1111 = wmfw not present, bin fully-qualified
+ *
+ * Part:
+ * cs1234 = for testing fully-qualified configurations
+ * cs1234nobin = generic wmfw without a bin available
+ * wm1234 = legacy wmfw and bin
+ * wm1234nobin = legacy wmfw without bin
+ */
+static const char * const wm_adsp_fw_find_test_dir_all_files[] = {
+ "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.wmfw",
+ "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-l1u2.wmfw",
+ "cirrus/cs1234-dsp1-mbc-vss-wfbf1111.wmfw",
+ "cirrus/cs1234-dsp1-mbc-vss-wsbf1111.wmfw",
+ "cirrus/cs1234-dsp1-mbc-vss-wsbs1111.wmfw",
+ "cirrus/cs1234-dsp1-mbc-vss-wfxx1111.wmfw",
+ "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ "cirrus/cs1234nobin-dsp1-mbc-vss.wmfw",
+ "cirrus/wm1234-dsp1-mbc-vss.wmfw",
+ "cirrus/wm1234nobin-dsp1-mbc-vss.wmfw",
+ "wm1234-dsp1-mbc-vss.wmfw",
+ "wm1234nobin-dsp1-mbc-vss.wmfw",
+ "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.bin",
+ "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-l1u2.bin",
+ "cirrus/cs1234-dsp1-mbc-vss-wsbf1111-amp1.bin",
+ "cirrus/cs1234-dsp1-mbc-vss-wsbf1111-l1u2.bin",
+ "cirrus/cs1234-dsp1-mbc-vss-wsbs1111.bin",
+ "cirrus/cs1234-dsp1-mbc-vss-xxbf1111-amp1.bin",
+ "cirrus/cs1234-dsp1-mbc-vss.bin",
+ "cirrus/wm1234-dsp1-mbc-vss.bin",
+ "wm1234-dsp1-mbc-vss.bin",
+ NULL /* terminator */
+};
+
+/*
+ * Regression testing that a change in the search algorithm doesn't change
+ * which file is picked. This doesn't cover every possible combination, only
+ * those that are already in use and typical cases.
+ *
+ * It wouldn't be efficent to fully prove the algorithm this way (too many
+ * directory content combinations would be needed, and it only infers what the
+ * algorithm searched for, it doesn't prove exactly what searches were made).
+ * So the main testing is done by checking for the expected file searches.
+ * This regression test is independent of the search algorithm.
+ *
+ * The main tests already prove that the algorithm only searches for files
+ * with the correct qualifiers so we can assume that files with the wrong
+ * qualifiers would not be picked and there's no need to test for that here.
+ */
+static const struct wm_adsp_fw_find_test_params wm_adsp_fw_find_pick_cases[] = {
+ /*
+ * Amps
+ */
+ { /* Full info, wmfw and bin fully-qualified */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "WFBF1111",
+ .alsa_name = "amp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.bin",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* Full info, wmfw and bin fully-qualified */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "WFBF1111",
+ .alsa_name = "l1u2",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-l1u2.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-l1u2.bin",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* Full info, wmfw only system-qualified, bin fully-qualified */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "WSBF1111",
+ .alsa_name = "amp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wsbf1111.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wsbf1111-amp1.bin",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* Full info, wmfw only system-qualified, bin fully-qualified */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "WSBF1111",
+ .alsa_name = "l1u2",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wsbf1111.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wsbf1111-l1u2.bin",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* Full info, wmfw optional but present, and bin fully-qualified */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "WFBF1111",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.bin",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* Full info, wmfw and bin only system-qualified */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "WSBS1111",
+ .alsa_name = "amp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wsbs1111.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wsbs1111.bin",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* Full info, wmfw optional but system-qualified wmfm present, bin fully-qualified */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "WSBF1111",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wsbf1111.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wsbf1111-amp1.bin",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* Full info, wmfw optional not present, and bin fully-qualified */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "XXBF1111",
+ .alsa_name = "amp1", .wmfw_optional = true,
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-xxbf1111-amp1.bin",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* Full info, wmfw and bin fully-qualified, bin mandatory and present */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "WFBF1111",
+ .alsa_name = "amp1", .bin_mandatory = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss-wfbf1111-amp1.bin",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* Full info, wmfw and bin fully-qualified, bin mandatory but not present */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "WFXX1111",
+ .alsa_name = "amp1", .bin_mandatory = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wfxx1111.wmfw",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* Full info, wmfw optional but present, bin mandatory but not present */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "WFXX1111",
+ .alsa_name = "amp1", .wmfw_optional = true, .bin_mandatory = true,
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss-wfxx1111.wmfw",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* Full info, wmfw and bin not present, generic fallbacks are present */
+ .part = "cs1234", .dsp_name = "dsp1", .system_name = "XXXX1111",
+ .alsa_name = "amp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* Full info, wmfw and bin not present, generic wmfw present */
+ .part = "cs1234nobin", .dsp_name = "dsp1", .system_name = "XXXX1111",
+ .alsa_name = "amp1",
+ .expect_wmfw = "cirrus/cs1234nobin-dsp1-mbc-vss.wmfw",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+
+ /*
+ * Codecs
+ */
+ { /* No qualifiers. Generic wmfws exist, legacy should be chosen. */
+ .part = "wm1234nobin", .dsp_name = "dsp1",
+ .expect_wmfw = "wm1234nobin-dsp1-mbc-vss.wmfw",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* No qualifiers. Generic wmfw and bin exist, legacy should be chosen */
+ .part = "wm1234", .dsp_name = "dsp1",
+ .expect_wmfw = "wm1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "wm1234-dsp1-mbc-vss.bin",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* No qualifiers. New generic wmfw exists, no legacy files. */
+ .part = "cs1234nobin", .dsp_name = "dsp1",
+ .expect_wmfw = "cirrus/cs1234nobin-dsp1-mbc-vss.wmfw",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+ { /* No qualifiers. New generic wmfw and bin exist, no legacy files. */
+ .part = "cs1234", .dsp_name = "dsp1",
+ .expect_wmfw = "cirrus/cs1234-dsp1-mbc-vss.wmfw",
+ .expect_bin = "cirrus/cs1234-dsp1-mbc-vss.bin",
+ .dir_files = wm_adsp_fw_find_test_dir_all_files,
+ },
+};
+KUNIT_ARRAY_PARAM(wm_adsp_fw_find_pick,
+ wm_adsp_fw_find_pick_cases,
+ wm_adsp_fw_find_test_param_desc);
+
+static struct kunit_case wm_adsp_fw_find_test_cases[] = {
+ KUNIT_CASE_PARAM(wm_adsp_fw_find_test_search_order,
+ wm_adsp_fw_find_full_search_gen_params),
+
+ KUNIT_CASE_PARAM(wm_adsp_fw_find_test_search_order,
+ wm_adsp_fw_find_system_alsaname_gen_params),
+
+ KUNIT_CASE_PARAM(wm_adsp_fw_find_test_search_order,
+ wm_adsp_fw_find_system_gen_params),
+
+ KUNIT_CASE_PARAM(wm_adsp_fw_find_test_search_order,
+ wm_adsp_fw_find_alsaname_gen_params),
+
+ KUNIT_CASE_PARAM(wm_adsp_fw_find_test_search_order,
+ wm_adsp_fw_find_noqual_gen_params),
+
+ KUNIT_CASE_PARAM(wm_adsp_fw_find_test_search_order,
+ wm_adsp_fw_find_normalization_gen_params),
+
+ KUNIT_CASE_PARAM(wm_adsp_fw_find_test_pick_file,
+ wm_adsp_fw_find_pick_gen_params),
+
+ KUNIT_CASE(wm_adsp_fw_find_test_find_firmware_byindex),
+
+ { } /* terminator */
+};
+
+static struct kunit_suite wm_adsp_fw_find_test_suite = {
+ .name = "wm-adsp-fw-find",
+ .init = wm_adsp_fw_find_test_case_init,
+ .exit = wm_adsp_fw_find_test_case_exit,
+ .test_cases = wm_adsp_fw_find_test_cases,
+};
+
+kunit_test_suite(wm_adsp_fw_find_test_suite);
+
+MODULE_DESCRIPTION("KUnit test for Cirrus Logic wm_adsp driver");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index 28001e9857d9..74dfd39fd604 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ALSA SoC Synopsys I2S Audio Layer
*
@@ -5,10 +6,6 @@
*
* Copyright (C) 2010 ST Microelectronics
* Rajeev Kumar <rajeevkumar.linux@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
*/
#include <linux/clk.h>
diff --git a/sound/soc/dwc/dwc-pcm.c b/sound/soc/dwc/dwc-pcm.c
index a418265c030a..bbc4ea88edc4 100644
--- a/sound/soc/dwc/dwc-pcm.c
+++ b/sound/soc/dwc/dwc-pcm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ALSA SoC Synopsys PIO PCM for I2S driver
*
@@ -5,10 +6,6 @@
*
* Copyright (C) 2016 Synopsys
* Jose Abreu <joabreu@synopsys.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
*/
#include <linux/io.h>
@@ -256,7 +253,7 @@ static const struct snd_soc_component_driver dw_pcm_component = {
.hw_params = dw_pcm_hw_params,
.trigger = dw_pcm_trigger,
.pointer = dw_pcm_pointer,
- .pcm_construct = dw_pcm_new,
+ .pcm_new = dw_pcm_new,
};
int dw_pcm_register(struct platform_device *pdev)
diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h
index dce88c9ad5f3..6510b3496371 100644
--- a/sound/soc/dwc/local.h
+++ b/sound/soc/dwc/local.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (ST) 2012 Rajeev Kumar (rajeevkumar.linux@gmail.com)
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
*/
#ifndef __DESIGNWARE_LOCAL_H
diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c
index de17b103a4cf..4d3266d9cbb7 100644
--- a/sound/soc/fsl/efika-audio-fabric.c
+++ b/sound/soc/fsl/efika-audio-fabric.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Efika driver for the PSC of the Freescale MPC52xx
* configured as AC97 interface
*
* Copyright 2008 Jon Smirl, Digispeaker
* Author: Jon Smirl <jonsmirl@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
*/
#include <linux/init.h>
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index 348b0aabfa68..5aa96af994c4 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -505,7 +505,7 @@ struct snd_soc_component_driver fsl_asrc_component = {
.open = fsl_asrc_dma_startup,
.close = fsl_asrc_dma_shutdown,
.pointer = fsl_asrc_dma_pcm_pointer,
- .pcm_construct = fsl_asrc_dma_pcm_new,
+ .pcm_new = fsl_asrc_dma_pcm_new,
.legacy_dai_naming = 1,
#ifdef CONFIG_DEBUG_FS
.debugfs_prefix = "asrc",
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 26ddbe867b58..b12474880185 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -267,14 +267,8 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
/**
* fsl_dma_new: initialize this PCM driver.
*
- * This function is called when the codec driver calls snd_soc_new_pcms(),
- * once for each .dai_link in the machine driver's snd_soc_card
- * structure.
- *
- * snd_dma_alloc_pages() is just a front-end to dma_alloc_coherent(), which
- * (currently) always allocates the DMA buffer in lowmem, even if GFP_HIGHMEM
- * is specified. Therefore, any DMA buffers we allocate will always be in low
- * memory, but we support for 36-bit physical addresses anyway.
+ * This function is called by soc_new_pcm(), once for each DAI link
+ * in the machine driver's snd_soc_card structure.
*
* Regardless of where the memory is actually allocated, since the device can
* technically DMA to any 36-bit address, we do need to set the DMA mask to 36.
@@ -860,7 +854,7 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
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_construct = fsl_dma_new;
+ dma->dai.pcm_new = fsl_dma_new;
/* Store the SSI-specific information that we need */
dma->ssi_stx_phys = res.start + REG_SSI_STX0;
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index 6c56134c60cc..114a6c0b6b73 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -54,6 +54,9 @@ static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol,
unsigned int regval = ucontrol->value.integer.value[0];
int ret;
+ if (regval < EASRC_WIDTH_16_BIT || regval > EASRC_WIDTH_24_BIT)
+ return -EINVAL;
+
ret = (easrc_priv->bps_iec958[mc->regbase] != regval);
easrc_priv->bps_iec958[mc->regbase] = regval;
@@ -70,8 +73,16 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol,
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
- ucontrol->value.enumerated.item[0] = easrc_priv->bps_iec958[mc->regbase];
+ ucontrol->value.integer.value[0] = easrc_priv->bps_iec958[mc->regbase];
+
+ return 0;
+}
+static int fsl_easrc_iec958_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
return 0;
}
@@ -81,11 +92,33 @@ static int fsl_easrc_get_reg(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
- unsigned int regval;
+ struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component);
+ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status;
+ int ret;
+
+ ret = regmap_read(easrc->regmap, REG_EASRC_CS0(mc->regbase), &regval[0]);
+ if (ret)
+ return ret;
- regval = snd_soc_component_read(component, mc->regbase);
+ ret = regmap_read(easrc->regmap, REG_EASRC_CS1(mc->regbase), &regval[1]);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(easrc->regmap, REG_EASRC_CS2(mc->regbase), &regval[2]);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(easrc->regmap, REG_EASRC_CS3(mc->regbase), &regval[3]);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(easrc->regmap, REG_EASRC_CS4(mc->regbase), &regval[4]);
+ if (ret)
+ return ret;
- ucontrol->value.integer.value[0] = regval;
+ ret = regmap_read(easrc->regmap, REG_EASRC_CS5(mc->regbase), &regval[5]);
+ if (ret)
+ return ret;
return 0;
}
@@ -97,22 +130,62 @@ static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol,
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component);
- unsigned int regval = ucontrol->value.integer.value[0];
- bool changed;
+ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status;
+ bool changed, changed_all = false;
int ret;
- ret = regmap_update_bits_check(easrc->regmap, mc->regbase,
- GENMASK(31, 0), regval, &changed);
- if (ret != 0)
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret)
return ret;
- return changed;
+ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS0(mc->regbase),
+ GENMASK(31, 0), regval[0], &changed);
+ if (ret != 0)
+ goto err;
+ changed_all |= changed;
+
+ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS1(mc->regbase),
+ GENMASK(31, 0), regval[1], &changed);
+ if (ret != 0)
+ goto err;
+ changed_all |= changed;
+
+ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS2(mc->regbase),
+ GENMASK(31, 0), regval[2], &changed);
+ if (ret != 0)
+ goto err;
+ changed_all |= changed;
+
+ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS3(mc->regbase),
+ GENMASK(31, 0), regval[3], &changed);
+ if (ret != 0)
+ goto err;
+ changed_all |= changed;
+
+ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS4(mc->regbase),
+ GENMASK(31, 0), regval[4], &changed);
+ if (ret != 0)
+ goto err;
+ changed_all |= changed;
+
+ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS5(mc->regbase),
+ GENMASK(31, 0), regval[5], &changed);
+ if (ret != 0)
+ goto err;
+ changed_all |= changed;
+err:
+ pm_runtime_put_autosuspend(component->dev);
+
+ if (ret != 0)
+ return ret;
+ else
+ return changed_all;
}
#define SOC_SINGLE_REG_RW(xname, xreg) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
- .info = snd_soc_info_xr_sx, .get = fsl_easrc_get_reg, \
+ .info = fsl_easrc_iec958_info, .get = fsl_easrc_get_reg, \
.put = fsl_easrc_set_reg, \
.private_value = (unsigned long)&(struct soc_mreg_control) \
{ .regbase = xreg, .regcount = 1, .nbits = 32, \
@@ -143,30 +216,10 @@ static const struct snd_kcontrol_new fsl_easrc_snd_controls[] = {
SOC_SINGLE_VAL_RW("Context 2 IEC958 Bits Per Sample", 2),
SOC_SINGLE_VAL_RW("Context 3 IEC958 Bits Per Sample", 3),
- SOC_SINGLE_REG_RW("Context 0 IEC958 CS0", REG_EASRC_CS0(0)),
- SOC_SINGLE_REG_RW("Context 1 IEC958 CS0", REG_EASRC_CS0(1)),
- SOC_SINGLE_REG_RW("Context 2 IEC958 CS0", REG_EASRC_CS0(2)),
- SOC_SINGLE_REG_RW("Context 3 IEC958 CS0", REG_EASRC_CS0(3)),
- SOC_SINGLE_REG_RW("Context 0 IEC958 CS1", REG_EASRC_CS1(0)),
- SOC_SINGLE_REG_RW("Context 1 IEC958 CS1", REG_EASRC_CS1(1)),
- SOC_SINGLE_REG_RW("Context 2 IEC958 CS1", REG_EASRC_CS1(2)),
- SOC_SINGLE_REG_RW("Context 3 IEC958 CS1", REG_EASRC_CS1(3)),
- SOC_SINGLE_REG_RW("Context 0 IEC958 CS2", REG_EASRC_CS2(0)),
- SOC_SINGLE_REG_RW("Context 1 IEC958 CS2", REG_EASRC_CS2(1)),
- SOC_SINGLE_REG_RW("Context 2 IEC958 CS2", REG_EASRC_CS2(2)),
- SOC_SINGLE_REG_RW("Context 3 IEC958 CS2", REG_EASRC_CS2(3)),
- SOC_SINGLE_REG_RW("Context 0 IEC958 CS3", REG_EASRC_CS3(0)),
- SOC_SINGLE_REG_RW("Context 1 IEC958 CS3", REG_EASRC_CS3(1)),
- SOC_SINGLE_REG_RW("Context 2 IEC958 CS3", REG_EASRC_CS3(2)),
- SOC_SINGLE_REG_RW("Context 3 IEC958 CS3", REG_EASRC_CS3(3)),
- SOC_SINGLE_REG_RW("Context 0 IEC958 CS4", REG_EASRC_CS4(0)),
- SOC_SINGLE_REG_RW("Context 1 IEC958 CS4", REG_EASRC_CS4(1)),
- SOC_SINGLE_REG_RW("Context 2 IEC958 CS4", REG_EASRC_CS4(2)),
- SOC_SINGLE_REG_RW("Context 3 IEC958 CS4", REG_EASRC_CS4(3)),
- SOC_SINGLE_REG_RW("Context 0 IEC958 CS5", REG_EASRC_CS5(0)),
- SOC_SINGLE_REG_RW("Context 1 IEC958 CS5", REG_EASRC_CS5(1)),
- SOC_SINGLE_REG_RW("Context 2 IEC958 CS5", REG_EASRC_CS5(2)),
- SOC_SINGLE_REG_RW("Context 3 IEC958 CS5", REG_EASRC_CS5(3)),
+ SOC_SINGLE_REG_RW("Context 0 IEC958 CS", 0),
+ SOC_SINGLE_REG_RW("Context 1 IEC958 CS", 1),
+ SOC_SINGLE_REG_RW("Context 2 IEC958 CS", 2),
+ SOC_SINGLE_REG_RW("Context 3 IEC958 CS", 3),
};
/*
@@ -1286,7 +1339,7 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx)
/*
* Release the context
*
- * This funciton is mainly doing the revert thing in request context
+ * This function is mainly doing the revert thing in request context
*/
static void fsl_easrc_release_context(struct fsl_asrc_pair *ctx)
{
diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c
index d6cde2757c6d..2e887f1f1f36 100644
--- a/sound/soc/fsl/fsl_micfil.c
+++ b/sound/soc/fsl/fsl_micfil.c
@@ -210,15 +210,23 @@ static int micfil_range_set(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int shift = mc->shift;
int max_range, new_range;
+ int ret;
new_range = ucontrol->value.integer.value[0];
max_range = micfil_get_max_range(micfil);
if (new_range > max_range)
dev_warn(&micfil->pdev->dev, "range makes channel %d data unreliable\n", shift / 4);
- regmap_update_bits(micfil->regmap, REG_MICFIL_OUT_CTRL, 0xF << shift, new_range << shift);
+ ret = pm_runtime_resume_and_get(cmpnt->dev);
+ if (ret)
+ return ret;
- return 0;
+ ret = snd_soc_component_update_bits(cmpnt, REG_MICFIL_OUT_CTRL, 0xF << shift,
+ new_range << shift);
+
+ pm_runtime_put_autosuspend(cmpnt->dev);
+
+ return ret;
}
static int micfil_set_quality(struct fsl_micfil *micfil)
@@ -281,10 +289,34 @@ static int micfil_quality_set(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt);
+ int val = ucontrol->value.integer.value[0];
+ bool change = false;
+ int old_val;
+ int ret;
+
+ if (val < QUALITY_HIGH || val > QUALITY_VLOW2)
+ return -EINVAL;
+
+ if (micfil->quality != val) {
+ ret = pm_runtime_resume_and_get(cmpnt->dev);
+ if (ret)
+ return ret;
+
+ old_val = micfil->quality;
+ micfil->quality = val;
+ ret = micfil_set_quality(micfil);
- micfil->quality = ucontrol->value.integer.value[0];
+ pm_runtime_put_autosuspend(cmpnt->dev);
+
+ if (ret) {
+ micfil->quality = old_val;
+ return ret;
+ }
- return micfil_set_quality(micfil);
+ change = true;
+ }
+
+ return change;
}
static const char * const micfil_hwvad_enable[] = {
@@ -343,6 +375,10 @@ static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol,
if (val < 0 || val > 3)
return -EINVAL;
+ ret = pm_runtime_resume_and_get(comp->dev);
+ if (ret)
+ return ret;
+
micfil->dc_remover = val;
/* Calculate total value for all channels */
@@ -352,10 +388,10 @@ static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol,
/* Update DC Remover mode for all channels */
ret = snd_soc_component_update_bits(comp, REG_MICFIL_DC_CTRL,
MICFIL_DC_CTRL_CONFIG, reg_val);
- if (ret < 0)
- return ret;
- return 0;
+ pm_runtime_put_autosuspend(comp->dev);
+
+ return ret;
}
static int micfil_get_dc_remover_state(struct snd_kcontrol *kcontrol,
@@ -377,10 +413,15 @@ static int hwvad_put_enable(struct snd_kcontrol *kcontrol,
unsigned int *item = ucontrol->value.enumerated.item;
struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
int val = snd_soc_enum_item_to_val(e, item[0]);
+ bool change = false;
+
+ if (val < 0 || val > 1)
+ return -EINVAL;
+ change = (micfil->vad_enabled != val);
micfil->vad_enabled = val;
- return 0;
+ return change;
}
static int hwvad_get_enable(struct snd_kcontrol *kcontrol,
@@ -402,13 +443,18 @@ static int hwvad_put_init_mode(struct snd_kcontrol *kcontrol,
unsigned int *item = ucontrol->value.enumerated.item;
struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
int val = snd_soc_enum_item_to_val(e, item[0]);
+ bool change = false;
+
+ if (val < MICFIL_HWVAD_ENVELOPE_MODE || val > MICFIL_HWVAD_ENERGY_MODE)
+ return -EINVAL;
/* 0 - Envelope-based Mode
* 1 - Energy-based Mode
*/
+ change = (micfil->vad_init_mode != val);
micfil->vad_init_mode = val;
- return 0;
+ return change;
}
static int hwvad_get_init_mode(struct snd_kcontrol *kcontrol,
@@ -503,7 +549,13 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
SOC_SINGLE("HWVAD ZCD Adjustment", REG_MICFIL_VAD0_ZCD, 8, 15, 0),
SOC_SINGLE("HWVAD ZCD And Behavior Switch",
REG_MICFIL_VAD0_ZCD, 4, 1, 0),
- SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .name = "VAD Detected",
+ .info = snd_soc_info_bool_ext,
+ .get = hwvad_detected,
+ },
};
static int fsl_micfil_use_verid(struct device *dev)
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
index 43d401ae2d03..76e014dfb6d7 100644
--- a/sound/soc/fsl/fsl_qmc_audio.c
+++ b/sound/soc/fsl/fsl_qmc_audio.c
@@ -54,8 +54,8 @@ struct qmc_dai_prtd {
struct snd_pcm_substream *substream;
};
-static int qmc_audio_pcm_construct(struct snd_soc_component *component,
- struct snd_soc_pcm_runtime *rtd)
+static int qmc_audio_pcm_new(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
int ret;
@@ -340,7 +340,7 @@ static const struct snd_soc_component_driver qmc_audio_soc_platform = {
.hw_params = qmc_audio_pcm_hw_params,
.trigger = qmc_audio_pcm_trigger,
.pointer = qmc_audio_pcm_pointer,
- .pcm_construct = qmc_audio_pcm_construct,
+ .pcm_new = qmc_audio_pcm_new,
.of_xlate_dai_name = qmc_audio_of_xlate_dai_name,
};
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 148e09e58dfa..bd336d2e4cb3 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -41,6 +41,52 @@ static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
.list = fsl_sai_rates,
};
+static const char * const inc_mode[] = {
+ "On enabled and bitcount increment", "On enabled"
+};
+
+static SOC_ENUM_SINGLE_DECL(transmit_tstmp_enum,
+ FSL_SAI_TTCTL, FSL_SAI_xTCTL_TSINC_SHIFT, inc_mode);
+static SOC_ENUM_SINGLE_DECL(receive_tstmp_enum,
+ FSL_SAI_RTCTL, FSL_SAI_xTCTL_TSINC_SHIFT, inc_mode);
+
+static const struct snd_kcontrol_new fsl_sai_timestamp_ctrls[] = {
+ FSL_ASOC_SINGLE_EXT("Transmit Timestamp Control Switch", FSL_SAI_TTCTL,
+ FSL_SAI_xTCTL_TSEN_SHIFT, 1, 0,
+ fsl_asoc_get_volsw, fsl_asoc_put_volsw),
+ FSL_ASOC_ENUM_EXT("Transmit Timestamp Increment", transmit_tstmp_enum,
+ fsl_asoc_get_enum_double, fsl_asoc_put_enum_double),
+ FSL_ASOC_SINGLE_EXT("Transmit Timestamp Reset Switch", FSL_SAI_TTCTL,
+ FSL_SAI_xTCTL_RTSC_SHIFT, 1, 0,
+ fsl_asoc_get_volsw, fsl_asoc_put_volsw),
+ FSL_ASOC_SINGLE_EXT("Transmit Bit Counter Reset Switch", FSL_SAI_TTCTL,
+ FSL_SAI_xTCTL_RBC_SHIFT, 1, 0,
+ fsl_asoc_get_volsw, fsl_asoc_put_volsw),
+ FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Timestamp Counter", FSL_SAI_TTCTN,
+ 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
+ FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Bit Counter", FSL_SAI_TBCTN,
+ 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
+ FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Latched Timestamp Counter", FSL_SAI_TTCAP,
+ 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
+ FSL_ASOC_SINGLE_EXT("Receive Timestamp Control Switch", FSL_SAI_RTCTL,
+ FSL_SAI_xTCTL_TSEN_SHIFT, 1, 0,
+ fsl_asoc_get_volsw, fsl_asoc_put_volsw),
+ FSL_ASOC_ENUM_EXT("Receive Timestamp Increment", receive_tstmp_enum,
+ fsl_asoc_get_enum_double, fsl_asoc_put_enum_double),
+ FSL_ASOC_SINGLE_EXT("Receive Timestamp Reset Switch", FSL_SAI_RTCTL,
+ FSL_SAI_xTCTL_RTSC_SHIFT, 1, 0,
+ fsl_asoc_get_volsw, fsl_asoc_put_volsw),
+ FSL_ASOC_SINGLE_EXT("Receive Bit Counter Reset Switch", FSL_SAI_RTCTL,
+ FSL_SAI_xTCTL_RBC_SHIFT, 1, 0,
+ fsl_asoc_get_volsw, fsl_asoc_put_volsw),
+ FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Timestamp Counter", FSL_SAI_RTCTN,
+ 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
+ FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Bit Counter", FSL_SAI_RBCTN,
+ 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
+ FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Latched Timestamp Counter", FSL_SAI_RTCAP,
+ 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
+};
+
/**
* fsl_sai_dir_is_synced - Check if stream is synced by the opposite stream
*
@@ -1010,6 +1056,17 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component)
return 0;
}
+static int fsl_sai_component_probe(struct snd_soc_component *component)
+{
+ struct fsl_sai *sai = snd_soc_component_get_drvdata(component);
+
+ if (sai->verid.feature & FSL_SAI_VERID_TSTMP_EN)
+ snd_soc_add_component_controls(component, fsl_sai_timestamp_ctrls,
+ ARRAY_SIZE(fsl_sai_timestamp_ctrls));
+
+ return 0;
+}
+
static struct snd_soc_dai_driver fsl_sai_dai_template[] = {
{
.name = "sai-tx-rx",
@@ -1063,6 +1120,7 @@ static struct snd_soc_dai_driver fsl_sai_dai_template[] = {
static const struct snd_soc_component_driver fsl_component = {
.name = "fsl-sai",
+ .probe = fsl_sai_component_probe,
.resume = fsl_sai_dai_resume,
.legacy_dai_naming = 1,
};
@@ -1211,6 +1269,14 @@ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
case FSL_SAI_RDR5:
case FSL_SAI_RDR6:
case FSL_SAI_RDR7:
+ case FSL_SAI_TTCTN:
+ case FSL_SAI_RTCTN:
+ case FSL_SAI_TTCTL:
+ case FSL_SAI_TBCTN:
+ case FSL_SAI_TTCAP:
+ case FSL_SAI_RTCTL:
+ case FSL_SAI_RBCTN:
+ case FSL_SAI_RTCAP:
return true;
default:
return false;
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index 7605cbaca3d8..af967833b6ed 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -196,9 +196,13 @@
#define FSL_SAI_MDIV_MASK 0xFFFFF
/* SAI timestamp and bitcounter */
+#define FSL_SAI_xTCTL_TSEN_SHIFT 0
#define FSL_SAI_xTCTL_TSEN BIT(0)
+#define FSL_SAI_xTCTL_TSINC_SHIFT 1
#define FSL_SAI_xTCTL_TSINC BIT(1)
+#define FSL_SAI_xTCTL_RTSC_SHIFT 8
#define FSL_SAI_xTCTL_RTSC BIT(8)
+#define FSL_SAI_xTCTL_RBC_SHIFT 9
#define FSL_SAI_xTCTL_RBC BIT(9)
/* SAI type */
diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c
index d69a6b9795bf..7651c64bc837 100644
--- a/sound/soc/fsl/fsl_utils.c
+++ b/sound/soc/fsl/fsl_utils.c
@@ -10,6 +10,7 @@
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
#include <sound/soc.h>
#include "fsl_utils.h"
@@ -197,6 +198,136 @@ void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr,
}
EXPORT_SYMBOL(fsl_asoc_constrain_rates);
+/*
+ * Below functions are used by mixer interface to avoid accessing registers
+ * which are volatile at pm runtime suspend state (cache_only is enabled).
+ */
+int fsl_asoc_get_xr_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ int ret = 0;
+
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_get_xr_sx(kcontrol, ucontrol);
+
+ pm_runtime_put_autosuspend(component->dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(fsl_asoc_get_xr_sx);
+
+int fsl_asoc_put_xr_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ int ret = 0;
+
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_put_xr_sx(kcontrol, ucontrol);
+ /*
+ * As this function only used by the SNDRV_CTL_ELEM_ACCESS_VOLATILE
+ * case. return 0 to avoid control event notification.
+ */
+ if (ret > 0)
+ ret = 0;
+
+ pm_runtime_put_autosuspend(component->dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(fsl_asoc_put_xr_sx);
+
+int fsl_asoc_get_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ int ret = 0;
+
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_get_enum_double(kcontrol, ucontrol);
+
+ pm_runtime_put_autosuspend(component->dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(fsl_asoc_get_enum_double);
+
+int fsl_asoc_put_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ int ret = 0;
+
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_put_enum_double(kcontrol, ucontrol);
+ /*
+ * As this function only used by the SNDRV_CTL_ELEM_ACCESS_VOLATILE
+ * case. return 0 to avoid control event notification.
+ */
+ if (ret > 0)
+ ret = 0;
+
+ pm_runtime_put_autosuspend(component->dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(fsl_asoc_put_enum_double);
+
+int fsl_asoc_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ int ret = 0;
+
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_get_volsw(kcontrol, ucontrol);
+
+ pm_runtime_put_autosuspend(component->dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(fsl_asoc_get_volsw);
+
+int fsl_asoc_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ int ret = 0;
+
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ /*
+ * As this function only used by the SNDRV_CTL_ELEM_ACCESS_VOLATILE
+ * case. return 0 to avoid control event notification.
+ */
+ if (ret > 0)
+ ret = 0;
+
+ pm_runtime_put_autosuspend(component->dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(fsl_asoc_put_volsw);
+
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
MODULE_DESCRIPTION("Freescale ASoC utility code");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_utils.h b/sound/soc/fsl/fsl_utils.h
index 21b25a11ecda..1aab0c1cee62 100644
--- a/sound/soc/fsl/fsl_utils.h
+++ b/sound/soc/fsl/fsl_utils.h
@@ -31,4 +31,52 @@ void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr,
const struct snd_pcm_hw_constraint_list *original_constr,
struct clk *pll8k_clk, struct clk *pll11k_clk,
struct clk *ext_clk, int *target_rates);
+
+/* Similar to SOC_SINGLE_XR_SX, but it is for read only registers. */
+#define FSL_ASOC_SINGLE_XR_SX_EXT_RO(xname, xregbase, xregcount, xnbits, \
+ xmin, xmax, xinvert, xhandler_get) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | \
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_soc_info_xr_sx, .get = xhandler_get, \
+ .private_value = (unsigned long)&(struct soc_mreg_control) \
+ {.regbase = xregbase, .regcount = xregcount, .nbits = xnbits, \
+ .invert = xinvert, .min = xmin, .max = xmax} }
+
+/* Similar to SOC_SINGLE_EXT, but it is for volatile register. */
+#define FSL_ASOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\
+ xhandler_get, xhandler_put) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_VOLATILE | \
+ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = snd_soc_info_volsw, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = SOC_SINGLE_VALUE(xreg, xshift, 0, xmax, xinvert, 0) }
+
+#define FSL_ASOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_VOLATILE | \
+ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = snd_soc_info_enum_double, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = (unsigned long)&xenum }
+
+int fsl_asoc_get_xr_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
+int fsl_asoc_put_xr_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
+int fsl_asoc_get_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
+int fsl_asoc_put_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
+int fsl_asoc_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
+int fsl_asoc_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
#endif /* _FSL_UTILS_H */
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
index a268fb81a2f8..ee16cf681488 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -62,6 +62,58 @@ struct fsl_xcvr {
u32 spdif_constr_rates_list[SPDIF_NUM_RATES];
};
+static const char * const inc_mode[] = {
+ "On enabled and bitcount increment", "On enabled"
+};
+
+static SOC_ENUM_SINGLE_DECL(transmit_tstmp_enum,
+ FSL_XCVR_TX_DPTH_CNTR_CTRL,
+ FSL_XCVR_TX_DPTH_CNTR_CTRL_TSINC_SHIFT, inc_mode);
+static SOC_ENUM_SINGLE_DECL(receive_tstmp_enum,
+ FSL_XCVR_RX_DPTH_CNTR_CTRL,
+ FSL_XCVR_RX_DPTH_CNTR_CTRL_TSINC_SHIFT, inc_mode);
+
+static const struct snd_kcontrol_new fsl_xcvr_timestamp_ctrls[] = {
+ FSL_ASOC_SINGLE_EXT("Transmit Timestamp Control Switch", FSL_XCVR_TX_DPTH_CNTR_CTRL,
+ FSL_XCVR_TX_DPTH_CNTR_CTRL_TSEN_SHIFT, 1, 0,
+ fsl_asoc_get_volsw, fsl_asoc_put_volsw),
+ FSL_ASOC_ENUM_EXT("Transmit Timestamp Increment", transmit_tstmp_enum,
+ fsl_asoc_get_enum_double, fsl_asoc_put_enum_double),
+ FSL_ASOC_SINGLE_EXT("Transmit Timestamp Reset Switch", FSL_XCVR_TX_DPTH_CNTR_CTRL,
+ FSL_XCVR_TX_DPTH_CNTR_CTRL_RTSC_SHIFT, 1, 0,
+ fsl_asoc_get_volsw, fsl_asoc_put_volsw),
+ FSL_ASOC_SINGLE_EXT("Transmit Bit Counter Reset Switch", FSL_XCVR_TX_DPTH_CNTR_CTRL,
+ FSL_XCVR_TX_DPTH_CNTR_CTRL_RBC_SHIFT, 1, 0,
+ fsl_asoc_get_volsw, fsl_asoc_put_volsw),
+ FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Timestamp Counter", FSL_XCVR_TX_DPTH_TSCR,
+ 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
+ FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Bit Counter", FSL_XCVR_TX_DPTH_BCR,
+ 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
+ FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Bit Count Timestamp", FSL_XCVR_TX_DPTH_BCTR,
+ 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
+ FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Latched Timestamp Counter", FSL_XCVR_TX_DPTH_BCRR,
+ 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
+ FSL_ASOC_SINGLE_EXT("Receive Timestamp Control Switch", FSL_XCVR_RX_DPTH_CNTR_CTRL,
+ FSL_XCVR_RX_DPTH_CNTR_CTRL_TSEN_SHIFT, 1, 0,
+ fsl_asoc_get_volsw, fsl_asoc_put_volsw),
+ FSL_ASOC_ENUM_EXT("Receive Timestamp Increment", receive_tstmp_enum,
+ fsl_asoc_get_enum_double, fsl_asoc_put_enum_double),
+ FSL_ASOC_SINGLE_EXT("Receive Timestamp Reset Switch", FSL_XCVR_RX_DPTH_CNTR_CTRL,
+ FSL_XCVR_RX_DPTH_CNTR_CTRL_RTSC_SHIFT, 1, 0,
+ fsl_asoc_get_volsw, fsl_asoc_put_volsw),
+ FSL_ASOC_SINGLE_EXT("Receive Bit Counter Reset Switch", FSL_XCVR_RX_DPTH_CNTR_CTRL,
+ FSL_XCVR_RX_DPTH_CNTR_CTRL_RBC_SHIFT, 1, 0,
+ fsl_asoc_get_volsw, fsl_asoc_put_volsw),
+ FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Timestamp Counter", FSL_XCVR_RX_DPTH_TSCR,
+ 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
+ FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Bit Counter", FSL_XCVR_RX_DPTH_BCR,
+ 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
+ FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Bit Count Timestamp", FSL_XCVR_RX_DPTH_BCTR,
+ 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
+ FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Latched Timestamp Counter", FSL_XCVR_RX_DPTH_BCRR,
+ 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
+};
+
static const struct fsl_xcvr_pll_conf {
u8 mfi; /* min=0x18, max=0x38 */
u32 mfn; /* signed int, 2's compl., min=0x3FFF0000, max=0x00010000 */
@@ -115,10 +167,17 @@ static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol,
struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
+ int val = snd_soc_enum_item_to_val(e, item[0]);
+ int ret;
- xcvr->arc_mode = snd_soc_enum_item_to_val(e, item[0]);
+ if (val < 0 || val > 1)
+ return -EINVAL;
- return 0;
+ ret = (xcvr->arc_mode != val);
+
+ xcvr->arc_mode = val;
+
+ return ret;
}
static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol,
@@ -218,10 +277,17 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol,
struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
+ int val = snd_soc_enum_item_to_val(e, item[0]);
struct snd_soc_card *card = dai->component->card;
struct snd_soc_pcm_runtime *rtd;
+ int ret;
- xcvr->mode = snd_soc_enum_item_to_val(e, item[0]);
+ if (val < FSL_XCVR_MODE_SPDIF || val > FSL_XCVR_MODE_EARC)
+ return -EINVAL;
+
+ ret = (xcvr->mode != val);
+
+ xcvr->mode = val;
fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
(xcvr->mode == FSL_XCVR_MODE_ARC));
@@ -231,7 +297,7 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol,
rtd = snd_soc_get_pcm_runtime(card, card->dai_link);
rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count =
(xcvr->mode == FSL_XCVR_MODE_SPDIF ? 1 : 0);
- return 0;
+ return ret;
}
static int fsl_xcvr_mode_get(struct snd_kcontrol *kcontrol,
@@ -1070,8 +1136,20 @@ static struct snd_soc_dai_driver fsl_xcvr_dai = {
},
};
+static int fsl_xcvr_component_probe(struct snd_soc_component *component)
+{
+ struct fsl_xcvr *xcvr = snd_soc_component_get_drvdata(component);
+
+ snd_soc_component_init_regmap(component, xcvr->regmap);
+
+ return 0;
+}
+
static const struct snd_soc_component_driver fsl_xcvr_comp = {
.name = "fsl-xcvr-dai",
+ .probe = fsl_xcvr_component_probe,
+ .controls = fsl_xcvr_timestamp_ctrls,
+ .num_controls = ARRAY_SIZE(fsl_xcvr_timestamp_ctrls),
.legacy_dai_naming = 1,
};
diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h
index dade3945cc0c..0cc7945b1d9f 100644
--- a/sound/soc/fsl/fsl_xcvr.h
+++ b/sound/soc/fsl/fsl_xcvr.h
@@ -233,6 +233,24 @@
#define FSL_XCVR_TX_DPTH_CTRL_CLK_RATIO BIT(29)
#define FSL_XCVR_TX_DPTH_CTRL_TM_NO_PRE_BME GENMASK(31, 30)
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL_TSEN_SHIFT 0
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL_TSEN BIT(0)
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL_TSINC_SHIFT 1
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL_TSINC BIT(1)
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL_RBC_SHIFT 8
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL_RBC BIT(8)
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL_RTSC_SHIFT 9
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL_RTSC BIT(9)
+
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL_TSEN_SHIFT 0
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL_TSEN BIT(0)
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL_TSINC_SHIFT 1
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL_TSINC BIT(1)
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL_RBC_SHIFT 8
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL_RBC BIT(8)
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL_RTSC_SHIFT 9
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL_RTSC BIT(9)
+
#define FSL_XCVR_PHY_AI_CTRL_AI_RESETN BIT(15)
#define FSL_XCVR_PHY_AI_CTRL_AI_RWB BIT(31)
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index d51a3de493cb..e0fb4f8fd522 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -273,8 +273,8 @@ static const struct snd_soc_component_driver imx_soc_component_fiq = {
.prepare = snd_imx_pcm_prepare,
.trigger = snd_imx_pcm_trigger,
.pointer = snd_imx_pcm_pointer,
- .pcm_construct = snd_imx_pcm_new,
- .pcm_destruct = snd_imx_pcm_free,
+ .pcm_new = snd_imx_pcm_new,
+ .pcm_free = snd_imx_pcm_free,
};
int imx_pcm_fiq_init(struct platform_device *pdev,
diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c
index edab68ae8366..031e5272215d 100644
--- a/sound/soc/fsl/imx-pcm-rpmsg.c
+++ b/sound/soc/fsl/imx-pcm-rpmsg.c
@@ -624,7 +624,7 @@ static int imx_rpmsg_pcm_new(struct snd_soc_component *component,
static const struct snd_soc_component_driver imx_rpmsg_soc_component = {
.name = IMX_PCM_DRV_NAME,
- .pcm_construct = imx_rpmsg_pcm_new,
+ .pcm_new = imx_rpmsg_pcm_new,
.open = imx_rpmsg_pcm_open,
.close = imx_rpmsg_pcm_close,
.hw_params = imx_rpmsg_pcm_hw_params,
diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c
index 76a8e68c1b62..40e0043cfe15 100644
--- a/sound/soc/fsl/imx-rpmsg.c
+++ b/sound/soc/fsl/imx-rpmsg.c
@@ -30,6 +30,53 @@ static const struct snd_soc_dapm_widget imx_rpmsg_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Main MIC", NULL),
};
+static int imx_rpmsg_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);
+ snd_pcm_format_t format = params_format(params);
+ struct device *dev = rtd->card->dev;
+ unsigned int fmt = rtd->dai_link->dai_fmt;
+ bool format_is_dsd = false;
+ int ret;
+
+ switch (format) {
+ case SNDRV_PCM_FORMAT_DSD_U8:
+ case SNDRV_PCM_FORMAT_DSD_U16_LE:
+ case SNDRV_PCM_FORMAT_DSD_U16_BE:
+ case SNDRV_PCM_FORMAT_DSD_U32_LE:
+ case SNDRV_PCM_FORMAT_DSD_U32_BE:
+ format_is_dsd = true;
+ break;
+ default:
+ format_is_dsd = false;
+ break;
+ }
+
+ if (format_is_dsd)
+ fmt = (rtd->dai_link->dai_fmt & ~SND_SOC_DAIFMT_FORMAT_MASK) |
+ SND_SOC_DAIFMT_PDM;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dev, "failed to set cpu dai fmt: %d\n", ret);
+ return ret;
+ }
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dev, "failed to set codec dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops imx_rpmsg_ops = {
+ .hw_params = imx_rpmsg_hw_params,
+};
+
static int imx_rpmsg_late_probe(struct snd_soc_card *card)
{
struct imx_rpmsg *data = snd_soc_card_get_drvdata(card);
@@ -135,6 +182,7 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
data->dai.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC;
+ data->dai.ops = &imx_rpmsg_ops;
/*
* i.MX rpmsg sound cards work on codec slave mode. MCLK will be
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index a593a95aa532..56e2cf2f727b 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -307,7 +307,7 @@ static const struct snd_soc_component_driver mpc5200_audio_dma_component = {
.close = psc_dma_close,
.pointer = psc_dma_pointer,
.trigger = psc_dma_trigger,
- .pcm_construct = psc_dma_new,
+ .pcm_new = psc_dma_new,
};
int mpc5200_audio_dma_create(struct platform_device *op)
@@ -326,7 +326,7 @@ int mpc5200_audio_dma_create(struct platform_device *op)
dev_err(&op->dev, "Missing reg property\n");
return -ENODEV;
}
- regs = ioremap(res.start, resource_size(&res));
+ regs = devm_ioremap(&op->dev, res.start, resource_size(&res));
if (!regs) {
dev_err(&op->dev, "Could not map registers\n");
return -ENODEV;
@@ -334,10 +334,8 @@ int mpc5200_audio_dma_create(struct platform_device *op)
/* Allocate and initialize the driver private data */
psc_dma = kzalloc_obj(*psc_dma);
- if (!psc_dma) {
- ret = -ENOMEM;
- goto out_unmap;
- }
+ if (!psc_dma)
+ return -ENOMEM;
/* Get the PSC ID */
prop = of_get_property(op->dev.of_node, "cell-index", &size);
@@ -424,8 +422,6 @@ out_irq:
free_irq(psc_dma->playback.irq, &psc_dma->playback);
out_free:
kfree(psc_dma);
-out_unmap:
- iounmap(regs);
return ret;
}
EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
@@ -444,7 +440,6 @@ int mpc5200_audio_dma_destroy(struct platform_device *op)
free_irq(psc_dma->capture.irq, &psc_dma->capture);
free_irq(psc_dma->playback.irq, &psc_dma->playback);
- iounmap(psc_dma->psc_regs);
kfree(psc_dma);
dev_set_drvdata(&op->dev, NULL);
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 8a5f41704739..18ce4ee06350 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -76,7 +76,7 @@ static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
{
struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc);
- if (dai && (dai->component->driver->pcm_construct ||
+ if (dai && (dai->component->driver->pcm_new ||
(dai->driver->ops && dai->driver->ops->pcm_new)))
return true;
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 89d694c2cbdd..e5cb602fd248 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -468,6 +468,7 @@ int simple_util_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *sdai;
struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *props = runtime_simple_priv_to_props(priv, rtd);
+ enum simple_util_sysclk_order order = props->sysclk_order;
unsigned int mclk, mclk_fs = 0;
int i, ret;
@@ -501,18 +502,36 @@ int simple_util_hw_params(struct snd_pcm_substream *substream,
goto end;
}
- for_each_rtd_codec_dais(rtd, i, sdai) {
- pdai = simple_props_to_dai_codec(props, i);
- ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction);
- if (ret && ret != -ENOTSUPP)
- goto end;
- }
+ if (order == SIMPLE_SYSCLK_ORDER_CPU_FIRST) {
+ /* CPU first */
+ for_each_rtd_cpu_dais(rtd, i, sdai) {
+ pdai = simple_props_to_dai_cpu(props, i);
+ ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction);
+ if (ret && ret != -ENOTSUPP)
+ goto end;
+ }
- for_each_rtd_cpu_dais(rtd, i, sdai) {
- pdai = simple_props_to_dai_cpu(props, i);
- ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction);
- if (ret && ret != -ENOTSUPP)
- goto end;
+ for_each_rtd_codec_dais(rtd, i, sdai) {
+ pdai = simple_props_to_dai_codec(props, i);
+ ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction);
+ if (ret && ret != -ENOTSUPP)
+ goto end;
+ }
+ } else {
+ /* default: codec first */
+ for_each_rtd_codec_dais(rtd, i, sdai) {
+ pdai = simple_props_to_dai_codec(props, i);
+ ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction);
+ if (ret && ret != -ENOTSUPP)
+ goto end;
+ }
+
+ for_each_rtd_cpu_dais(rtd, i, sdai) {
+ pdai = simple_props_to_dai_cpu(props, i);
+ ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction);
+ if (ret && ret != -ENOTSUPP)
+ goto end;
+ }
}
}
@@ -699,7 +718,7 @@ void simple_util_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
int is_single_links)
{
/*
- * In soc_bind_dai_link() will check cpu name after
+ * In snd_soc_add_pcm_runtime() will check cpu name after
* of_node matching if dai_link has cpu_dai_name.
* but, it will never match if name was created by
* fmt_single_name() remove cpu_dai_name if cpu_args
@@ -1109,7 +1128,9 @@ int graph_util_parse_dai(struct simple_util_priv *priv, struct device_node *ep,
struct device *dev = simple_priv_to_dev(priv);
struct device_node *node;
struct of_phandle_args args = {};
+ struct snd_soc_dai_link_component resolved_dlc = {};
struct snd_soc_dai *dai;
+ const char *fallback_dai_name;
int ret;
if (!ep)
@@ -1133,39 +1154,31 @@ int graph_util_parse_dai(struct simple_util_priv *priv, struct device_node *ep,
dlc->of_node = node;
dlc->dai_name = dai_name;
dlc->dai_args = dai_args;
+ } else {
+ /* Get dai->name */
+ args.np = node;
+ args.args[0] = graph_get_dai_id(ep);
+ args.args_count = (of_graph_get_endpoint_count(node) > 1);
- goto parse_dai_end;
- }
+ ret = snd_soc_get_dlc(&args, &resolved_dlc);
+ if (ret < 0)
+ goto err;
- /* Get dai->name */
- args.np = node;
- args.args[0] = graph_get_dai_id(ep);
- args.args_count = (of_graph_get_endpoint_count(node) > 1);
+ /* Keep fallback dai_name valid across component rebind */
+ fallback_dai_name = resolved_dlc.dai_name;
+ if (fallback_dai_name) {
+ fallback_dai_name = devm_kstrdup_const(dev, fallback_dai_name,
+ GFP_KERNEL);
+ ret = -ENOMEM;
+ if (!fallback_dai_name)
+ goto err;
+ }
- /*
- * FIXME
- *
- * Here, dlc->dai_name is pointer to CPU/Codec DAI name.
- * If user unbinded CPU or Codec driver, but not for Sound Card,
- * dlc->dai_name is keeping unbinded CPU or Codec
- * driver's pointer.
- *
- * If user re-bind CPU or Codec driver again, ALSA SoC will try
- * to rebind Card via snd_soc_try_rebind_card(), but because of
- * above reason, it might can't bind Sound Card.
- * Because Sound Card is pointing to released dai_name pointer.
- *
- * To avoid this rebind Card issue,
- * 1) It needs to alloc memory to keep dai_name eventhough
- * CPU or Codec driver was unbinded, or
- * 2) user need to rebind Sound Card everytime
- * if he unbinded CPU or Codec.
- */
- ret = snd_soc_get_dlc(&args, dlc);
- if (ret < 0)
- goto err;
+ dlc->of_node = resolved_dlc.of_node;
+ dlc->dai_name = fallback_dai_name;
+ dlc->dai_args = resolved_dlc.dai_args;
+ }
-parse_dai_end:
if (is_single_link)
*is_single_link = of_graph_get_endpoint_count(node) == 1;
ret = 0;
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 06638f9a74b8..b24ba1330896 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -48,7 +48,8 @@ static int simple_parse_platform(struct simple_util_priv *priv,
/*
* Get node via "sound-dai = <&phandle port>"
- * it will be used as xxx_of_node on soc_bind_dai_link()
+ * It will be used as the of_node for component matching during
+ * snd_soc_add_pcm_runtime().
*/
ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
if (ret)
@@ -68,7 +69,9 @@ static int simple_parse_dai(struct simple_util_priv *priv,
{
struct device *dev = simple_priv_to_dev(priv);
struct of_phandle_args args;
+ struct snd_soc_dai_link_component resolved_dlc = {};
struct snd_soc_dai *dai;
+ const char *fallback_dai_name;
int ret;
if (!node)
@@ -76,7 +79,8 @@ static int simple_parse_dai(struct simple_util_priv *priv,
/*
* Get node via "sound-dai = <&phandle port>"
- * it will be used as xxx_of_node on soc_bind_dai_link()
+ * It will be used as the of_node for component matching during
+ * snd_soc_add_pcm_runtime().
*/
ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
if (ret)
@@ -92,34 +96,28 @@ static int simple_parse_dai(struct simple_util_priv *priv,
dlc->dai_args = snd_soc_copy_dai_args(dev, &args);
if (!dlc->dai_args)
goto end;
+ } else {
+ ret = snd_soc_get_dlc(&args, &resolved_dlc);
+ if (ret < 0)
+ goto end;
- goto parse_dai_end;
- }
+ /* Keep fallback dai_name valid across component rebind */
+ fallback_dai_name = resolved_dlc.dai_name;
+ if (fallback_dai_name) {
+ fallback_dai_name = devm_kstrdup_const(dev, fallback_dai_name,
+ GFP_KERNEL);
+ ret = -ENOMEM;
+ if (!fallback_dai_name) {
+ of_node_put(resolved_dlc.of_node);
+ goto end;
+ }
+ }
- /*
- * FIXME
- *
- * Here, dlc->dai_name is pointer to CPU/Codec DAI name.
- * If user unbinded CPU or Codec driver, but not for Sound Card,
- * dlc->dai_name is keeping unbinded CPU or Codec
- * driver's pointer.
- *
- * If user re-bind CPU or Codec driver again, ALSA SoC will try
- * to rebind Card via snd_soc_try_rebind_card(), but because of
- * above reason, it might can't bind Sound Card.
- * Because Sound Card is pointing to released dai_name pointer.
- *
- * To avoid this rebind Card issue,
- * 1) It needs to alloc memory to keep dai_name eventhough
- * CPU or Codec driver was unbinded, or
- * 2) user need to rebind Sound Card everytime
- * if he unbinded CPU or Codec.
- */
- ret = snd_soc_get_dlc(&args, dlc);
- if (ret < 0)
- goto end;
+ dlc->of_node = resolved_dlc.of_node;
+ dlc->dai_name = fallback_dai_name;
+ dlc->dai_args = resolved_dlc.dai_args;
+ }
-parse_dai_end:
if (is_single_link)
*is_single_link = !args.args_count;
ret = 0;
diff --git a/sound/soc/generic/test-component.c b/sound/soc/generic/test-component.c
index 2e49066dedd4..fc40d024152e 100644
--- a/sound/soc/generic/test-component.c
+++ b/sound/soc/generic/test-component.c
@@ -273,8 +273,8 @@ static int test_component_resume(struct snd_soc_component *component)
}
#define PREALLOC_BUFFER (32 * 1024)
-static int test_component_pcm_construct(struct snd_soc_component *component,
- struct snd_soc_pcm_runtime *rtd)
+static int test_component_pcm_new(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtd)
{
mile_stone(component);
@@ -287,8 +287,8 @@ static int test_component_pcm_construct(struct snd_soc_component *component,
return 0;
}
-static void test_component_pcm_destruct(struct snd_soc_component *component,
- struct snd_pcm *pcm)
+static void test_component_pcm_free(struct snd_soc_component *component,
+ struct snd_pcm *pcm)
{
mile_stone(component);
}
@@ -562,7 +562,7 @@ static int test_driver_probe(struct platform_device *pdev)
if (adata->is_cpu) {
cdriv->name = "test_cpu";
- cdriv->pcm_construct = test_component_pcm_construct;
+ cdriv->pcm_new = test_component_pcm_new;
cdriv->pointer = test_component_pointer;
cdriv->trigger = test_component_trigger;
cdriv->legacy_dai_naming = 1;
@@ -597,7 +597,7 @@ static int test_driver_probe(struct platform_device *pdev)
cdriv->be_hw_params_fixup = test_component_be_hw_params_fixup;
if (adata->is_cpu)
- cdriv->pcm_destruct = test_component_pcm_destruct;
+ cdriv->pcm_free = test_component_pcm_free;
}
i = 0;
diff --git a/sound/soc/google/chv3-i2s.c b/sound/soc/google/chv3-i2s.c
index 0ff24653d49f..fd12cedfe1c9 100644
--- a/sound/soc/google/chv3-i2s.c
+++ b/sound/soc/google/chv3-i2s.c
@@ -163,8 +163,8 @@ static int chv3_dma_close(struct snd_soc_component *component,
return 0;
}
-static int chv3_dma_pcm_construct(struct snd_soc_component *component,
- struct snd_soc_pcm_runtime *rtd)
+static int chv3_dma_pcm_new(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtd)
{
struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
struct snd_pcm_substream *substream;
@@ -271,7 +271,7 @@ static const struct snd_soc_component_driver chv3_i2s_comp = {
.name = "chv3-i2s-comp",
.open = chv3_dma_open,
.close = chv3_dma_close,
- .pcm_construct = chv3_dma_pcm_construct,
+ .pcm_new = chv3_dma_pcm_new,
.hw_params = chv3_dma_hw_params,
.prepare = chv3_dma_prepare,
.pointer = chv3_dma_pointer,
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index 67caea39b557..f074af2499c8 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -707,7 +707,7 @@ static const struct snd_soc_component_driver sst_soc_platform_drv = {
.pointer = sst_soc_pointer,
.delay = sst_soc_delay,
.compress_ops = &sst_platform_compress_ops,
- .pcm_construct = sst_soc_pcm_new,
+ .pcm_new = sst_soc_pcm_new,
};
static int sst_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index d53c2f76fcd4..797b9c9163b4 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -1349,8 +1349,8 @@ static int avs_component_mmap(struct snd_soc_component *component,
#define MAX_PREALLOC_SIZE (32 * 1024 * 1024)
-static int avs_component_construct(struct snd_soc_component *component,
- struct snd_soc_pcm_runtime *rtd)
+static int avs_component_new(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_pcm *pcm = rtd->pcm;
@@ -1377,7 +1377,7 @@ static struct snd_soc_component_driver avs_component_driver = {
.open = avs_component_open,
.pointer = avs_component_pointer,
.mmap = avs_component_mmap,
- .pcm_construct = avs_component_construct,
+ .pcm_new = avs_component_new,
.module_get_upon_open = 1, /* increment refcount when a pcm is opened */
.topology_name_prefix = "intel/avs",
};
@@ -1755,7 +1755,7 @@ static struct snd_soc_component_driver avs_hda_component_driver = {
.open = avs_component_hda_open,
.pointer = avs_component_pointer,
.mmap = avs_component_mmap,
- .pcm_construct = avs_component_construct,
+ .pcm_new = avs_component_new,
/*
* hda platform component's probe() is dependent on
* codec->pcm_list_head, it needs to be initialized after codec
diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c
index 74096236984a..099119ad28b3 100644
--- a/sound/soc/intel/avs/probes.c
+++ b/sound/soc/intel/avs/probes.c
@@ -144,7 +144,7 @@ static int avs_probe_compr_set_params(struct snd_compr_stream *cstream,
ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
if (ret < 0)
return ret;
- bps = snd_pcm_format_physical_width(params->codec.format);
+ bps = snd_pcm_format_physical_width((__force snd_pcm_format_t)params->codec.format);
if (bps < 0)
return bps;
format_val = snd_hdac_stream_format(params->codec.ch_out, bps, params->codec.sample_rate);
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 103e0b445603..40da3eea5fa7 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -285,10 +285,12 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
if (SND_SOC_DAPM_EVENT_ON(event)) {
ret = clk_prepare_enable(priv->mclk);
if (ret < 0) {
- dev_err(card->dev, "could not configure MCLK state\n");
+ dev_err(card->dev, "could not configure MCLK state: %d\n", ret);
return ret;
}
ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000);
+ if (ret < 0)
+ clk_disable_unprepare(priv->mclk);
} else {
/*
* Set codec clock source to internal clock before
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index 68cf463f1d50..62cb4856c797 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -205,10 +205,12 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
if (SND_SOC_DAPM_EVENT_ON(event)) {
ret = clk_prepare_enable(priv->mclk);
if (ret < 0) {
- dev_err(card->dev, "could not configure MCLK state");
+ dev_err(card->dev, "could not configure MCLK state: %d\n", ret);
return ret;
}
ret = byt_rt5651_prepare_and_enable_pll1(codec_dai, 48000, 50);
+ if (ret < 0)
+ clk_disable_unprepare(priv->mclk);
} else {
/*
* Set codec clock source to internal clock before
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index 359723f2700e..fd4cefd298d2 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -67,7 +67,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
ret = clk_prepare_enable(ctx->mclk);
if (ret < 0) {
dev_err(card->dev,
- "could not configure MCLK state");
+ "could not configure MCLK state: %d\n", ret);
return ret;
}
}
@@ -77,6 +77,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
CHT_PLAT_CLK_3_HZ, 48000 * 512);
if (ret < 0) {
dev_err(card->dev, "can't set codec pll: %d\n", ret);
+ if (ctx->mclk)
+ clk_disable_unprepare(ctx->mclk);
return ret;
}
@@ -85,6 +87,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
48000 * 512, SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
+ if (ctx->mclk)
+ clk_disable_unprepare(ctx->mclk);
return ret;
}
} else {
diff --git a/sound/soc/intel/boards/ehl_rt5660.c b/sound/soc/intel/boards/ehl_rt5660.c
index c40cd9fb1a26..7de39bc1e763 100644
--- a/sound/soc/intel/boards/ehl_rt5660.c
+++ b/sound/soc/intel/boards/ehl_rt5660.c
@@ -23,10 +23,8 @@
#include "hda_dsp_common.h"
#include "../../codecs/rt5660.h"
-#define DUAL_CHANNEL 2
#define HDMI_LINK_START 3
#define HDMI_LINE_END 6
-#define NAME_SIZE 32
#define IDISP_CODEC_MASK 0x4
struct sof_card_private {
diff --git a/sound/soc/intel/catpt/Makefile b/sound/soc/intel/catpt/Makefile
index f5f6a7e956ce..e8316e33b820 100644
--- a/sound/soc/intel/catpt/Makefile
+++ b/sound/soc/intel/catpt/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
snd-soc-catpt-y := device.o dsp.o loader.o ipc.o messages.o pcm.o sysfs.o
# tell define_trace.h where to find the trace header
diff --git a/sound/soc/intel/catpt/core.h b/sound/soc/intel/catpt/core.h
index df8a5fd95e13..7e479ef89ad0 100644
--- a/sound/soc/intel/catpt/core.h
+++ b/sound/soc/intel/catpt/core.h
@@ -96,7 +96,7 @@ struct catpt_dev {
struct catpt_module_type modules[CATPT_MODULE_COUNT];
struct catpt_ssp_device_format devfmt[CATPT_SSP_COUNT];
struct list_head stream_list;
- spinlock_t list_lock;
+ struct mutex stream_mutex;
struct mutex clk_mutex;
struct catpt_dx_context dx_ctx;
diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c
index 0b3f20e384c7..ca4fd18b6a6e 100644
--- a/sound/soc/intel/catpt/device.c
+++ b/sound/soc/intel/catpt/device.c
@@ -226,7 +226,7 @@ static void catpt_dev_init(struct catpt_dev *cdev, struct device *dev,
cdev->spec = spec;
init_completion(&cdev->fw_ready);
INIT_LIST_HEAD(&cdev->stream_list);
- spin_lock_init(&cdev->list_lock);
+ mutex_init(&cdev->stream_mutex);
mutex_init(&cdev->clk_mutex);
/*
diff --git a/sound/soc/intel/catpt/ipc.c b/sound/soc/intel/catpt/ipc.c
index 5a01a9afb26e..2e3b7a5cbb9b 100644
--- a/sound/soc/intel/catpt/ipc.c
+++ b/sound/soc/intel/catpt/ipc.c
@@ -5,6 +5,7 @@
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//
+#include <linux/cleanup.h>
#include <linux/irqreturn.h>
#include "core.h"
#include "messages.h"
@@ -151,6 +152,8 @@ catpt_dsp_notify_stream(struct catpt_dev *cdev, union catpt_notify_msg msg)
struct catpt_notify_position pos;
struct catpt_notify_glitch glitch;
+ guard(mutex)(&cdev->stream_mutex);
+
stream = catpt_stream_find(cdev, msg.stream_hw_id);
if (!stream) {
dev_warn(cdev->dev, "notify %d for non-existent stream %d\n",
diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c
index dc7afe587e6f..432cb1f0ab4e 100644
--- a/sound/soc/intel/catpt/loader.c
+++ b/sound/soc/intel/catpt/loader.c
@@ -90,6 +90,7 @@ int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan)
{
struct catpt_stream_runtime *stream;
+ /* Lockless as no streams can be added or removed during D3 -> D0 transition. */
list_for_each_entry(stream, &cdev->stream_list, node) {
u32 off, size;
int ret;
@@ -180,6 +181,7 @@ catpt_restore_streams_context(struct catpt_dev *cdev, struct dma_chan *chan)
{
struct catpt_stream_runtime *stream;
+ /* Lockless as no streams can be added or removed during D3 -> D0 transition. */
list_for_each_entry(stream, &cdev->stream_list, node) {
u32 off, size;
int ret;
diff --git a/sound/soc/intel/catpt/messages.h b/sound/soc/intel/catpt/messages.h
index a634943eb669..fcc9f1b46bc2 100644
--- a/sound/soc/intel/catpt/messages.h
+++ b/sound/soc/intel/catpt/messages.h
@@ -69,6 +69,7 @@ struct catpt_fw_version {
int catpt_ipc_get_fw_version(struct catpt_dev *cdev,
struct catpt_fw_version *version);
+/* PIN_IDs represent both, individual streams and the general mixer. */
enum catpt_pin_id {
CATPT_PIN_ID_SYSTEM = 0,
CATPT_PIN_ID_REFERENCE = 1,
@@ -79,6 +80,8 @@ enum catpt_pin_id {
CATPT_PIN_ID_MIXER = 7,
CATPT_PIN_ID_BLUETOOTH_CAPTURE = 8,
CATPT_PIN_ID_BLUETOOTH_RENDER = 9,
+ /* 10 is reserved */
+ CATPT_PIN_ID_INVALID = 11,
};
enum catpt_path_id {
diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c
index 2c5ea4e0ff3d..7b2bab12c707 100644
--- a/sound/soc/intel/catpt/pcm.c
+++ b/sound/soc/intel/catpt/pcm.c
@@ -5,6 +5,7 @@
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//
+#include <linux/cleanup.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
@@ -97,12 +98,12 @@ catpt_get_stream_template(struct snd_pcm_substream *substream)
return catpt_topology[type];
}
+/* Caller responsible for holding ->stream_mutex. */
struct catpt_stream_runtime *
catpt_stream_find(struct catpt_dev *cdev, u8 stream_hw_id)
{
struct catpt_stream_runtime *pos, *result = NULL;
- spin_lock(&cdev->list_lock);
list_for_each_entry(pos, &cdev->stream_list, node) {
if (pos->info.stream_hw_id == stream_hw_id) {
result = pos;
@@ -110,40 +111,53 @@ catpt_stream_find(struct catpt_dev *cdev, u8 stream_hw_id)
}
}
- spin_unlock(&cdev->list_lock);
return result;
}
-static void catpt_stream_read_position(struct catpt_dev *cdev,
- struct catpt_stream_runtime *stream, u32 *pos)
+/* Caller responsible for holding ->stream_mutex. */
+static u8 catpt_stream_hw_id(struct catpt_dev *cdev, enum catpt_pin_id pin_id)
{
- memcpy_fromio(pos, cdev->lpe_ba + stream->info.read_pos_regaddr, sizeof(*pos));
+ struct catpt_stream_runtime *stream;
+
+ switch (pin_id) {
+ default:
+ stream = catpt_stream_find(cdev, pin_id);
+ if (stream)
+ return stream->info.stream_hw_id;
+ break;
+ case CATPT_PIN_ID_MIXER:
+ if (!list_empty(&cdev->stream_list))
+ return cdev->mixer.mixer_hw_id;
+ break;
+ }
+
+ return CATPT_PIN_ID_INVALID;
}
-static u32 catpt_stream_volume(struct catpt_dev *cdev,
- struct catpt_stream_runtime *stream, u32 channel)
+/* Caller responsible for holding ->stream_mutex. */
+static u32 *catpt_stream_volume_regs(struct catpt_dev *cdev, enum catpt_pin_id pin_id)
{
- u32 volume, offset;
+ struct catpt_stream_runtime *stream;
- if (channel >= CATPT_CHANNELS_MAX)
- channel = 0;
+ switch (pin_id) {
+ case CATPT_PIN_ID_MIXER:
+ if (!list_empty(&cdev->stream_list))
+ return &cdev->mixer.volume_regaddr[0];
+ break;
+ default:
+ stream = catpt_stream_find(cdev, pin_id);
+ if (stream)
+ return &stream->info.volume_regaddr[0];
+ break;
+ }
- offset = stream->info.volume_regaddr[channel];
- memcpy_fromio(&volume, cdev->lpe_ba + offset, sizeof(volume));
- return volume;
+ return NULL;
}
-static u32 catpt_mixer_volume(struct catpt_dev *cdev,
- struct catpt_mixer_stream_info *info, u32 channel)
+static void catpt_stream_read_position(struct catpt_dev *cdev,
+ struct catpt_stream_runtime *stream, u32 *pos)
{
- u32 volume, offset;
-
- if (channel >= CATPT_CHANNELS_MAX)
- channel = 0;
-
- offset = info->volume_regaddr[channel];
- memcpy_fromio(&volume, cdev->lpe_ba + offset, sizeof(volume));
- return volume;
+ memcpy_fromio(pos, cdev->lpe_ba + stream->info.read_pos_regaddr, sizeof(*pos));
}
static void catpt_arrange_page_table(struct snd_pcm_substream *substream,
@@ -286,10 +300,6 @@ static int catpt_dai_startup(struct snd_pcm_substream *substream,
INIT_LIST_HEAD(&stream->node);
snd_soc_dai_set_dma_data(dai, substream, stream);
- spin_lock(&cdev->list_lock);
- list_add_tail(&stream->node, &cdev->stream_list);
- spin_unlock(&cdev->list_lock);
-
return 0;
err_request:
@@ -307,10 +317,6 @@ static void catpt_dai_shutdown(struct snd_pcm_substream *substream,
stream = snd_soc_dai_get_dma_data(dai, substream);
- spin_lock(&cdev->list_lock);
- list_del(&stream->node);
- spin_unlock(&cdev->list_lock);
-
release_resource(stream->persistent);
kfree(stream->persistent);
catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask);
@@ -322,46 +328,62 @@ static void catpt_dai_shutdown(struct snd_pcm_substream *substream,
static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol);
-static int catpt_dai_apply_usettings(struct snd_soc_dai *dai,
- struct catpt_stream_runtime *stream)
+struct catpt_control_data {
+ enum catpt_pin_id pin_id;
+ long volumes[CATPT_CHANNELS_MAX];
+};
+
+static int catpt_apply_volume(struct catpt_dev *cdev, struct snd_soc_card *card, const char *name)
+{
+ struct snd_kcontrol *kctl = snd_ctl_find_id_mixer(card->snd_card, name);
+ struct catpt_control_data *data;
+
+ if (!kctl)
+ return -ENOENT;
+ data = (struct catpt_control_data *)kctl->private_value;
+
+ return catpt_set_dspvol(cdev, data->pin_id, data->volumes);
+}
+
+static int catpt_apply_mute(struct catpt_dev *cdev, struct snd_soc_card *card)
+{
+ struct snd_kcontrol *kctl = snd_ctl_find_id_mixer(card->snd_card, "Loopback Mute");
+ bool mute;
+ int ret;
+
+ if (!kctl)
+ return -ENOENT;
+ mute = *(bool *)kctl->private_value;
+
+ ret = catpt_ipc_mute_loopback(cdev, CATPT_PIN_ID_REFERENCE, mute);
+ return CATPT_IPC_RET(ret);
+}
+
+static int catpt_apply_controls(struct catpt_dev *cdev, struct snd_soc_card *card,
+ struct catpt_stream_runtime *stream)
{
- struct snd_soc_component *component = dai->component;
- struct snd_kcontrol *pos;
- struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
- const char *name;
int ret;
- u32 id = stream->info.stream_hw_id;
- /* only selected streams have individual controls */
- switch (id) {
+ /* Update the master volume when the first stream is opened. */
+ if (list_empty(&cdev->stream_list)) {
+ ret = catpt_apply_volume(cdev, card, "Master Playback Volume");
+ if (ret)
+ return ret;
+ }
+
+ /* Only selected streams have individual controls. */
+ switch (stream->info.stream_hw_id) {
case CATPT_PIN_ID_OFFLOAD1:
- name = "Media0 Playback Volume";
- break;
+ return catpt_apply_volume(cdev, card, "Media0 Playback Volume");
case CATPT_PIN_ID_OFFLOAD2:
- name = "Media1 Playback Volume";
- break;
+ return catpt_apply_volume(cdev, card, "Media1 Playback Volume");
case CATPT_PIN_ID_CAPTURE1:
- name = "Mic Capture Volume";
- break;
+ return catpt_apply_volume(cdev, card, "Mic Capture Volume");
case CATPT_PIN_ID_REFERENCE:
- name = "Loopback Mute";
- break;
+ return catpt_apply_mute(cdev, card);
default:
return 0;
}
-
- list_for_each_entry(pos, &component->card->snd_card->controls, list) {
- if (pos->private_data == component &&
- !strncmp(name, pos->id.name, sizeof(pos->id.name)))
- break;
- }
- if (list_entry_is_head(pos, &component->card->snd_card->controls, list))
- return -ENOENT;
-
- if (stream->template->type != CATPT_STRM_TYPE_LOOPBACK)
- return catpt_set_dspvol(cdev, id, (long *)pos->private_value);
- ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)pos->private_value);
- return CATPT_IPC_RET(ret);
}
static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
@@ -410,12 +432,15 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
if (ret)
return CATPT_IPC_RET(ret);
- ret = catpt_dai_apply_usettings(dai, stream);
+ guard(mutex)(&cdev->stream_mutex);
+
+ ret = catpt_apply_controls(cdev, dai->component->card, stream);
if (ret) {
catpt_ipc_free_stream(cdev, stream->info.stream_hw_id);
return ret;
}
+ list_add_tail(&stream->node, &cdev->stream_list);
stream->allocated = true;
return 0;
}
@@ -430,6 +455,10 @@ static int catpt_dai_hw_free(struct snd_pcm_substream *substream,
if (!stream->allocated)
return 0;
+ mutex_lock(&cdev->stream_mutex);
+ list_del(&stream->node);
+ mutex_unlock(&cdev->stream_mutex);
+
catpt_ipc_reset_stream(cdev, stream->info.stream_hw_id);
catpt_ipc_free_stream(cdev, stream->info.stream_hw_id);
@@ -574,8 +603,8 @@ static const struct snd_pcm_hardware catpt_pcm_hardware = {
.buffer_bytes_max = CATPT_BUFFER_MAX_SIZE,
};
-static int catpt_component_pcm_construct(struct snd_soc_component *component,
- struct snd_soc_pcm_runtime *rtm)
+static int catpt_component_pcm_new(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtm)
{
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
@@ -856,187 +885,91 @@ static int catpt_volume_info(struct snd_kcontrol *kcontrol,
return 0;
}
-static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int catpt_volume_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kctl);
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
- u32 dspvol;
- int ret;
+ struct catpt_control_data *data;
+ u32 dspvol, *regs;
+ long *uvolumes;
int i;
- ret = pm_runtime_resume_and_get(cdev->dev);
- if (ret)
- return ret;
+ data = (struct catpt_control_data *)kctl->private_value;
+ uvolumes = &uctl->value.integer.value[0];
- for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
- dspvol = catpt_mixer_volume(cdev, &cdev->mixer, i);
- ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol);
- }
+ guard(mutex)(&cdev->stream_mutex);
- pm_runtime_put_autosuspend(cdev->dev);
+ regs = catpt_stream_volume_regs(cdev, data->pin_id);
+ if (regs) {
+ for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
+ dspvol = readl(cdev->lpe_ba + regs[i]);
+ data->volumes[i] = dspvol_to_ctlvol(dspvol);
+ }
+ }
+ memcpy(uvolumes, data->volumes, sizeof(data->volumes));
return 0;
}
-static int catpt_mixer_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int catpt_volume_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kctl);
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
+ struct catpt_control_data *data;
+ u8 stream_hw_id;
+ long *uvolumes;
int ret;
- ret = pm_runtime_resume_and_get(cdev->dev);
- if (ret)
- return ret;
+ data = (struct catpt_control_data *)kctl->private_value;
+ uvolumes = &uctl->value.integer.value[0];
- ret = catpt_set_dspvol(cdev, cdev->mixer.mixer_hw_id,
- ucontrol->value.integer.value);
-
- pm_runtime_put_autosuspend(cdev->dev);
-
- return ret;
-}
-
-static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol,
- enum catpt_pin_id pin_id)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct catpt_stream_runtime *stream;
- struct catpt_dev *cdev = dev_get_drvdata(component->dev);
- long *ctlvol = (long *)kcontrol->private_value;
- u32 dspvol;
- int ret;
- int i;
-
- stream = catpt_stream_find(cdev, pin_id);
- if (!stream) {
- for (i = 0; i < CATPT_CHANNELS_MAX; i++)
- ucontrol->value.integer.value[i] = ctlvol[i];
+ if (!memcmp(data->volumes, uvolumes, sizeof(data->volumes)))
return 0;
- }
- ret = pm_runtime_resume_and_get(cdev->dev);
- if (ret)
- return ret;
+ guard(mutex)(&cdev->stream_mutex);
- for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
- dspvol = catpt_stream_volume(cdev, stream, i);
- ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol);
+ stream_hw_id = catpt_stream_hw_id(cdev, data->pin_id);
+ if (stream_hw_id != CATPT_PIN_ID_INVALID) {
+ ret = catpt_set_dspvol(cdev, stream_hw_id, uvolumes);
+ if (ret)
+ return ret;
}
- pm_runtime_put_autosuspend(cdev->dev);
-
- return 0;
+ memcpy(data->volumes, uvolumes, sizeof(data->volumes));
+ return 1;
}
-static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol,
- enum catpt_pin_id pin_id)
+static int catpt_loopback_mute_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct catpt_stream_runtime *stream;
- struct catpt_dev *cdev = dev_get_drvdata(component->dev);
- long *ctlvol = (long *)kcontrol->private_value;
- int ret, i;
-
- stream = catpt_stream_find(cdev, pin_id);
- if (!stream) {
- for (i = 0; i < CATPT_CHANNELS_MAX; i++)
- ctlvol[i] = ucontrol->value.integer.value[i];
- return 0;
- }
-
- ret = pm_runtime_resume_and_get(cdev->dev);
- if (ret)
- return ret;
-
- ret = catpt_set_dspvol(cdev, stream->info.stream_hw_id,
- ucontrol->value.integer.value);
-
- pm_runtime_put_autosuspend(cdev->dev);
-
- if (ret)
- return ret;
-
- for (i = 0; i < CATPT_CHANNELS_MAX; i++)
- ctlvol[i] = ucontrol->value.integer.value[i];
+ uctl->value.integer.value[0] = *(bool *)kctl->private_value;
return 0;
}
-static int catpt_offload1_volume_get(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *uctl)
+static int catpt_loopback_mute_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
{
- return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_OFFLOAD1);
-}
-
-static int catpt_offload1_volume_put(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *uctl)
-{
- return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_OFFLOAD1);
-}
-
-static int catpt_offload2_volume_get(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *uctl)
-{
- return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_OFFLOAD2);
-}
-
-static int catpt_offload2_volume_put(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *uctl)
-{
- return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_OFFLOAD2);
-}
-
-static int catpt_capture_volume_get(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *uctl)
-{
- return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_CAPTURE1);
-}
-
-static int catpt_capture_volume_put(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *uctl)
-{
- return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_CAPTURE1);
-}
-
-static int catpt_loopback_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = *(bool *)kcontrol->private_value;
- return 0;
-}
-
-static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct catpt_stream_runtime *stream;
+ struct snd_soc_component *component = snd_kcontrol_chip(kctl);
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
- bool mute;
+ bool *kmute, cmute;
+ u8 stream_hw_id;
int ret;
- mute = (bool)ucontrol->value.integer.value[0];
- stream = catpt_stream_find(cdev, CATPT_PIN_ID_REFERENCE);
- if (!stream) {
- *(bool *)kcontrol->private_value = mute;
- return 0;
- }
-
- ret = pm_runtime_resume_and_get(cdev->dev);
- if (ret)
- return ret;
+ kmute = (bool *)kctl->private_value;
+ cmute = (bool)uctl->value.integer.value[0];
- ret = catpt_ipc_mute_loopback(cdev, stream->info.stream_hw_id, mute);
+ if (*kmute == cmute)
+ return 0;
- pm_runtime_put_autosuspend(cdev->dev);
+ guard(mutex)(&cdev->stream_mutex);
- if (ret)
- return CATPT_IPC_RET(ret);
+ stream_hw_id = catpt_stream_hw_id(cdev, CATPT_PIN_ID_REFERENCE);
+ if (stream_hw_id != CATPT_PIN_ID_INVALID) {
+ ret = catpt_ipc_mute_loopback(cdev, stream_hw_id, cmute);
+ if (ret)
+ return CATPT_IPC_RET(ret);
+ }
- *(bool *)kcontrol->private_value = mute;
- return 0;
+ *kmute = cmute;
+ return 1;
}
static int catpt_waves_switch_get(struct snd_kcontrol *kcontrol,
@@ -1067,27 +1000,28 @@ static int catpt_waves_param_put(struct snd_kcontrol *kcontrol,
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(catpt_volume_tlv, -9000, 300, 1);
-#define CATPT_VOLUME_CTL(kname, sname) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = (kname), \
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
- SNDRV_CTL_ELEM_ACCESS_READWRITE, \
- .info = catpt_volume_info, \
- .get = catpt_##sname##_volume_get, \
- .put = catpt_##sname##_volume_put, \
- .tlv.p = catpt_volume_tlv, \
- .private_value = (unsigned long) \
- &(long[CATPT_CHANNELS_MAX]) {0} }
+#define CATPT_VOLUME_CTL(kname, pname) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = kname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = catpt_volume_info, \
+ .get = catpt_volume_get, \
+ .put = catpt_volume_put, \
+ .tlv.p = catpt_volume_tlv, \
+ .private_value = (unsigned long) \
+ &(struct catpt_control_data) { CATPT_PIN_ID_##pname } \
+}
static const struct snd_kcontrol_new component_kcontrols[] = {
/* Master volume (mixer stream) */
-CATPT_VOLUME_CTL("Master Playback Volume", mixer),
+CATPT_VOLUME_CTL("Master Playback Volume", MIXER),
/* Individual volume controls for offload and capture */
-CATPT_VOLUME_CTL("Media0 Playback Volume", offload1),
-CATPT_VOLUME_CTL("Media1 Playback Volume", offload2),
-CATPT_VOLUME_CTL("Mic Capture Volume", capture),
+CATPT_VOLUME_CTL("Media0 Playback Volume", OFFLOAD1),
+CATPT_VOLUME_CTL("Media1 Playback Volume", OFFLOAD2),
+CATPT_VOLUME_CTL("Mic Capture Volume", CAPTURE1),
SOC_SINGLE_BOOL_EXT("Loopback Mute", (unsigned long)&(bool[1]) {0},
- catpt_loopback_switch_get, catpt_loopback_switch_put),
+ catpt_loopback_mute_get, catpt_loopback_mute_put),
/* Enable or disable WAVES module */
SOC_SINGLE_BOOL_EXT("Waves Switch", 0,
catpt_waves_switch_get, catpt_waves_switch_put),
@@ -1122,7 +1056,7 @@ static const struct snd_soc_dapm_route component_routes[] = {
static const struct snd_soc_component_driver catpt_comp_driver = {
.name = "catpt-platform",
- .pcm_construct = catpt_component_pcm_construct,
+ .pcm_new = catpt_component_pcm_new,
.open = catpt_component_open,
.pointer = catpt_component_pointer,
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 ddd919847c1f..3b7818355ff6 100644
--- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
@@ -134,31 +134,6 @@ static const struct snd_soc_acpi_endpoint spk_6_endpoint = {
.group_id = 1,
};
-/*
- * Multi-function codecs with three endpoints created for
- * headset, amp and dmic functions.
- */
-static const struct snd_soc_acpi_endpoint rt_mf_endpoints[] = {
- {
- .num = 0,
- .aggregated = 0,
- .group_position = 0,
- .group_id = 0,
- },
- {
- .num = 1,
- .aggregated = 0,
- .group_position = 0,
- .group_id = 0,
- },
- {
- .num = 2,
- .aggregated = 0,
- .group_position = 0,
- .group_id = 0,
- },
-};
-
static const struct snd_soc_acpi_endpoint jack_dmic_endpoints[] = {
/* Jack Endpoint */
{
@@ -365,33 +340,6 @@ static const struct snd_soc_acpi_adr_device rt722_0_agg_adr[] = {
}
};
-static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = {
- {
- .adr = 0x000030025d072201ull,
- .num_endpoints = ARRAY_SIZE(rt_mf_endpoints),
- .endpoints = rt_mf_endpoints,
- .name_prefix = "rt722"
- }
-};
-
-static const struct snd_soc_acpi_adr_device rt722_1_single_adr[] = {
- {
- .adr = 0x000130025d072201ull,
- .num_endpoints = ARRAY_SIZE(rt_mf_endpoints),
- .endpoints = rt_mf_endpoints,
- .name_prefix = "rt722"
- }
-};
-
-static const struct snd_soc_acpi_adr_device rt722_3_single_adr[] = {
- {
- .adr = 0x000330025d072201ull,
- .num_endpoints = ARRAY_SIZE(rt_mf_endpoints),
- .endpoints = rt_mf_endpoints,
- .name_prefix = "rt722"
- }
-};
-
static const struct snd_soc_acpi_adr_device rt1320_1_group1_adr[] = {
{
.adr = 0x000130025D132001ull,
@@ -479,33 +427,6 @@ static const struct snd_soc_acpi_link_adr ptl_cs42l43_l2_cs35l56x6_l13[] = {
{}
};
-static const struct snd_soc_acpi_link_adr ptl_rt722_only[] = {
- {
- .mask = BIT(0),
- .num_adr = ARRAY_SIZE(rt722_0_single_adr),
- .adr_d = rt722_0_single_adr,
- },
- {}
-};
-
-static const struct snd_soc_acpi_link_adr ptl_rt722_l1[] = {
- {
- .mask = BIT(1),
- .num_adr = ARRAY_SIZE(rt722_1_single_adr),
- .adr_d = rt722_1_single_adr,
- },
- {}
-};
-
-static const struct snd_soc_acpi_link_adr ptl_rt722_l3[] = {
- {
- .mask = BIT(3),
- .num_adr = ARRAY_SIZE(rt722_3_single_adr),
- .adr_d = rt722_3_single_adr,
- },
- {}
-};
-
static const struct snd_soc_acpi_link_adr ptl_rt722_l0_rt1320_l23[] = {
{
.mask = BIT(0),
@@ -699,20 +620,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = {
.sof_tplg_filename = "sof-ptl-rt711.tplg",
},
{
- .link_mask = BIT(0),
- .links = ptl_rt722_only,
- .drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-ptl-rt722.tplg",
- .get_function_tplg_files = sof_sdw_get_tplg_files,
- },
- {
- .link_mask = BIT(1),
- .links = ptl_rt722_l1,
- .drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-ptl-rt722.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",
@@ -720,13 +627,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = {
.sof_tplg_filename = "sof-ptl-rt712-l3-rt1320-l3.tplg",
.get_function_tplg_files = sof_sdw_get_tplg_files,
},
- {
- .link_mask = BIT(3),
- .links = ptl_rt722_l3,
- .drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-ptl-rt722.tplg",
- .get_function_tplg_files = sof_sdw_get_tplg_files,
- },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ptl_sdw_machines);
diff --git a/sound/soc/intel/keembay/Makefile b/sound/soc/intel/keembay/Makefile
index 3da9a6f9ba2a..fe3d761743d9 100644
--- a/sound/soc/intel/keembay/Makefile
+++ b/sound/soc/intel/keembay/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
snd-soc-kmb_platform-y := \
kmb_platform.o
diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c
index 4ed71d11ad77..6659e8060ef3 100644
--- a/sound/soc/intel/keembay/kmb_platform.c
+++ b/sound/soc/intel/keembay/kmb_platform.c
@@ -388,7 +388,7 @@ static snd_pcm_uframes_t kmb_pcm_pointer(struct snd_soc_component *component,
static const struct snd_soc_component_driver kmb_component = {
.name = "kmb",
- .pcm_construct = kmb_platform_pcm_new,
+ .pcm_new = kmb_platform_pcm_new,
.open = kmb_pcm_open,
.trigger = kmb_pcm_trigger,
.pointer = kmb_pcm_pointer,
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index 036b42058272..bd09cb163e65 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -261,5 +261,5 @@ const struct snd_soc_component_driver kirkwood_soc_component = {
.hw_params = kirkwood_dma_hw_params,
.prepare = kirkwood_dma_prepare,
.pointer = kirkwood_dma_pointer,
- .pcm_construct = kirkwood_dma_new,
+ .pcm_new = kirkwood_dma_new,
};
diff --git a/sound/soc/loongson/loongson_dma.c b/sound/soc/loongson/loongson_dma.c
index f26b2951bc9c..a149b643175c 100644
--- a/sound/soc/loongson/loongson_dma.c
+++ b/sound/soc/loongson/loongson_dma.c
@@ -341,5 +341,5 @@ const struct snd_soc_component_driver loongson_i2s_component = {
.trigger = loongson_pcm_trigger,
.pointer = loongson_pcm_pointer,
.mmap = loongson_pcm_mmap,
- .pcm_construct = loongson_pcm_new,
+ .pcm_new = loongson_pcm_new,
};
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
index 938dd3d46b00..f2b39fc9ec81 100644
--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
@@ -149,7 +149,7 @@ static int mtk_afe_component_probe(struct snd_soc_component *component)
const struct snd_soc_component_driver mtk_afe_pcm_platform = {
.name = AFE_PCM_NAME,
.pointer = mtk_afe_pcm_pointer,
- .pcm_construct = mtk_afe_pcm_new,
+ .pcm_new = mtk_afe_pcm_new,
.probe = mtk_afe_component_probe,
};
EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform);
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c
index 085e993c650d..44a521c3a610 100644
--- a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c
@@ -2773,7 +2773,7 @@ static int mt8186_afe_component_probe(struct snd_soc_component *component)
static const struct snd_soc_component_driver mt8186_afe_component = {
.name = AFE_PCM_NAME,
- .pcm_construct = mtk_afe_pcm_new,
+ .pcm_new = mtk_afe_pcm_new,
.pointer = mtk_afe_pcm_pointer,
.probe = mt8186_afe_component_probe,
};
diff --git a/sound/soc/mediatek/mt8189/mt8189-afe-pcm.c b/sound/soc/mediatek/mt8189/mt8189-afe-pcm.c
index 166ece74270e..24b0c78815f6 100644
--- a/sound/soc/mediatek/mt8189/mt8189-afe-pcm.c
+++ b/sound/soc/mediatek/mt8189/mt8189-afe-pcm.c
@@ -2378,8 +2378,8 @@ static void mt8189_afe_pcm_free(struct snd_soc_component *component,
static const struct snd_soc_component_driver mt8189_afe_component = {
.name = AFE_PCM_NAME,
.probe = mt8189_afe_component_probe,
- .pcm_construct = mtk_afe_pcm_new,
- .pcm_destruct = mt8189_afe_pcm_free,
+ .pcm_new = mtk_afe_pcm_new,
+ .pcm_free = mt8189_afe_pcm_free,
.open = mt8189_afe_pcm_open,
.pointer = mtk_afe_pcm_pointer,
};
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
index 245f17411638..f1c0e612313d 100644
--- a/sound/soc/mxs/mxs-sgtl5000.c
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -157,13 +157,16 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "failed to parse audio-routing (%d)\n",
ret);
+ mxs_saif_put_mclk(0);
return ret;
}
}
ret = devm_snd_soc_register_card(&pdev->dev, card);
- if (ret)
+ if (ret) {
+ mxs_saif_put_mclk(0);
return dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n");
+ }
return 0;
}
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index c34bfa27a446..37bd8dbd541f 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -843,7 +843,7 @@ static struct snd_soc_dai_driver pxa_ssp_dai = {
static const struct snd_soc_component_driver pxa_ssp_component = {
.name = "pxa-ssp",
- .pcm_construct = pxa2xx_soc_pcm_new,
+ .pcm_new = pxa2xx_soc_pcm_new,
.open = pxa2xx_soc_pcm_open,
.close = pxa2xx_soc_pcm_close,
.hw_params = pxa2xx_soc_pcm_hw_params,
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index 109a4958d9c0..a0c672602918 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -198,7 +198,7 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
static const struct snd_soc_component_driver pxa_ac97_component = {
.name = "pxa-ac97",
- .pcm_construct = pxa2xx_soc_pcm_new,
+ .pcm_new = pxa2xx_soc_pcm_new,
.open = pxa2xx_soc_pcm_open,
.close = pxa2xx_soc_pcm_close,
.hw_params = pxa2xx_soc_pcm_hw_params,
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 849fbf176a70..f6ada6cffc88 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -356,7 +356,7 @@ static struct snd_soc_dai_driver pxa_i2s_dai = {
static const struct snd_soc_component_driver pxa_i2s_component = {
.name = "pxa-i2s",
- .pcm_construct = pxa2xx_soc_pcm_new,
+ .pcm_new = pxa2xx_soc_pcm_new,
.open = pxa2xx_soc_pcm_open,
.close = pxa2xx_soc_pcm_close,
.hw_params = pxa2xx_soc_pcm_hw_params,
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index 9d6c41f775e5..ff0fbb61dccd 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -18,7 +18,7 @@
#include <sound/dmaengine_pcm.h>
static const struct snd_soc_component_driver pxa2xx_soc_platform = {
- .pcm_construct = pxa2xx_soc_pcm_new,
+ .pcm_new = pxa2xx_soc_pcm_new,
.open = pxa2xx_soc_pcm_open,
.close = pxa2xx_soc_pcm_close,
.hw_params = pxa2xx_soc_pcm_hw_params,
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index 7ee60a58a336..cf1f3a767cee 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -120,6 +120,12 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
link->id = args.args[0];
+ if (link->id >= LPASS_MAX_PORT) {
+ dev_err(dev, "%s: Invalid cpu dai id %d\n", link->name, link->id);
+ ret = -EINVAL;
+ goto err;
+ }
+
if (platform) {
link->platforms->of_node = of_parse_phandle(platform,
"sound-dai",
diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h
index 1b8d3f90bffa..ee6662885593 100644
--- a/sound/soc/qcom/common.h
+++ b/sound/soc/qcom/common.h
@@ -4,8 +4,11 @@
#ifndef __QCOM_SND_COMMON_H__
#define __QCOM_SND_COMMON_H__
+#include <dt-bindings/sound/qcom,q6afe.h>
#include <sound/soc.h>
+#define LPASS_MAX_PORT (SENARY_MI2S_TX + 1)
+
int qcom_snd_parse_of(struct snd_soc_card *card);
int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_jack *jack, bool *jack_setup);
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index ce6896cc015d..e162627d6f86 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -1268,7 +1268,7 @@ static const struct snd_soc_component_driver lpass_component_driver = {
.trigger = lpass_platform_pcmops_trigger,
.pointer = lpass_platform_pcmops_pointer,
.mmap = lpass_platform_pcmops_mmap,
- .pcm_construct = lpass_platform_pcm_new,
+ .pcm_new = lpass_platform_pcm_new,
.suspend = lpass_platform_pcmops_suspend,
.resume = lpass_platform_pcmops_resume,
.copy = lpass_platform_copy,
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index de3ec6f594c1..68b71039b981 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -14,10 +14,11 @@
#include <linux/regmap.h>
#include <dt-bindings/sound/qcom,lpass.h>
#include <dt-bindings/sound/qcom,q6afe.h>
+#include "common.h"
#include "lpass-hdmi.h"
#define LPASS_AHBIX_CLOCK_FREQUENCY 131072000
-#define LPASS_MAX_PORTS (DISPLAY_PORT_RX_7 + 1)
+#define LPASS_MAX_PORTS (LPASS_MAX_PORT)
#define LPASS_MAX_MI2S_PORTS (8)
#define LPASS_MAX_DMA_CHANNELS (8)
#define LPASS_MAX_HDMI_DMA_CHANNELS (4)
diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c
index 241c3b4479c6..0eff5e572573 100644
--- a/sound/soc/qcom/qdsp6/audioreach.c
+++ b/sound/soc/qcom/qdsp6/audioreach.c
@@ -1365,9 +1365,14 @@ int audioreach_set_media_format(struct q6apm_graph *graph,
case MODULE_ID_SPEAKER_PROTECTION:
rc = audioreach_speaker_protection(graph, module,
PARAM_ID_SP_OP_MODE_NORMAL);
+ if (!rc)
+ rc = audioreach_module_enable(graph, module, true);
+
break;
case MODULE_ID_SPEAKER_PROTECTION_VI:
rc = audioreach_speaker_protection_vi(graph, module, cfg);
+ if (!rc)
+ rc = audioreach_module_enable(graph, module, true);
break;
default:
@@ -1396,66 +1401,6 @@ void audioreach_graph_free_buf(struct q6apm_graph *graph)
}
EXPORT_SYMBOL_GPL(audioreach_graph_free_buf);
-int audioreach_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, size_t period_sz,
- unsigned int periods, bool is_contiguous)
-{
- struct apm_shared_map_region_payload *mregions;
- struct apm_cmd_shared_mem_map_regions *cmd;
- uint32_t num_regions, buf_sz, payload_size;
- struct audioreach_graph_data *data;
- struct gpr_pkt *pkt __free(kfree) = NULL;
- void *p;
- int i;
-
- if (dir == SNDRV_PCM_STREAM_PLAYBACK)
- data = &graph->rx_data;
- else
- data = &graph->tx_data;
-
- if (is_contiguous) {
- num_regions = 1;
- buf_sz = period_sz * periods;
- } else {
- buf_sz = period_sz;
- num_regions = periods;
- }
-
- /* DSP expects size should be aligned to 4K */
- buf_sz = ALIGN(buf_sz, 4096);
-
- payload_size = sizeof(*cmd) + (sizeof(*mregions) * num_regions);
-
- pkt = audioreach_alloc_apm_pkt(payload_size, APM_CMD_SHARED_MEM_MAP_REGIONS, dir,
- graph->port->id);
- if (IS_ERR(pkt))
- return PTR_ERR(pkt);
-
- p = (void *)pkt + GPR_HDR_SIZE;
- cmd = p;
- cmd->mem_pool_id = APM_MEMORY_MAP_SHMEM8_4K_POOL;
- cmd->num_regions = num_regions;
-
- cmd->property_flag = 0x0;
-
- mregions = p + sizeof(*cmd);
-
- mutex_lock(&graph->lock);
-
- for (i = 0; i < num_regions; i++) {
- struct audio_buffer *ab;
-
- ab = &data->buf[i];
- mregions->shm_addr_lsw = lower_32_bits(ab->phys);
- mregions->shm_addr_msw = upper_32_bits(ab->phys);
- mregions->mem_size_bytes = buf_sz;
- ++mregions;
- }
- mutex_unlock(&graph->lock);
-
- return audioreach_graph_send_cmd_sync(graph, pkt, APM_CMD_RSP_SHARED_MEM_MAP_REGIONS);
-}
-EXPORT_SYMBOL_GPL(audioreach_map_memory_regions);
-
int audioreach_shared_memory_send_eos(struct q6apm_graph *graph)
{
struct data_cmd_wr_sh_mem_ep_eos *eos;
diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h
index 89f172aab8c0..6ddc287f0fb4 100644
--- a/sound/soc/qcom/qdsp6/audioreach.h
+++ b/sound/soc/qcom/qdsp6/audioreach.h
@@ -722,6 +722,7 @@ struct audioreach_connection {
struct audioreach_graph_info {
int id;
+ uint32_t mem_map_handle;
uint32_t num_sub_graphs;
struct list_head sg_list;
/* DPCM connection from FE Graph to BE graph */
@@ -838,10 +839,6 @@ int audioreach_tplg_init(struct snd_soc_component *component);
/* Module specific */
void audioreach_graph_free_buf(struct q6apm_graph *graph);
-int audioreach_map_memory_regions(struct q6apm_graph *graph,
- unsigned int dir, size_t period_sz,
- unsigned int periods,
- bool is_contiguous);
int audioreach_send_cmd_sync(struct device *dev, gpr_device_t *gdev, struct gpr_ibasic_rsp_result_t *result,
struct mutex *cmd_lock, gpr_port_t *port, wait_queue_head_t *cmd_wait,
struct gpr_pkt *pkt, uint32_t rsp_opcode);
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c
index 0f47aadaabe1..a0d21034a626 100644
--- a/sound/soc/qcom/qdsp6/q6afe-dai.c
+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c
@@ -409,6 +409,7 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
q6afe_slim_port_prepare(dai_data->port[dai->id],
&dai_data->port_config[dai->id].slim);
break;
+ case SENARY_MI2S_RX ... SENARY_MI2S_TX:
case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
rc = q6afe_i2s_port_prepare(dai_data->port[dai->id],
@@ -540,6 +541,7 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
{"Tertiary MI2S Playback", NULL, "TERT_MI2S_RX"},
{"Quaternary MI2S Playback", NULL, "QUAT_MI2S_RX"},
{"Quinary MI2S Playback", NULL, "QUIN_MI2S_RX"},
+ {"Senary MI2S Playback", NULL, "SEN_MI2S_RX"},
{"Primary TDM0 Playback", NULL, "PRIMARY_TDM_RX_0"},
{"Primary TDM1 Playback", NULL, "PRIMARY_TDM_RX_1"},
@@ -636,6 +638,7 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
{"SEC_MI2S_TX", NULL, "Secondary MI2S Capture"},
{"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"},
{"QUIN_MI2S_TX", NULL, "Quinary MI2S Capture"},
+ {"SEN_MI2S_TX", NULL, "Senary MI2S Capture"},
{"WSA_CODEC_DMA_RX_0 Playback", NULL, "WSA_CODEC_DMA_RX_0"},
{"WSA_CODEC_DMA_TX_0", NULL, "WSA_CODEC_DMA_TX_0 Capture"},
@@ -770,6 +773,8 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
SND_SOC_DAPM_AIF_OUT("SLIMBUS_4_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("SLIMBUS_6_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEN_MI2S_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEN_MI2S_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("QUIN_MI2S_RX", NULL,
0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("QUIN_MI2S_TX", NULL,
@@ -1037,6 +1042,7 @@ static void of_q6afe_parse_dai_data(struct device *dev,
switch (id) {
/* MI2S specific properties */
+ case SENARY_MI2S_RX ... SENARY_MI2S_TX:
case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
priv = &data->priv[id];
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
index 43d877322bae..40237267fda0 100644
--- a/sound/soc/qcom/qdsp6/q6afe.c
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -130,6 +130,8 @@
#define AFE_PORT_ID_QUATERNARY_MI2S_TX 0x1007
#define AFE_PORT_ID_QUINARY_MI2S_RX 0x1016
#define AFE_PORT_ID_QUINARY_MI2S_TX 0x1017
+#define AFE_PORT_ID_SENARY_MI2S_RX 0x1018
+#define AFE_PORT_ID_SENARY_MI2S_TX 0x1019
/* Start of the range of port IDs for TDM devices. */
#define AFE_PORT_ID_TDM_PORT_RANGE_START 0x9000
@@ -718,6 +720,10 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = {
QUINARY_MI2S_RX, 1, 1},
[QUINARY_MI2S_TX] = { AFE_PORT_ID_QUINARY_MI2S_TX,
QUINARY_MI2S_TX, 0, 1},
+ [SENARY_MI2S_RX] = { AFE_PORT_ID_SENARY_MI2S_RX,
+ SENARY_MI2S_RX, 1, 1},
+ [SENARY_MI2S_TX] = { AFE_PORT_ID_SENARY_MI2S_TX,
+ SENARY_MI2S_TX, 0, 1},
[PRIMARY_TDM_RX_0] = { AFE_PORT_ID_PRIMARY_TDM_RX,
PRIMARY_TDM_RX_0, 1, 1},
[PRIMARY_TDM_TX_0] = { AFE_PORT_ID_PRIMARY_TDM_TX,
@@ -1777,6 +1783,8 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
case AFE_PORT_ID_QUINARY_MI2S_RX:
case AFE_PORT_ID_QUINARY_MI2S_TX:
+ case AFE_PORT_ID_SENARY_MI2S_RX:
+ case AFE_PORT_ID_SENARY_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/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h
index a29abe4ce436..0b8c3ec1315c 100644
--- a/sound/soc/qcom/qdsp6/q6afe.h
+++ b/sound/soc/qcom/qdsp6/q6afe.h
@@ -2,8 +2,9 @@
#ifndef __Q6AFE_H__
#define __Q6AFE_H__
+#include "../common.h"
-#define AFE_PORT_MAX 137
+#define AFE_PORT_MAX (LPASS_MAX_PORT)
#define MSM_AFE_PORT_TYPE_RX 0
#define MSM_AFE_PORT_TYPE_TX 1
diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c
index 168c166c960d..ede19fdea6e9 100644
--- a/sound/soc/qcom/qdsp6/q6apm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6apm-dai.c
@@ -228,11 +228,10 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,
cfg.bit_width = prtd->bits_per_sample;
cfg.fmt = SND_AUDIOCODEC_PCM;
audioreach_set_default_channel_mapping(cfg.channel_map, runtime->channels);
-
if (prtd->state) {
/* clear the previous setup if any */
q6apm_graph_stop(prtd->graph);
- q6apm_unmap_memory_regions(prtd->graph, substream->stream);
+ q6apm_free_fragments(prtd->graph, substream->stream);
}
prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
@@ -247,8 +246,8 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,
if (ret < 0)
dev_err(dev, "%s: CMD Format block failed\n", __func__);
- ret = q6apm_map_memory_regions(prtd->graph, substream->stream, prtd->phys,
- (prtd->pcm_size / prtd->periods), prtd->periods);
+ ret = q6apm_alloc_fragments(prtd->graph, substream->stream, prtd->phys,
+ (prtd->pcm_size / prtd->periods), prtd->periods);
if (ret < 0) {
dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n", ret);
@@ -317,6 +316,7 @@ static int q6apm_dai_trigger(struct snd_soc_component *component,
case SNDRV_PCM_TRIGGER_STOP:
/* TODO support be handled via SoftPause Module */
prtd->state = Q6APM_STREAM_STOPPED;
+ prtd->queue_ptr = 0;
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -354,7 +354,7 @@ static int q6apm_dai_open(struct snd_soc_component *component,
spin_lock_init(&prtd->lock);
prtd->substream = substream;
- prtd->graph = q6apm_graph_open(dev, event_handler, prtd, graph_id);
+ prtd->graph = q6apm_graph_open(dev, event_handler, prtd, graph_id, substream->stream);
if (IS_ERR(prtd->graph)) {
dev_err(dev, "%s: Could not allocate memory\n", __func__);
ret = PTR_ERR(prtd->graph);
@@ -415,9 +415,10 @@ static int q6apm_dai_close(struct snd_soc_component *component,
struct snd_pcm_runtime *runtime = substream->runtime;
struct q6apm_dai_rtd *prtd = runtime->private_data;
- if (prtd->state) { /* only stop graph that is started */
+ if (prtd->state) {
+ /* only stop graph that is started */
q6apm_graph_stop(prtd->graph);
- q6apm_unmap_memory_regions(prtd->graph, substream->stream);
+ q6apm_free_fragments(prtd->graph, substream->stream);
}
q6apm_graph_close(prtd->graph);
@@ -466,11 +467,94 @@ static int q6apm_dai_hw_params(struct snd_soc_component *component,
return 0;
}
+static int q6apm_dai_memory_map(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream, int graph_id)
+{
+ struct q6apm_dai_data *pdata;
+ struct device *dev = component->dev;
+ phys_addr_t phys;
+ int ret;
+
+ pdata = snd_soc_component_get_drvdata(component);
+ if (!pdata) {
+ dev_err(component->dev, "Drv data not found ..\n");
+ return -EINVAL;
+ }
+
+ if (pdata->sid < 0)
+ phys = substream->dma_buffer.addr;
+ else
+ phys = substream->dma_buffer.addr | (pdata->sid << 32);
+
+ ret = q6apm_map_memory_fixed_region(dev, graph_id, phys, BUFFER_BYTES_MAX);
+ if (ret < 0)
+ dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n", ret);
+
+ return ret;
+}
+
static int q6apm_dai_pcm_new(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_pcm *pcm = rtd->pcm;
int size = BUFFER_BYTES_MAX;
+ int graph_id, ret;
+ struct snd_pcm_substream *substream;
+
+ graph_id = cpu_dai->driver->id;
+
+ ret = snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, component->dev, size);
+ if (ret)
+ return ret;
+
+ /* Note: DSP backend dais are uni-directional ONLY(either playback or capture) */
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+ substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ ret = q6apm_dai_memory_map(component, substream, graph_id);
+ if (ret)
+ return ret;
+ }
+
+ if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+ substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+ ret = q6apm_dai_memory_map(component, substream, graph_id);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void q6apm_dai_memory_unmap(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *soc_prtd;
+ struct snd_soc_dai *cpu_dai;
+ int graph_id;
+
+ soc_prtd = snd_soc_substream_to_rtd(substream);
+ if (!soc_prtd)
+ return;
+
+ cpu_dai = snd_soc_rtd_to_cpu(soc_prtd, 0);
+ if (!cpu_dai)
+ return;
+
+ graph_id = cpu_dai->driver->id;
+ q6apm_unmap_memory_fixed_region(component->dev, graph_id);
+}
+
+static void q6apm_dai_pcm_free(struct snd_soc_component *component, struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+
+ substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+ if (substream)
+ q6apm_dai_memory_unmap(component, substream);
- return snd_pcm_set_fixed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, component->dev, size);
+ substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ if (substream)
+ q6apm_dai_memory_unmap(component, substream);
}
static int q6apm_dai_compr_open(struct snd_soc_component *component,
@@ -495,7 +579,8 @@ static int q6apm_dai_compr_open(struct snd_soc_component *component,
return -ENOMEM;
prtd->cstream = stream;
- prtd->graph = q6apm_graph_open(dev, event_handler_compr, prtd, graph_id);
+ prtd->graph = q6apm_graph_open(dev, event_handler_compr, prtd, graph_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
if (IS_ERR(prtd->graph)) {
ret = PTR_ERR(prtd->graph);
kfree(prtd);
@@ -528,7 +613,8 @@ static int q6apm_dai_compr_free(struct snd_soc_component *component,
struct q6apm_dai_rtd *prtd = runtime->private_data;
q6apm_graph_stop(prtd->graph);
- q6apm_unmap_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK);
+ q6apm_free_fragments(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK);
+ q6apm_unmap_memory_fixed_region(component->dev, prtd->graph->id);
q6apm_graph_close(prtd->graph);
snd_dma_free_pages(&prtd->dma_buffer);
prtd->graph = NULL;
@@ -677,9 +763,9 @@ static int q6apm_dai_compr_set_params(struct snd_soc_component *component,
if (ret)
return ret;
- ret = q6apm_map_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK,
- prtd->phys, (prtd->pcm_size / prtd->periods),
- prtd->periods);
+ ret = q6apm_alloc_fragments(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK,
+ prtd->phys, (prtd->pcm_size / prtd->periods),
+ prtd->periods);
if (ret < 0)
return -ENOMEM;
@@ -831,7 +917,8 @@ static const struct snd_soc_component_driver q6apm_fe_dai_component = {
.open = q6apm_dai_open,
.close = q6apm_dai_close,
.prepare = q6apm_dai_prepare,
- .pcm_construct = q6apm_dai_pcm_new,
+ .pcm_new = q6apm_dai_pcm_new,
+ .pcm_free = q6apm_dai_pcm_free,
.hw_params = q6apm_dai_hw_params,
.pointer = q6apm_dai_pointer,
.trigger = q6apm_dai_trigger,
diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
index 5be37eeea329..006b283484d9 100644
--- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
+++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
@@ -150,7 +150,7 @@ static void q6apm_lpass_dai_shutdown(struct snd_pcm_substream *substream, struct
rc = q6apm_graph_stop(dai_data->graph[dai->id]);
dai_data->is_port_started[dai->id] = false;
if (rc < 0)
- dev_err(dai->dev, "fail to close APM port (%d)\n", rc);
+ dev_err(dai->dev, "failed to stop APM port (%d)\n", rc);
}
if (dai_data->graph[dai->id]) {
@@ -159,6 +159,31 @@ static void q6apm_lpass_dai_shutdown(struct snd_pcm_substream *substream, struct
}
}
+static int q6apm_lpass_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (!dai_data->is_port_started[dai->id]) {
+ ret = q6apm_graph_start(dai_data->graph[dai->id]);
+ if (ret < 0)
+ dev_err(dai->dev, "Failed to start APM port %d\n", dai->id);
+ else
+ dai_data->is_port_started[dai->id] = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
@@ -171,18 +196,14 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s
q6apm_graph_stop(dai_data->graph[dai->id]);
dai_data->is_port_started[dai->id] = false;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- q6apm_graph_close(dai_data->graph[dai->id]);
- dai_data->graph[dai->id] = NULL;
- }
}
/**
* It is recommend to load DSP with source graph first and then sink
* graph, so sequence for playback and capture will be different
*/
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- graph = q6apm_graph_open(dai->dev, NULL, dai->dev, graph_id);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai_data->graph[dai->id] == NULL) {
+ graph = q6apm_graph_open(dai->dev, NULL, dai->dev, graph_id, substream->stream);
if (IS_ERR(graph)) {
dev_err(dai->dev, "Failed to open graph (%d)\n", graph_id);
rc = PTR_ERR(graph);
@@ -203,14 +224,6 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s
dev_err(dai->dev, "Failed to prepare Graph %d\n", rc);
goto err;
}
-
- rc = q6apm_graph_start(dai_data->graph[dai->id]);
- if (rc < 0) {
- dev_err(dai->dev, "Failed to start APM port %d\n", dai->id);
- goto err;
- }
- dai_data->is_port_started[dai->id] = true;
-
return 0;
err:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -227,7 +240,7 @@ static int q6apm_lpass_dai_startup(struct snd_pcm_substream *substream, struct s
int graph_id = dai->id;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- graph = q6apm_graph_open(dai->dev, NULL, dai->dev, graph_id);
+ graph = q6apm_graph_open(dai->dev, NULL, dai->dev, graph_id, substream->stream);
if (IS_ERR(graph)) {
dev_err(dai->dev, "Failed to open graph (%d)\n", graph_id);
return PTR_ERR(graph);
@@ -254,6 +267,7 @@ static const struct snd_soc_dai_ops q6dma_ops = {
.shutdown = q6apm_lpass_dai_shutdown,
.set_channel_map = q6dma_set_channel_map,
.hw_params = q6dma_hw_params,
+ .trigger = q6apm_lpass_dai_trigger,
};
static const struct snd_soc_dai_ops q6i2s_ops = {
@@ -263,6 +277,7 @@ static const struct snd_soc_dai_ops q6i2s_ops = {
.set_channel_map = q6dma_set_channel_map,
.hw_params = q6dma_hw_params,
.set_fmt = q6i2s_set_fmt,
+ .trigger = q6apm_lpass_dai_trigger,
};
static const struct snd_soc_dai_ops q6hdmi_ops = {
@@ -271,6 +286,7 @@ static const struct snd_soc_dai_ops q6hdmi_ops = {
.shutdown = q6apm_lpass_dai_shutdown,
.hw_params = q6hdmi_hw_params,
.set_fmt = q6i2s_set_fmt,
+ .trigger = q6apm_lpass_dai_trigger,
};
static const struct snd_soc_component_driver q6apm_lpass_dai_component = {
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index 970b08c89bb3..3c119a6132e4 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -200,13 +200,53 @@ int q6apm_graph_media_format_shmem(struct q6apm_graph *graph,
}
EXPORT_SYMBOL_GPL(q6apm_graph_media_format_shmem);
-int q6apm_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, phys_addr_t phys,
- size_t period_sz, unsigned int periods)
+int q6apm_map_memory_fixed_region(struct device *dev, unsigned int graph_id, phys_addr_t phys,
+ size_t sz)
+{
+ struct audioreach_graph_info *info;
+ struct q6apm *apm = dev_get_drvdata(dev->parent);
+ struct apm_shared_map_region_payload *mregions;
+ struct apm_cmd_shared_mem_map_regions *cmd;
+ int payload_size = sizeof(*cmd) + (sizeof(*mregions));
+ uint32_t buf_sz;
+ void *p;
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(payload_size,
+ APM_CMD_SHARED_MEM_MAP_REGIONS, graph_id);
+ if (IS_ERR(pkt))
+ return PTR_ERR(pkt);
+
+ info = idr_find(&apm->graph_info_idr, graph_id);
+ if (!info)
+ return -ENODEV;
+
+ if (info->mem_map_handle)
+ return 0;
+
+ /* DSP expects size should be aligned to 4K */
+ buf_sz = ALIGN(sz, 4096);
+
+ p = (void *)pkt + GPR_HDR_SIZE;
+ cmd = p;
+ cmd->mem_pool_id = APM_MEMORY_MAP_SHMEM8_4K_POOL;
+ cmd->num_regions = 1;
+ cmd->property_flag = 0x0;
+
+ mregions = p + sizeof(*cmd);
+
+ mregions->shm_addr_lsw = lower_32_bits(phys);
+ mregions->shm_addr_msw = upper_32_bits(phys);
+ mregions->mem_size_bytes = buf_sz;
+
+ return q6apm_send_cmd_sync(apm, pkt, APM_CMD_RSP_SHARED_MEM_MAP_REGIONS);
+}
+EXPORT_SYMBOL_GPL(q6apm_map_memory_fixed_region);
+
+int q6apm_alloc_fragments(struct q6apm_graph *graph, unsigned int dir, phys_addr_t phys,
+ size_t period_sz, unsigned int periods)
{
struct audioreach_graph_data *data;
struct audio_buffer *buf;
int cnt;
- int rc;
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
data = &graph->rx_data;
@@ -215,6 +255,8 @@ int q6apm_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, phys_a
mutex_lock(&graph->lock);
+ data->dsp_buf = 0;
+
if (data->buf) {
mutex_unlock(&graph->lock);
return 0;
@@ -246,46 +288,41 @@ int q6apm_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, phys_a
mutex_unlock(&graph->lock);
- rc = audioreach_map_memory_regions(graph, dir, period_sz, periods, 1);
- if (rc < 0) {
- dev_err(graph->dev, "Memory_map_regions failed\n");
- audioreach_graph_free_buf(graph);
- }
-
- return rc;
+ return 0;
}
-EXPORT_SYMBOL_GPL(q6apm_map_memory_regions);
+EXPORT_SYMBOL_GPL(q6apm_alloc_fragments);
-int q6apm_unmap_memory_regions(struct q6apm_graph *graph, unsigned int dir)
+int q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id)
{
struct apm_cmd_shared_mem_unmap_regions *cmd;
- struct audioreach_graph_data *data;
- int rc;
+ struct q6apm *apm = dev_get_drvdata(dev->parent);
+ struct audioreach_graph_info *info;
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(sizeof(*cmd),
+ APM_CMD_SHARED_MEM_UNMAP_REGIONS, graph_id);
+ if (IS_ERR(pkt))
+ return PTR_ERR(pkt);
- if (dir == SNDRV_PCM_STREAM_PLAYBACK)
- data = &graph->rx_data;
- else
- data = &graph->tx_data;
+ info = idr_find(&apm->graph_info_idr, graph_id);
+ if (!info)
+ return -ENODEV;
- if (!data->mem_map_handle)
+ if (!info->mem_map_handle)
return 0;
- struct gpr_pkt *pkt __free(kfree) =
- audioreach_alloc_apm_pkt(sizeof(*cmd), APM_CMD_SHARED_MEM_UNMAP_REGIONS,
- dir, graph->port->id);
- if (IS_ERR(pkt))
- return PTR_ERR(pkt);
-
cmd = (void *)pkt + GPR_HDR_SIZE;
- cmd->mem_map_handle = data->mem_map_handle;
+ cmd->mem_map_handle = info->mem_map_handle;
- rc = audioreach_graph_send_cmd_sync(graph, pkt, APM_CMD_SHARED_MEM_UNMAP_REGIONS);
+ return q6apm_send_cmd_sync(apm, pkt, APM_CMD_SHARED_MEM_UNMAP_REGIONS);
+}
+EXPORT_SYMBOL_GPL(q6apm_unmap_memory_fixed_region);
+int q6apm_free_fragments(struct q6apm_graph *graph, unsigned int dir)
+{
audioreach_graph_free_buf(graph);
- return rc;
+ return 0;
}
-EXPORT_SYMBOL_GPL(q6apm_unmap_memory_regions);
+EXPORT_SYMBOL_GPL(q6apm_free_fragments);
int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples)
{
@@ -409,12 +446,11 @@ int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
{
struct apm_data_cmd_wr_sh_mem_ep_data_buffer_v2 *write_buffer;
struct audio_buffer *ab;
- int iid = q6apm_graph_get_rx_shmem_module_iid(graph);
struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_pkt(sizeof(*write_buffer),
DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2,
graph->rx_data.dsp_buf | (len << APM_WRITE_TOKEN_LEN_SHIFT),
- graph->port->id, iid);
+ graph->port->id, graph->shm_iid);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -428,7 +464,7 @@ int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
write_buffer->buf_size = len;
write_buffer->timestamp_lsw = lsw_ts;
write_buffer->timestamp_msw = msw_ts;
- write_buffer->mem_map_handle = graph->rx_data.mem_map_handle;
+ write_buffer->mem_map_handle = graph->info->mem_map_handle;
write_buffer->flags = wflags;
graph->rx_data.dsp_buf++;
@@ -447,11 +483,10 @@ int q6apm_read(struct q6apm_graph *graph)
struct data_cmd_rd_sh_mem_ep_data_buffer_v2 *read_buffer;
struct audioreach_graph_data *port;
struct audio_buffer *ab;
- int iid = q6apm_graph_get_tx_shmem_module_iid(graph);
struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_pkt(sizeof(*read_buffer),
DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2,
- graph->tx_data.dsp_buf, graph->port->id, iid);
+ graph->tx_data.dsp_buf, graph->port->id, graph->shm_iid);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -463,7 +498,7 @@ int q6apm_read(struct q6apm_graph *graph)
read_buffer->buf_addr_lsw = lower_32_bits(ab->phys);
read_buffer->buf_addr_msw = upper_32_bits(ab->phys);
- read_buffer->mem_map_handle = port->mem_map_handle;
+ read_buffer->mem_map_handle = graph->info->mem_map_handle;
read_buffer->buf_size = ab->size;
port->dsp_buf++;
@@ -494,7 +529,6 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op)
{
struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2 *rd_done;
struct data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_v2 *done;
- struct apm_cmd_rsp_shared_mem_map_regions *rsp;
const struct gpr_ibasic_rsp_result_t *result;
struct q6apm_graph *graph = priv;
const struct gpr_hdr *hdr = &data->hdr;
@@ -530,18 +564,6 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op)
}
break;
- case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS:
- graph->result.opcode = hdr->opcode;
- graph->result.status = 0;
- rsp = data->payload;
-
- if (hdr->token == SNDRV_PCM_STREAM_PLAYBACK)
- graph->rx_data.mem_map_handle = rsp->mem_map_handle;
- else
- graph->tx_data.mem_map_handle = rsp->mem_map_handle;
-
- wake_up(&graph->cmd_wait);
- break;
case DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_V2:
if (!graph->ar_graph)
break;
@@ -571,16 +593,6 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op)
break;
case GPR_BASIC_RSP_RESULT:
switch (result->opcode) {
- case APM_CMD_SHARED_MEM_UNMAP_REGIONS:
- graph->result.opcode = result->opcode;
- graph->result.status = 0;
- if (hdr->token == SNDRV_PCM_STREAM_PLAYBACK)
- graph->rx_data.mem_map_handle = 0;
- else
- graph->tx_data.mem_map_handle = 0;
-
- wake_up(&graph->cmd_wait);
- break;
case APM_CMD_SHARED_MEM_MAP_REGIONS:
case DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT:
case APM_CMD_SET_CFG:
@@ -602,7 +614,7 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op)
}
struct q6apm_graph *q6apm_graph_open(struct device *dev, q6apm_cb cb,
- void *priv, int graph_id)
+ void *priv, int graph_id, int dir)
{
struct q6apm *apm = dev_get_drvdata(dev->parent);
struct audioreach_graph *ar_graph;
@@ -629,6 +641,12 @@ struct q6apm_graph *q6apm_graph_open(struct device *dev, q6apm_cb cb,
graph->id = ar_graph->id;
graph->dev = dev;
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+ graph->shm_iid = q6apm_graph_get_rx_shmem_module_iid(graph);
+ else
+ graph->shm_iid = q6apm_graph_get_tx_shmem_module_iid(graph);
+
+
mutex_init(&graph->lock);
init_waitqueue_head(&graph->cmd_wait);
@@ -747,13 +765,23 @@ static int apm_probe(gpr_device_t *gdev)
q6apm_get_apm_state(apm);
- ret = devm_snd_soc_register_component(dev, &q6apm_audio_component, NULL, 0);
+ ret = snd_soc_register_component(dev, &q6apm_audio_component, NULL, 0);
if (ret < 0) {
dev_err(dev, "failed to register q6apm: %d\n", ret);
return ret;
}
- return of_platform_populate(dev->of_node, NULL, NULL, dev);
+ ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+ if (ret)
+ snd_soc_unregister_component(dev);
+
+ return ret;
+}
+
+static void apm_remove(gpr_device_t *gdev)
+{
+ of_platform_depopulate(&gdev->dev);
+ snd_soc_unregister_component(&gdev->dev);
}
struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, uint32_t mid)
@@ -768,7 +796,9 @@ struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, ui
static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op)
{
gpr_device_t *gdev = priv;
+ struct audioreach_graph_info *info;
struct q6apm *apm = dev_get_drvdata(&gdev->dev);
+ struct apm_cmd_rsp_shared_mem_map_regions *rsp;
struct device *dev = &gdev->dev;
struct gpr_ibasic_rsp_result_t *result;
const struct gpr_hdr *hdr = &data->hdr;
@@ -785,6 +815,7 @@ static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op)
break;
case GPR_BASIC_RSP_RESULT:
switch (result->opcode) {
+ case APM_CMD_SHARED_MEM_MAP_REGIONS:
case APM_CMD_GRAPH_START:
case APM_CMD_GRAPH_OPEN:
case APM_CMD_GRAPH_PREPARE:
@@ -799,10 +830,38 @@ static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op)
result->opcode);
wake_up(&apm->wait);
break;
+ case APM_CMD_SHARED_MEM_UNMAP_REGIONS:
+ apm->result.opcode = hdr->opcode;
+ apm->result.status = 0;
+ rsp = data->payload;
+
+ info = idr_find(&apm->graph_info_idr, hdr->token);
+ if (info)
+ info->mem_map_handle = 0;
+ else
+ dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
+ result->opcode);
+
+ wake_up(&apm->wait);
+ break;
default:
break;
}
break;
+ case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS:
+ apm->result.opcode = hdr->opcode;
+ apm->result.status = 0;
+ rsp = data->payload;
+
+ info = idr_find(&apm->graph_info_idr, hdr->token);
+ if (info)
+ info->mem_map_handle = rsp->mem_map_handle;
+ else
+ dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
+ result->opcode);
+
+ wake_up(&apm->wait);
+ break;
default:
break;
}
@@ -820,6 +879,7 @@ MODULE_DEVICE_TABLE(of, apm_device_id);
static gpr_driver_t apm_driver = {
.probe = apm_probe,
+ .remove = apm_remove,
.gpr_callback = apm_callback,
.driver = {
.name = "qcom-apm",
diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h
index 7ce08b401e31..909fc337fd28 100644
--- a/sound/soc/qcom/qdsp6/q6apm.h
+++ b/sound/soc/qcom/qdsp6/q6apm.h
@@ -14,9 +14,10 @@
#include <linux/of_platform.h>
#include <linux/jiffies.h>
#include <linux/soc/qcom/apr.h>
+#include "../common.h"
#include "audioreach.h"
-#define APM_PORT_MAX 127
+#define APM_PORT_MAX LPASS_MAX_PORT
#define APM_PORT_MAX_AUDIO_CHAN_CNT 8
#define PCM_CHANNEL_NULL 0
#define PCM_CHANNEL_FL 1 /* Front left channel. */
@@ -77,7 +78,6 @@ struct audioreach_graph_data {
struct audio_buffer *buf;
uint32_t num_periods;
uint32_t dsp_buf;
- uint32_t mem_map_handle;
atomic_t hw_ptr;
};
@@ -98,6 +98,7 @@ struct q6apm_graph {
void *priv;
q6apm_cb cb;
uint32_t id;
+ uint32_t shm_iid;
struct device *dev;
struct q6apm *apm;
gpr_port_t *port;
@@ -112,7 +113,7 @@ struct q6apm_graph {
/* Graph Operations */
struct q6apm_graph *q6apm_graph_open(struct device *dev, q6apm_cb cb,
- void *priv, int graph_id);
+ void *priv, int graph_id, int dir);
int q6apm_graph_close(struct q6apm_graph *graph);
int q6apm_graph_prepare(struct q6apm_graph *graph);
int q6apm_graph_start(struct q6apm_graph *graph);
@@ -132,11 +133,14 @@ int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
uint32_t lsw_ts, uint32_t wflags);
/* Memory Map related */
-int q6apm_map_memory_regions(struct q6apm_graph *graph,
- unsigned int dir, phys_addr_t phys,
- size_t period_sz, unsigned int periods);
-int q6apm_unmap_memory_regions(struct q6apm_graph *graph,
- unsigned int dir);
+int q6apm_map_memory_fixed_region(struct device *dev,
+ unsigned int graph_id, phys_addr_t phys,
+ size_t sz);
+int q6apm_alloc_fragments(struct q6apm_graph *graph,
+ unsigned int dir, phys_addr_t phys,
+ size_t period_sz, unsigned int periods);
+int q6apm_free_fragments(struct q6apm_graph *graph, unsigned int dir);
+int q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id);
/* Helpers */
int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt,
uint32_t rsp_opcode);
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 9e3d176f50c2..4f8f7db6c3d3 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -1224,7 +1224,7 @@ static const struct snd_soc_component_driver q6asm_fe_dai_component = {
.trigger = q6asm_dai_trigger,
.ack = q6asm_dai_ack,
.pointer = q6asm_dai_pointer,
- .pcm_construct = q6asm_dai_pcm_new,
+ .pcm_new = q6asm_dai_pcm_new,
.compress_ops = &q6asm_dai_compress_ops,
.dapm_widgets = q6asm_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(q6asm_dapm_widgets),
diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
index 4eed54b071a5..e5cd82f77b55 100644
--- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
+++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
@@ -96,6 +96,42 @@
.id = did, \
}
+#define Q6AFE_MI2S_RX_DAI(pre, did) { \
+ .playback = { \
+ .stream_name = pre" MI2S Playback", \
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_176400, \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE, \
+ .channels_min = 1, \
+ .channels_max = 8, \
+ .rate_min = 8000, \
+ .rate_max = 176400, \
+ }, \
+ .name = #did, \
+ .id = did, \
+ }
+
+#define Q6AFE_MI2S_TX_DAI(pre, did) { \
+ .capture = { \
+ .stream_name = pre" MI2S Capture", \
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_176400, \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE, \
+ .channels_min = 1, \
+ .channels_max = 8, \
+ .rate_min = 8000, \
+ .rate_max = 176400, \
+ }, \
+ .name = #did, \
+ .id = did, \
+ }
+
static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = {
{
.playback = {
@@ -483,7 +519,45 @@ static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = {
},
.id = QUINARY_MI2S_TX,
.name = "QUIN_MI2S_TX",
+ }, {
+ .playback = {
+ .stream_name = "Senary MI2S Playback",
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .id = SENARY_MI2S_RX,
+ .name = "SEN_MI2S_RX",
+ }, {
+ .capture = {
+ .stream_name = "Senary MI2S Capture",
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .id = SENARY_MI2S_TX,
+ .name = "SEN_MI2S_TX",
},
+ Q6AFE_MI2S_RX_DAI("LPI RX0", LPI_MI2S_RX_0),
+ Q6AFE_MI2S_RX_DAI("LPI RX1", LPI_MI2S_RX_1),
+ 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_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_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),
@@ -634,8 +708,10 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev,
case SLIMBUS_0_RX ... SLIMBUS_6_TX:
q6dsp_audio_fe_dais[i].ops = cfg->q6slim_ops;
break;
+ 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:
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/topology.c b/sound/soc/qcom/qdsp6/topology.c
index e732fac9b8ca..1f69fba6de26 100644
--- a/sound/soc/qcom/qdsp6/topology.c
+++ b/sound/soc/qcom/qdsp6/topology.c
@@ -952,9 +952,6 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp,
struct audioreach_container *cont;
struct audioreach_module *mod;
- mod = dobj->private;
- cont = mod->container;
-
if (w->id == snd_soc_dapm_mixer) {
/* virtual widget */
struct snd_ar_control *scontrol = dobj->private;
@@ -963,6 +960,11 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp,
kfree(scontrol);
return 0;
}
+ mod = dobj->private;
+ if (!mod)
+ return 0;
+
+ cont = mod->container;
mutex_lock(&apm->lock);
idr_remove(&apm->modules_idr, mod->instance_id);
diff --git a/sound/soc/renesas/dma-sh7760.c b/sound/soc/renesas/dma-sh7760.c
index c53539482c20..810f44cd6523 100644
--- a/sound/soc/renesas/dma-sh7760.c
+++ b/sound/soc/renesas/dma-sh7760.c
@@ -58,8 +58,9 @@ struct camelot_pcm {
struct snd_pcm_substream *rx_ss;
unsigned long rx_period_size;
unsigned int rx_period;
+};
-} cam_pcm_data[2] = {
+static struct camelot_pcm cam_pcm_data[2] = {
{
.mmio = 0xFE3C0040,
.txid = DMABRGIRQ_A0TXF,
@@ -310,7 +311,7 @@ static const struct snd_soc_component_driver sh7760_soc_component = {
.prepare = camelot_prepare,
.trigger = camelot_trigger,
.pointer = camelot_pos,
- .pcm_construct = camelot_pcm_new,
+ .pcm_new = camelot_pcm_new,
};
static int sh7760_soc_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/renesas/fsi.c b/sound/soc/renesas/fsi.c
index 1491c2f2cc96..8cbd7acc26f4 100644
--- a/sound/soc/renesas/fsi.c
+++ b/sound/soc/renesas/fsi.c
@@ -1817,7 +1817,7 @@ static const struct snd_soc_component_driver fsi_soc_component = {
.name = "fsi",
.open = fsi_pcm_open,
.pointer = fsi_pointer,
- .pcm_construct = fsi_pcm_new,
+ .pcm_new = fsi_pcm_new,
};
/*
diff --git a/sound/soc/renesas/rcar/core.c b/sound/soc/renesas/rcar/core.c
index 69fb19964a71..2dc078358612 100644
--- a/sound/soc/renesas/rcar/core.c
+++ b/sound/soc/renesas/rcar/core.c
@@ -1974,7 +1974,7 @@ static int rsnd_probe(struct platform_device *pdev)
* asoc register
*/
ci = 0;
- for (i = 0; priv->component_dais[i] > 0; i++) {
+ for (i = 0; i < RSND_MAX_COMPONENT && priv->component_dais[i] > 0; i++) {
int nr = priv->component_dais[i];
ret = devm_snd_soc_register_component(dev, &rsnd_soc_component,
diff --git a/sound/soc/renesas/rcar/msiof.c b/sound/soc/renesas/rcar/msiof.c
index f2addfbac923..2671abc028cc 100644
--- a/sound/soc/renesas/rcar/msiof.c
+++ b/sound/soc/renesas/rcar/msiof.c
@@ -514,7 +514,7 @@ static const struct snd_soc_component_driver msiof_component_driver = {
.open = msiof_open,
.close = msiof_close,
.pointer = msiof_pointer,
- .pcm_construct = msiof_new,
+ .pcm_new = msiof_new,
.trigger = msiof_trigger,
.hw_params = msiof_hw_params,
};
diff --git a/sound/soc/renesas/rz-ssi.c b/sound/soc/renesas/rz-ssi.c
index 74e078c04150..71e434cfe07b 100644
--- a/sound/soc/renesas/rz-ssi.c
+++ b/sound/soc/renesas/rz-ssi.c
@@ -1117,7 +1117,7 @@ static const struct snd_soc_component_driver rz_ssi_soc_component = {
.name = "rz-ssi",
.open = rz_ssi_pcm_open,
.pointer = rz_ssi_pcm_pointer,
- .pcm_construct = rz_ssi_pcm_new,
+ .pcm_new = rz_ssi_pcm_new,
.legacy_dai_naming = 1,
};
diff --git a/sound/soc/renesas/siu_pcm.c b/sound/soc/renesas/siu_pcm.c
index f15ff36e7934..fd5b20b469a4 100644
--- a/sound/soc/renesas/siu_pcm.c
+++ b/sound/soc/renesas/siu_pcm.c
@@ -483,7 +483,6 @@ siu_pcm_pointer_dma(struct snd_soc_component *component,
static int siu_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
- /* card->dev == socdev->dev, see snd_soc_new_pcms() */
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
struct siu_info *info = siu_i2s_data;
@@ -546,8 +545,8 @@ const struct snd_soc_component_driver siu_component = {
.prepare = siu_pcm_prepare,
.trigger = siu_pcm_trigger,
.pointer = siu_pcm_pointer_dma,
- .pcm_construct = siu_pcm_new,
- .pcm_destruct = siu_pcm_free,
+ .pcm_new = siu_pcm_new,
+ .pcm_free = siu_pcm_free,
.legacy_dai_naming = 1,
};
EXPORT_SYMBOL_GPL(siu_component);
diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c
index 1bf614dbdf4d..ed393e5034a4 100644
--- a/sound/soc/rockchip/rockchip_sai.c
+++ b/sound/soc/rockchip/rockchip_sai.c
@@ -628,6 +628,10 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
+ if (!sai->is_tdm)
+ regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK,
+ SAI_XCR_SBW(params_physical_width(params)));
+
regmap_read(sai->regmap, reg, &val);
slot_width = SAI_XCR_SBW_V(val);
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index beb7e09e9fac..cb455ddce253 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -399,8 +399,8 @@ static const struct snd_soc_component_driver asoc_idma_platform = {
.hw_params = idma_hw_params,
.hw_free = idma_hw_free,
.prepare = idma_prepare,
- .pcm_construct = idma_new,
- .pcm_destruct = idma_free,
+ .pcm_new = idma_new,
+ .pcm_free = idma_free,
};
static int asoc_idma_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 235d0063d1b3..fb30f6b637a0 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -407,21 +407,12 @@ static int spdif_probe(struct platform_device *pdev)
if (ret)
goto err1;
- /* Request S/PDIF Register's memory region */
- if (!request_mem_region(mem_res->start,
- resource_size(mem_res), "samsung-spdif")) {
- dev_err(&pdev->dev, "Unable to request register region\n");
- ret = -EBUSY;
+ spdif->regs = devm_ioremap_resource(&pdev->dev, mem_res);
+ if (IS_ERR(spdif->regs)) {
+ ret = PTR_ERR(spdif->regs);
goto err2;
}
- spdif->regs = ioremap(mem_res->start, 0x100);
- if (spdif->regs == NULL) {
- dev_err(&pdev->dev, "Cannot ioremap registers\n");
- ret = -ENXIO;
- goto err3;
- }
-
spdif_stereo_out.addr_width = 2;
spdif_stereo_out.addr = mem_res->start + DATA_OUTBUF;
filter = NULL;
@@ -435,7 +426,7 @@ static int spdif_probe(struct platform_device *pdev)
NULL, NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to register DMA: %d\n", ret);
- goto err4;
+ goto err2;
}
dev_set_drvdata(&pdev->dev, spdif);
@@ -444,14 +435,10 @@ static int spdif_probe(struct platform_device *pdev)
&samsung_spdif_component, &samsung_spdif_dai, 1);
if (ret != 0) {
dev_err(&pdev->dev, "fail to register dai\n");
- goto err4;
+ goto err2;
}
return 0;
-err4:
- iounmap(spdif->regs);
-err3:
- release_mem_region(mem_res->start, resource_size(mem_res));
err2:
clk_disable_unprepare(spdif->sclk);
err1:
@@ -463,12 +450,6 @@ err0:
static void spdif_remove(struct platform_device *pdev)
{
struct samsung_spdif_info *spdif = &spdif_info;
- struct resource *mem_res;
-
- iounmap(spdif->regs);
-
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(mem_res->start, resource_size(mem_res));
clk_disable_unprepare(spdif->sclk);
clk_disable_unprepare(spdif->pclk);
diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c
index a0191e5a5a7d..2bfc8e5aee31 100644
--- a/sound/soc/sdca/sdca_asoc.c
+++ b/sound/soc/sdca/sdca_asoc.c
@@ -51,6 +51,25 @@ static bool readonly_control(struct sdca_control *control)
return control->has_fixed || control->mode == SDCA_ACCESS_MODE_RO;
}
+static int ge_count_routes(struct sdca_entity *entity)
+{
+ int count = 0;
+ int i, j;
+
+ for (i = 0; i < entity->ge.num_modes; i++) {
+ struct sdca_ge_mode *mode = &entity->ge.modes[i];
+
+ for (j = 0; j < mode->num_controls; j++) {
+ struct sdca_ge_control *affected = &mode->controls[j];
+
+ if (affected->sel != SDCA_CTL_SU_SELECTOR || affected->val)
+ count++;
+ }
+ }
+
+ return count;
+}
+
/**
* sdca_asoc_count_component - count the various component parts
* @dev: Pointer to the device against which allocations will be done.
@@ -74,6 +93,7 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
int *num_widgets, int *num_routes, int *num_controls,
int *num_dais)
{
+ struct sdca_control *control;
int i, j;
*num_widgets = function->num_entities - 1;
@@ -83,6 +103,7 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
for (i = 0; i < function->num_entities - 1; i++) {
struct sdca_entity *entity = &function->entities[i];
+ bool skip_primary_routes = false;
/* Add supply/DAI widget connections */
switch (entity->type) {
@@ -96,6 +117,17 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
case SDCA_ENTITY_TYPE_PDE:
*num_routes += entity->pde.num_managed;
break;
+ case SDCA_ENTITY_TYPE_GE:
+ *num_routes += ge_count_routes(entity);
+ skip_primary_routes = true;
+ break;
+ case SDCA_ENTITY_TYPE_SU:
+ control = sdca_selector_find_control(dev, entity, SDCA_CTL_SU_SELECTOR);
+ if (!control)
+ return -EINVAL;
+
+ skip_primary_routes = (control->layers == SDCA_ACCESS_LAYER_DEVICE);
+ break;
default:
break;
}
@@ -104,7 +136,8 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
(*num_routes)++;
/* Add primary entity connections from DisCo */
- *num_routes += entity->num_sources;
+ if (!skip_primary_routes)
+ *num_routes += entity->num_sources;
for (j = 0; j < entity->num_controls; j++) {
if (exported_control(entity, &entity->controls[j]))
@@ -442,7 +475,6 @@ static int entity_parse_su_device(struct device *dev,
struct snd_soc_dapm_route **route)
{
struct sdca_control_range *range;
- int num_routes = 0;
int i, j;
if (!entity->group) {
@@ -455,7 +487,7 @@ static int entity_parse_su_device(struct device *dev,
if (!range)
return -EINVAL;
- (*widget)->id = snd_soc_dapm_mux;
+ (*widget)->id = snd_soc_dapm_mux_named_ctl;
(*widget)->kcontrol_news = entity->group->ge.kctl;
(*widget)->num_kcontrols = 1;
(*widget)++;
@@ -478,11 +510,6 @@ static int entity_parse_su_device(struct device *dev,
return -EINVAL;
}
- if (++num_routes > entity->num_sources) {
- dev_err(dev, "%s: too many input routes\n", entity->label);
- return -EINVAL;
- }
-
term = sdca_range_search(range, SDCA_SELECTED_MODE_INDEX,
mode->val, SDCA_SELECTED_MODE_TERM_TYPE);
if (!term) {
@@ -778,6 +805,72 @@ int sdca_asoc_populate_dapm(struct device *dev, struct sdca_function_data *funct
}
EXPORT_SYMBOL_NS(sdca_asoc_populate_dapm, "SND_SOC_SDCA");
+static int q78_write(struct snd_soc_component *component,
+ struct soc_mixer_control *mc,
+ unsigned int reg, const int val)
+{
+ unsigned int mask = GENMASK(mc->sign_bit, 0);
+ unsigned int reg_val;
+
+ if (val < 0 || val > mc->max - mc->min)
+ return -EINVAL;
+
+ reg_val = (val + mc->min) * mc->shift;
+
+ return snd_soc_component_update_bits(component, reg, mask, reg_val);
+}
+
+int sdca_asoc_q78_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ int ret;
+
+ ret = q78_write(component, mc, mc->reg, ucontrol->value.integer.value[0]);
+ if (ret < 0)
+ return ret;
+
+ if (snd_soc_volsw_is_stereo(mc)) {
+ int err; /* Don't drop change flag */
+
+ err = q78_write(component, mc, mc->rreg, ucontrol->value.integer.value[1]);
+ if (err)
+ return err;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(sdca_asoc_q78_put_volsw, "SND_SOC_SDCA");
+
+static int q78_read(struct snd_soc_component *component,
+ struct soc_mixer_control *mc, unsigned int reg)
+{
+ unsigned int reg_val;
+ int val;
+
+ reg_val = snd_soc_component_read(component, reg);
+
+ val = (sign_extend32(reg_val, mc->sign_bit) / (int)mc->shift) - mc->min;
+
+ return val & GENMASK(mc->sign_bit, 0);
+}
+
+int sdca_asoc_q78_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = q78_read(component, mc, mc->reg);
+
+ if (snd_soc_volsw_is_stereo(mc))
+ ucontrol->value.integer.value[1] = q78_read(component, mc, mc->rreg);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_asoc_q78_get_volsw, "SND_SOC_SDCA");
+
static int control_limit_kctl(struct device *dev,
struct sdca_entity *entity,
struct sdca_control *control,
@@ -814,16 +907,15 @@ static int control_limit_kctl(struct device *dev,
tlv[2] = (min * 100) >> 8;
tlv[3] = (max * 100) >> 8;
- step = (step * 100) >> 8;
-
- mc->min = ((int)tlv[2] / step);
- mc->max = ((int)tlv[3] / step);
+ mc->min = min / step;
+ mc->max = max / step;
mc->shift = step;
mc->sign_bit = 15;
- mc->sdca_q78 = 1;
kctl->tlv.p = tlv;
kctl->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+ kctl->get = sdca_asoc_q78_get_volsw;
+ kctl->put = sdca_asoc_q78_put_volsw;
return 0;
}
diff --git a/sound/soc/sdca/sdca_class.c b/sound/soc/sdca/sdca_class.c
index 918b638acb57..6e9b66f71801 100644
--- a/sound/soc/sdca/sdca_class.c
+++ b/sound/soc/sdca/sdca_class.c
@@ -137,6 +137,13 @@ static const struct regmap_config class_dev_regmap_config = {
.unlock = class_regmap_unlock,
};
+static void class_remove_functions(void *data)
+{
+ struct sdca_class_drv *drv = data;
+
+ sdca_dev_unregister_functions(drv->sdw);
+}
+
static void class_boot_work(struct work_struct *work)
{
struct sdca_class_drv *drv = container_of(work,
@@ -157,6 +164,11 @@ static void class_boot_work(struct work_struct *work)
if (ret)
goto err;
+ /* Ensure function drivers are removed before the IRQ is destroyed */
+ ret = devm_add_action_or_reset(drv->dev, class_remove_functions, drv);
+ if (ret)
+ goto err;
+
dev_dbg(drv->dev, "boot work complete\n");
pm_runtime_mark_last_busy(drv->dev);
@@ -168,15 +180,6 @@ err:
pm_runtime_put_sync(drv->dev);
}
-static void class_dev_remove(void *data)
-{
- struct sdca_class_drv *drv = data;
-
- cancel_work_sync(&drv->boot_work);
-
- sdca_dev_unregister_functions(drv->sdw);
-}
-
static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id)
{
struct device *dev = &sdw->dev;
@@ -230,15 +233,19 @@ static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id
if (ret)
return ret;
- ret = devm_add_action_or_reset(dev, class_dev_remove, drv);
- if (ret)
- return ret;
-
queue_work(system_long_wq, &drv->boot_work);
return 0;
}
+static void class_sdw_remove(struct sdw_slave *sdw)
+{
+ struct device *dev = &sdw->dev;
+ struct sdca_class_drv *drv = dev_get_drvdata(dev);
+
+ cancel_work_sync(&drv->boot_work);
+}
+
static int class_suspend(struct device *dev)
{
struct sdca_class_drv *drv = dev_get_drvdata(dev);
@@ -317,6 +324,8 @@ static const struct dev_pm_ops class_pm_ops = {
static const struct sdw_device_id class_sdw_id[] = {
SDW_SLAVE_ENTRY(0x01FA, 0x4245, 0),
+ SDW_SLAVE_ENTRY(0x01FA, 0x4249, 0),
+ SDW_SLAVE_ENTRY(0x01FA, 0x4747, 0),
{}
};
MODULE_DEVICE_TABLE(sdw, class_sdw_id);
@@ -328,6 +337,7 @@ static struct sdw_driver class_sdw_driver = {
},
.probe = class_sdw_probe,
+ .remove = class_sdw_remove,
.id_table = class_sdw_id,
.ops = &class_sdw_ops,
};
diff --git a/sound/soc/sdca/sdca_class_function.c b/sound/soc/sdca/sdca_class_function.c
index 730103120514..31fc08d51307 100644
--- a/sound/soc/sdca/sdca_class_function.c
+++ b/sound/soc/sdca/sdca_class_function.c
@@ -377,8 +377,14 @@ static int class_function_probe(struct auxiliary_device *auxdev,
return dev_err_probe(dev, PTR_ERR(drv->regmap),
"failed to create regmap");
- if (desc->type == SDCA_FUNCTION_TYPE_UAJ)
+ switch (desc->type) {
+ case SDCA_FUNCTION_TYPE_UAJ:
+ case SDCA_FUNCTION_TYPE_RJ:
cmp_drv->set_jack = class_function_set_jack;
+ break;
+ default:
+ break;
+ }
ret = sdca_asoc_populate_component(dev, drv->function, cmp_drv,
&dais, &num_dais,
@@ -555,6 +561,10 @@ static const struct auxiliary_device_id class_function_id_table[] = {
.name = "snd_soc_sdca." SDCA_FUNCTION_TYPE_HID_NAME,
.driver_data = SDCA_FUNCTION_TYPE_HID,
},
+ {
+ .name = "snd_soc_sdca." SDCA_FUNCTION_TYPE_RJ_NAME,
+ .driver_data = SDCA_FUNCTION_TYPE_RJ,
+ },
{},
};
MODULE_DEVICE_TABLE(auxiliary, class_function_id_table);
diff --git a/sound/soc/sdca/sdca_fdl.c b/sound/soc/sdca/sdca_fdl.c
index 07892bc3a44e..994821a6df61 100644
--- a/sound/soc/sdca/sdca_fdl.c
+++ b/sound/soc/sdca/sdca_fdl.c
@@ -46,11 +46,6 @@ int sdca_reset_function(struct device *dev, struct sdca_function_data *function,
if (ret) // Allowed for function reset to not be implemented
return 0;
- if (!function->reset_max_delay) {
- dev_err(dev, "No reset delay specified in DisCo\n");
- return -EINVAL;
- }
-
/*
* Poll up to 16 times but no more than once per ms, these are just
* arbitrarily selected values, so may be fine tuned in future.
diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c
index dca60ee8e62c..fd6a254c9530 100644
--- a/sound/soc/sdca/sdca_functions.c
+++ b/sound/soc/sdca/sdca_functions.c
@@ -2176,8 +2176,12 @@ int sdca_parse_function(struct device *dev, struct sdw_slave *sdw,
ret = fwnode_property_read_u32(function_desc->node,
"mipi-sdca-function-reset-max-delay", &tmp);
- if (!ret)
+ if (ret || tmp == 0) {
+ dev_dbg(dev, "reset delay missing, defaulting to 100mS\n");
+ function->reset_max_delay = 100000;
+ } else {
function->reset_max_delay = tmp;
+ }
dev_dbg(dev, "%pfwP: name %s busy delay %dus reset delay %dus\n",
function->desc->node, function->desc->name,
diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c
index 5cdabf8ae9da..6e10b4e660d9 100644
--- a/sound/soc/sdca/sdca_interrupts.c
+++ b/sound/soc/sdca/sdca_interrupts.c
@@ -119,7 +119,17 @@ static irqreturn_t function_status_handler(int irq, void *data)
for_each_set_bit(mask, &status, BITS_PER_BYTE) {
switch (BIT(mask)) {
case SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION:
- //FIXME: Add init writes
+/*
+ * FIXME: Should this do init writes?
+ *
+ * Currently init writes/cache sync are done from the suspend/resume
+ * infrastructure. It is unclear in what situations one would receive this
+ * IRQ outside of that flow. Presumably it would be something like the chip
+ * crashing. In that case however doing the init writes and a cache sync might
+ * not be sufficient, for example if the failure was during audio playback
+ * there could be ordering constraints on the register writes to restore the
+ * state that are not handled by a simple cache sync.
+ */
break;
case SDCA_CTL_ENTITY_0_FUNCTION_FAULT:
dev_err(dev, "function fault\n");
@@ -555,7 +565,7 @@ EXPORT_SYMBOL_NS_GPL(sdca_irq_populate, "SND_SOC_SDCA");
/**
* sdca_irq_cleanup - Free all the individual IRQs for an SDCA Function
- * @sdev: Device pointer against which the sdca_interrupt_info was allocated.
+ * @dev: Device pointer against which the sdca_interrupt_info was allocated.
* @function: Pointer to the SDCA Function.
* @info: Pointer to the SDCA interrupt info for this device.
*
@@ -630,13 +640,12 @@ EXPORT_SYMBOL_NS_GPL(sdca_irq_allocate, "SND_SOC_SDCA");
static void irq_enable_flags(struct sdca_function_data *function,
struct sdca_interrupt_info *info, bool early)
{
- struct sdca_interrupt *interrupt;
int i;
for (i = 0; i < SDCA_MAX_INTERRUPTS; i++) {
- interrupt = &info->irqs[i];
+ struct sdca_interrupt *interrupt = &info->irqs[i];
- if (!interrupt || interrupt->function != function)
+ if (!interrupt->irq || interrupt->function != function)
continue;
switch (SDCA_CTL_TYPE(interrupt->entity->type,
@@ -689,13 +698,12 @@ EXPORT_SYMBOL_NS_GPL(sdca_irq_enable, "SND_SOC_SDCA");
void sdca_irq_disable(struct sdca_function_data *function,
struct sdca_interrupt_info *info)
{
- struct sdca_interrupt *interrupt;
int i;
for (i = 0; i < SDCA_MAX_INTERRUPTS; i++) {
- interrupt = &info->irqs[i];
+ struct sdca_interrupt *interrupt = &info->irqs[i];
- if (!interrupt || interrupt->function != function)
+ if (!interrupt->irq || interrupt->function != function)
continue;
disable_irq(interrupt->irq);
diff --git a/sound/soc/sdw_utils/Makefile b/sound/soc/sdw_utils/Makefile
index e8bd5ffb1a6a..a8d091fd374b 100644
--- a/sound/soc/sdw_utils/Makefile
+++ b/sound/soc/sdw_utils/Makefile
@@ -6,6 +6,7 @@ snd-soc-sdw-utils-y := soc_sdw_utils.o soc_sdw_dmic.o soc_sdw_rt_dmic.o \
soc_sdw_bridge_cs35l56.o \
soc_sdw_cs42l42.o soc_sdw_cs42l43.o \
soc_sdw_cs42l45.o \
+ soc_sdw_cs47l47.o \
soc_sdw_cs_amp.o \
soc_sdw_maxim.o \
soc_sdw_ti_amp.o
diff --git a/sound/soc/sdw_utils/soc_sdw_cs42l43.c b/sound/soc/sdw_utils/soc_sdw_cs42l43.c
index 2685ff4f0932..4a451b9d4f13 100644
--- a/sound/soc/sdw_utils/soc_sdw_cs42l43.c
+++ b/sound/soc/sdw_utils/soc_sdw_cs42l43.c
@@ -107,6 +107,7 @@ EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_hs_rtd_init, "SND_SOC_SDW_UTILS");
int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
struct snd_soc_card *card = rtd->card;
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
@@ -131,8 +132,15 @@ int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_so
ret = snd_soc_dapm_add_routes(dapm, cs42l43_spk_map,
ARRAY_SIZE(cs42l43_spk_map));
- if (ret)
+ if (ret) {
dev_err(card->dev, "cs42l43 speaker map addition failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_set_sysclk(component, CS42L43_SYSCLK, CS42L43_SYSCLK_SDW,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret)
+ dev_err(card->dev, "Failed to set sysclk: %d\n", ret);
return ret;
}
diff --git a/sound/soc/sdw_utils/soc_sdw_cs47l47.c b/sound/soc/sdw_utils/soc_sdw_cs47l47.c
new file mode 100644
index 000000000000..259ecf1e0a71
--- /dev/null
+++ b/sound/soc/sdw_utils/soc_sdw_cs47l47.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Based on sof_sdw_cs42l45.c
+// This file incorporates work covered by the following copyright notice:
+// Copyright (c) 2023 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
+
+/*
+ * soc_sdw_cs47l47 - Helpers to handle CS47L47 from generic machine driver
+ */
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-card.h>
+#include <sound/soc-component.h>
+#include <sound/soc-dai.h>
+#include <sound/soc_sdw_utils.h>
+
+static struct snd_soc_jack_pin soc_jack_pins[] = {
+ {
+ .pin = "cs47l47 OT 43 Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "cs47l47 OT 45 Headset",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "cs47l47 IT 31 Microphone",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "cs47l47 IT 33 Headset",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+int asoc_sdw_cs47l47_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_jack *jack = &ctx->sdw_headset;
+ int ret;
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s hs:cs47l47",
+ card->components);
+ if (!card->components)
+ return -ENOMEM;
+
+ ret = snd_soc_card_jack_new_pins(card, "Jack", SND_JACK_MECHANICAL |
+ SND_JACK_HEADSET | SND_JACK_LINEOUT, jack,
+ soc_jack_pins, ARRAY_SIZE(soc_jack_pins));
+ if (ret) {
+ dev_err(card->dev, "Failed to create jack: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_set_jack(component, jack, NULL);
+ if (ret) {
+ dev_err(card->dev, "Failed to register jack: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_cs47l47_hs_rtd_init, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_cs47l47_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_card *card = rtd->card;
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s mic:cs47l47-dmic",
+ card->components);
+ if (!card->components)
+ return -ENOMEM;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_cs47l47_dmic_rtd_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/sdw_utils/soc_sdw_rt_dmic.c b/sound/soc/sdw_utils/soc_sdw_rt_dmic.c
index 97be110a59b6..fed85bad9e88 100644
--- a/sound/soc/sdw_utils/soc_sdw_rt_dmic.c
+++ b/sound/soc/sdw_utils/soc_sdw_rt_dmic.c
@@ -9,15 +9,20 @@
#include <linux/device.h>
#include <linux/errno.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <sound/soc_sdw_utils.h>
+#include <sound/sdca_function.h>
int asoc_sdw_rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
struct snd_soc_card *card = rtd->card;
struct snd_soc_component *component;
+ struct sdw_slave *sdw_peripheral = NULL;
char *mic_name;
+ int rt1320_dmic_num = 0, part_id, i;
component = dai->component;
@@ -32,9 +37,44 @@ int asoc_sdw_rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_da
if (!mic_name)
return -ENOMEM;
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s mic:%s", card->components,
- mic_name);
+ /*
+ * If there is any rt1320/rt1321 DMIC belonging to this card, try to count the `cfg-mics`
+ * to be used in card->components.
+ * Note: The rt1320 drivers register the peripheral dev to component->dev, so get the
+ * sdw_peripheral from component->dev.
+ */
+ if (is_sdw_slave(component->dev))
+ sdw_peripheral = dev_to_sdw_dev(component->dev);
+ if (sdw_peripheral &&
+ (sdw_peripheral->id.part_id == 0x1320 || sdw_peripheral->id.part_id == 0x1321)) {
+ part_id = sdw_peripheral->id.part_id;
+ /*
+ * This rtd init callback is called once, so count the rt1320/rt1321 with SDCA
+ * function SmartMic type in this card.
+ */
+ for_each_card_components(card, component) {
+ if (!is_sdw_slave(component->dev))
+ continue;
+ sdw_peripheral = dev_to_sdw_dev(component->dev);
+ if (sdw_peripheral->id.part_id != part_id)
+ continue;
+ for (i = 0; i < sdw_peripheral->sdca_data.num_functions; i++) {
+ if (sdw_peripheral->sdca_data.function[i].type ==
+ SDCA_FUNCTION_TYPE_SMART_MIC) {
+ rt1320_dmic_num++;
+ break;
+ }
+ }
+ }
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s mic:%s cfg-mics:%d", card->components,
+ mic_name, rt1320_dmic_num);
+ } else {
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s mic:%s", card->components,
+ mic_name);
+ }
+
if (!card->components)
return -ENOMEM;
diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c
index 0e67d9f34cba..2807f536eef0 100644
--- a/sound/soc/sdw_utils/soc_sdw_utils.c
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -73,6 +73,7 @@ static const struct snd_kcontrol_new rt700_controls[] = {
struct asoc_sdw_codec_info codec_info_list[] = {
{
+ .vendor_id = 0x0102,
.part_id = 0x0000, /* TAS2783A */
.name_prefix = "tas2783",
.dais = {
@@ -92,6 +93,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x700,
.name_prefix = "rt700",
.dais = {
@@ -110,6 +112,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x711,
.name_prefix = "rt711",
.version_id = 3,
@@ -131,6 +134,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x711,
.name_prefix = "rt711",
.version_id = 2,
@@ -152,6 +156,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x712,
.name_prefix = "rt712",
.version_id = 3,
@@ -194,6 +199,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 3,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x1712,
.name_prefix = "rt712-dmic",
.version_id = 3,
@@ -209,6 +215,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x713,
.name_prefix = "rt713",
.version_id = 3,
@@ -237,6 +244,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 2,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x1713,
.name_prefix = "rt713-dmic",
.version_id = 3,
@@ -252,6 +260,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x1308,
.name_prefix = "rt1308",
.acpi_id = "10EC1308",
@@ -275,6 +284,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.ops = &soc_sdw_rt1308_i2s_ops,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x1316,
.name_prefix = "rt1316",
.dais = {
@@ -296,6 +306,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x1318,
.name_prefix = "rt1318",
.dais = {
@@ -317,8 +328,10 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x1320,
.name_prefix = "rt1320",
+ .is_amp = true,
.dais = {
{
.direction = {true, false},
@@ -334,12 +347,24 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.widgets = generic_spk_widgets,
.num_widgets = ARRAY_SIZE(generic_spk_widgets),
},
+ {
+ .direction = {false, true},
+ .dai_name = "rt1320-aif2",
+ .component_name = "rt1320",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ .widgets = generic_dmic_widgets,
+ .num_widgets = ARRAY_SIZE(generic_dmic_widgets),
+ },
},
- .dai_num = 1,
+ .dai_num = 2,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x1321,
.name_prefix = "rt1320",
+ .is_amp = true,
.dais = {
{
.direction = {true, false},
@@ -355,10 +380,21 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.widgets = generic_spk_widgets,
.num_widgets = ARRAY_SIZE(generic_spk_widgets),
},
+ {
+ .direction = {false, true},
+ .dai_name = "rt1320-aif2",
+ .component_name = "rt1320",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ .widgets = generic_dmic_widgets,
+ .num_widgets = ARRAY_SIZE(generic_dmic_widgets),
+ },
},
- .dai_num = 1,
+ .dai_num = 2,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x714,
.name_prefix = "rt714",
.version_id = 3,
@@ -375,6 +411,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x715,
.name_prefix = "rt715",
.version_id = 3,
@@ -391,6 +428,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x714,
.name_prefix = "rt714",
.version_id = 2,
@@ -407,6 +445,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x715,
.name_prefix = "rt715",
.version_id = 2,
@@ -423,6 +462,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x721,
.name_prefix = "rt721",
.version_id = 3,
@@ -466,6 +506,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 3,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x722,
.name_prefix = "rt722",
.version_id = 3,
@@ -513,6 +554,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 3,
},
{
+ .vendor_id = 0x019f,
.part_id = 0x8373,
.name_prefix = "Left",
.dais = {
@@ -533,6 +575,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x019f,
.part_id = 0x8363,
.name_prefix = "Left",
.dais = {
@@ -553,6 +596,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x025d,
.part_id = 0x5682,
.name_prefix = "rt5682",
.dais = {
@@ -571,6 +615,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x01fa,
.part_id = 0x3556,
.name_prefix = "AMP",
.dais = {
@@ -598,6 +643,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 2,
},
{
+ .vendor_id = 0x01fa,
.part_id = 0x3557,
.name_prefix = "AMP",
.dais = {
@@ -625,6 +671,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 2,
},
{
+ .vendor_id = 0x01fa,
.part_id = 0x3563,
.name_prefix = "AMP",
.dais = {
@@ -652,6 +699,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 2,
},
{
+ .vendor_id = 0x01fa,
.part_id = 0x4242,
.name_prefix = "cs42l42",
.dais = {
@@ -670,6 +718,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x01fa,
.part_id = 0x4243,
.name_prefix = "cs42l43",
.count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar,
@@ -724,12 +773,105 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 4,
},
{
+ .vendor_id = 0x01fa,
+ .part_id = 0x2A3B,
+ .name_prefix = "cs42l43",
+ .count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar,
+ .add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar,
+ .dais = {
+ {
+ .direction = {true, false},
+ .codec_name = "cs42l43-codec",
+ .dai_name = "cs42l43-dp5",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .rtd_init = asoc_sdw_cs42l43_hs_rtd_init,
+ .controls = generic_jack_controls,
+ .num_controls = ARRAY_SIZE(generic_jack_controls),
+ .widgets = generic_jack_widgets,
+ .num_widgets = ARRAY_SIZE(generic_jack_widgets),
+ },
+ {
+ .direction = {false, true},
+ .codec_name = "cs42l43-codec",
+ .dai_name = "cs42l43-dp1",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init,
+ .widgets = generic_dmic_widgets,
+ .num_widgets = ARRAY_SIZE(generic_dmic_widgets),
+ .quirk = SOC_SDW_CODEC_MIC,
+ .quirk_exclude = true,
+ },
+ {
+ .direction = {false, true},
+ .codec_name = "cs42l43-codec",
+ .dai_name = "cs42l43-dp2",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ },
+ {
+ .direction = {true, false},
+ .codec_name = "cs42l43-codec",
+ .dai_name = "cs42l43-dp6",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .init = asoc_sdw_cs42l43_spk_init,
+ .rtd_init = asoc_sdw_cs42l43_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),
+ .quirk = SOC_SDW_CODEC_SPKR | SOC_SDW_SIDECAR_AMPS,
+ },
+ },
+ .dai_num = 4,
+ },
+ {
+ .vendor_id = 0x01fa,
.part_id = 0x4245,
.name_prefix = "cs42l45",
.dais = {
{
.direction = {true, false},
- .codec_name = "snd_soc_sdca.UAJ.1",
+ .codec_name = "snd_soc_sdca.UAJ",
+ .dai_name = "IT 41",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .rtd_init = asoc_sdw_cs42l45_hs_rtd_init,
+ },
+ {
+ .direction = {false, true},
+ .codec_name = "snd_soc_sdca.SmartMic",
+ .dai_name = "OT 113",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_cs42l45_dmic_rtd_init,
+ },
+ {
+ .direction = {false, true},
+ .codec_name = "snd_soc_sdca.UAJ",
+ .dai_name = "OT 36",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ },
+ },
+ .dai_num = 3,
+ .auxs = {
+ {
+ .codec_name = "snd_soc_sdca.HID",
+ },
+ },
+ .aux_num = 1,
+ },
+ {
+ .vendor_id = 0x01fa,
+ .part_id = 0x4249,
+ .name_prefix = "cs42l45", /* Use same user-space as cs42l45 */
+ .dais = {
+ {
+ .direction = {true, false},
+ .codec_name = "snd_soc_sdca.UAJ",
.dai_name = "IT 41",
.dai_type = SOC_SDW_DAI_TYPE_JACK,
.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
@@ -737,7 +879,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
},
{
.direction = {false, true},
- .codec_name = "snd_soc_sdca.SmartMic.0",
+ .codec_name = "snd_soc_sdca.SmartMic",
.dai_name = "OT 113",
.dai_type = SOC_SDW_DAI_TYPE_MIC,
.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
@@ -745,7 +887,44 @@ struct asoc_sdw_codec_info codec_info_list[] = {
},
{
.direction = {false, true},
- .codec_name = "snd_soc_sdca.UAJ.1",
+ .codec_name = "snd_soc_sdca.UAJ",
+ .dai_name = "OT 36",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ },
+ },
+ .dai_num = 3,
+ .auxs = {
+ {
+ .codec_name = "snd_soc_sdca.HID",
+ },
+ },
+ .aux_num = 1,
+ },
+ {
+ .vendor_id = 0x01fa,
+ .part_id = 0x4747,
+ .name_prefix = "cs47l47",
+ .dais = {
+ {
+ .direction = {true, false},
+ .codec_name = "snd_soc_sdca.UAJ",
+ .dai_name = "IT 41",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .rtd_init = asoc_sdw_cs47l47_hs_rtd_init,
+ },
+ {
+ .direction = {false, true},
+ .codec_name = "snd_soc_sdca.SmartMic",
+ .dai_name = "OT 113",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_cs47l47_dmic_rtd_init,
+ },
+ {
+ .direction = {false, true},
+ .codec_name = "snd_soc_sdca.UAJ",
.dai_name = "OT 36",
.dai_type = SOC_SDW_DAI_TYPE_JACK,
.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
@@ -754,12 +933,13 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 3,
.auxs = {
{
- .codec_name = "snd_soc_sdca.HID.2",
+ .codec_name = "snd_soc_sdca.HID",
},
},
.aux_num = 1,
},
{
+ .vendor_id = 0x0105,
.part_id = 0xaaaa, /* generic codec mockup */
.name_prefix = "sdw_mockup_mmulti-function",
.version_id = 0,
@@ -786,6 +966,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 3,
},
{
+ .vendor_id = 0x0105,
.part_id = 0xaa55, /* headset codec mockup */
.name_prefix = "sdw_mockup_headset0",
.version_id = 0,
@@ -800,6 +981,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x0105,
.part_id = 0x55aa, /* amplifier mockup */
.name_prefix = "sdw_mockup_amp1",
.version_id = 0,
@@ -814,6 +996,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .vendor_id = 0x0105,
.part_id = 0x5555,
.name_prefix = "sdw_mockup_mic0",
.version_id = 0,
@@ -838,9 +1021,10 @@ EXPORT_SYMBOL_NS(asoc_sdw_get_codec_info_list_count, "SND_SOC_SDW_UTILS");
struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr)
{
- unsigned int part_id, sdw_version;
+ unsigned int vendor_id, part_id, sdw_version;
int i;
+ vendor_id = SDW_MFG_ID(adr);
part_id = SDW_PART_ID(adr);
sdw_version = SDW_VERSION(adr);
for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
@@ -849,6 +1033,7 @@ struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr)
* version_id is not specified in the codec info.
*/
if (part_id == codec_info_list[i].part_id &&
+ vendor_id == codec_info_list[i].vendor_id &&
(!codec_info_list[i].version_id ||
sdw_version == codec_info_list[i].version_id))
return &codec_info_list[i];
@@ -863,6 +1048,7 @@ static struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_sdw_id(const struct
for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
if (id->part_id == codec_info_list[i].part_id &&
+ id->mfg_id == codec_info_list[i].vendor_id &&
(!codec_info_list[i].version_id ||
id->sdw_version == codec_info_list[i].version_id))
return &codec_info_list[i];
@@ -967,8 +1153,8 @@ int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)
ret = snd_soc_add_card_controls(card, codec_info->dais[dai_index].controls,
codec_info->dais[dai_index].num_controls);
if (ret) {
- dev_err(card->dev, "%#x controls addition failed: %d\n",
- codec_info->part_id, ret);
+ dev_err(card->dev, "%#x-%#x controls addition failed: %d\n",
+ codec_info->vendor_id, codec_info->part_id, ret);
return ret;
}
}
@@ -977,8 +1163,8 @@ int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)
codec_info->dais[dai_index].widgets,
codec_info->dais[dai_index].num_widgets);
if (ret) {
- dev_err(card->dev, "%#x widgets addition failed: %d\n",
- codec_info->part_id, ret);
+ dev_err(card->dev, "%#x-%#x widgets addition failed: %d\n",
+ codec_info->vendor_id, codec_info->part_id, ret);
return ret;
}
}
@@ -1215,8 +1401,18 @@ const char *asoc_sdw_get_codec_name(struct device *dev,
const struct snd_soc_acpi_link_adr *adr_link,
int adr_index)
{
- if (dai_info->codec_name)
- return devm_kstrdup(dev, dai_info->codec_name, GFP_KERNEL);
+ if (dai_info->codec_name) {
+ struct snd_soc_component *component;
+
+ component = snd_soc_lookup_component_by_name(dai_info->codec_name);
+ if (component) {
+ dev_dbg(dev, "%s found component %s for codec_name %s\n",
+ __func__, component->name, dai_info->codec_name);
+ return devm_kstrdup(dev, component->name, GFP_KERNEL);
+ } else {
+ return devm_kstrdup(dev, dai_info->codec_name, GFP_KERNEL);
+ }
+ }
return _asoc_sdw_get_codec_name(dev, adr_link, adr_index);
}
@@ -1528,7 +1724,17 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
return -EINVAL;
for (j = 0; j < codec_info->aux_num; j++) {
- soc_aux->dlc.name = codec_info->auxs[j].codec_name;
+ struct snd_soc_component *component;
+
+ component = snd_soc_lookup_component_by_name(codec_info->auxs[j].codec_name);
+ if (component) {
+ dev_dbg(dev, "%s found component %s for aux name %s\n",
+ __func__, component->name,
+ codec_info->auxs[j].codec_name);
+ soc_aux->dlc.name = component->name;
+ } else {
+ soc_aux->dlc.name = codec_info->auxs[j].codec_name;
+ }
soc_aux++;
}
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c
index 89f236ab3034..21492d15833f 100644
--- a/sound/soc/soc-component.c
+++ b/sound/soc/soc-component.c
@@ -342,14 +342,22 @@ int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component,
return -ENOTSUPP;
}
-void snd_soc_component_setup_regmap(struct snd_soc_component *component)
+int snd_soc_component_regmap_val_bytes(struct snd_soc_component *component)
{
- int val_bytes = regmap_get_val_bytes(component->regmap);
+ int val_bytes;
/* Errors are legitimate for non-integer byte multiples */
- if (val_bytes > 0)
- component->val_bytes = val_bytes;
+
+ if (!component->regmap)
+ return 0;
+
+ val_bytes = regmap_get_val_bytes(component->regmap);
+ if (val_bytes < 0)
+ return 0;
+
+ return val_bytes;
}
+EXPORT_SYMBOL_GPL(snd_soc_component_regmap_val_bytes);
#ifdef CONFIG_REGMAP
@@ -368,7 +376,6 @@ void snd_soc_component_init_regmap(struct snd_soc_component *component,
struct regmap *regmap)
{
component->regmap = regmap;
- snd_soc_component_setup_regmap(component);
}
EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap);
@@ -1037,8 +1044,8 @@ int snd_soc_pcm_component_new(struct snd_soc_pcm_runtime *rtd)
int i;
for_each_rtd_components(rtd, i, component) {
- if (component->driver->pcm_construct) {
- ret = component->driver->pcm_construct(component, rtd);
+ if (component->driver->pcm_new) {
+ ret = component->driver->pcm_new(component, rtd);
if (ret < 0)
return soc_component_ret(component, ret);
}
@@ -1056,8 +1063,8 @@ void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd)
return;
for_each_rtd_components(rtd, i, component)
- if (component->driver->pcm_destruct)
- component->driver->pcm_destruct(component, rtd->pcm);
+ if (component->driver->pcm_free)
+ component->driver->pcm_free(component, rtd->pcm);
}
int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream)
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 7b81dffc6a93..b8402802ae78 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -69,10 +69,10 @@ static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback)
snd_soc_dai_digital_mute(codec_dai, 1, stream);
if (!snd_soc_dai_active(cpu_dai))
- cpu_dai->symmetric_rate = 0;
+ soc_pcm_set_dai_params(cpu_dai, NULL);
if (!snd_soc_dai_active(codec_dai))
- codec_dai->symmetric_rate = 0;
+ soc_pcm_set_dai_params(codec_dai, NULL);
snd_soc_link_compr_shutdown(cstream, rollback);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index ff6eb6bfc63b..3fecf9fc903c 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -167,15 +167,12 @@ static int dai_list_show(struct seq_file *m, void *v)
{
struct snd_soc_component *component;
struct snd_soc_dai *dai;
-
- mutex_lock(&client_mutex);
+ guard(mutex)(&client_mutex);
for_each_component(component)
for_each_component_dais(component, dai)
seq_printf(m, "%s\n", dai->name);
- mutex_unlock(&client_mutex);
-
return 0;
}
DEFINE_SHOW_ATTRIBUTE(dai_list);
@@ -183,14 +180,11 @@ DEFINE_SHOW_ATTRIBUTE(dai_list);
static int component_list_show(struct seq_file *m, void *v)
{
struct snd_soc_component *component;
-
- mutex_lock(&client_mutex);
+ guard(mutex)(&client_mutex);
for_each_component(component)
seq_printf(m, "%s\n", component->name);
- mutex_unlock(&client_mutex);
-
return 0;
}
DEFINE_SHOW_ATTRIBUTE(component_list);
@@ -394,15 +388,24 @@ EXPORT_SYMBOL_GPL(snd_soc_lookup_component_nolocked);
struct snd_soc_component *snd_soc_lookup_component(struct device *dev,
const char *driver_name)
{
+ guard(mutex)(&client_mutex);
+
+ return snd_soc_lookup_component_nolocked(dev, driver_name);
+}
+EXPORT_SYMBOL_GPL(snd_soc_lookup_component);
+
+struct snd_soc_component *snd_soc_lookup_component_by_name(const char *component_name)
+{
struct snd_soc_component *component;
- mutex_lock(&client_mutex);
- component = snd_soc_lookup_component_nolocked(dev, driver_name);
- mutex_unlock(&client_mutex);
+ guard(mutex)(&client_mutex);
+ for_each_component(component)
+ if (strstr(component->name, component_name))
+ return component;
- return component;
+ return NULL;
}
-EXPORT_SYMBOL_GPL(snd_soc_lookup_component);
+EXPORT_SYMBOL_GPL(snd_soc_lookup_component_by_name);
struct snd_soc_pcm_runtime
*snd_soc_get_pcm_runtime(struct snd_soc_card *card,
@@ -936,13 +939,9 @@ EXPORT_SYMBOL_GPL(snd_soc_find_dai);
struct snd_soc_dai *snd_soc_find_dai_with_mutex(
const struct snd_soc_dai_link_component *dlc)
{
- struct snd_soc_dai *dai;
-
- mutex_lock(&client_mutex);
- dai = snd_soc_find_dai(dlc);
- mutex_unlock(&client_mutex);
+ guard(mutex)(&client_mutex);
- return dai;
+ return snd_soc_find_dai(dlc);
}
EXPORT_SYMBOL_GPL(snd_soc_find_dai_with_mutex);
@@ -2154,8 +2153,6 @@ static void snd_soc_unbind_card(struct snd_soc_card *card)
{
if (snd_soc_card_is_instantiated(card)) {
card->instantiated = false;
- snd_soc_flush_all_delayed_work(card);
-
soc_cleanup_card_resources(card);
}
}
@@ -2575,14 +2572,13 @@ int snd_soc_register_card(struct snd_soc_card *card)
INIT_LIST_HEAD(&card->list);
INIT_LIST_HEAD(&card->rtd_list);
INIT_LIST_HEAD(&card->dapm_dirty);
- INIT_LIST_HEAD(&card->dobj_list);
card->instantiated = 0;
mutex_init(&card->mutex);
mutex_init(&card->dapm_mutex);
mutex_init(&card->pcm_mutex);
- mutex_lock(&client_mutex);
+ guard(mutex)(&client_mutex);
if (card->devres_dev) {
ret = devm_snd_soc_bind_card(card->devres_dev, card);
@@ -2594,8 +2590,6 @@ int snd_soc_register_card(struct snd_soc_card *card)
ret = snd_soc_bind_card(card);
}
- mutex_unlock(&client_mutex);
-
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_register_card);
@@ -2608,10 +2602,11 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card);
*/
void snd_soc_unregister_card(struct snd_soc_card *card)
{
- mutex_lock(&client_mutex);
+ guard(mutex)(&client_mutex);
+
snd_soc_unbind_card(card);
list_del(&card->list);
- mutex_unlock(&client_mutex);
+
dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_card);
@@ -2889,8 +2884,7 @@ int snd_soc_add_component(struct snd_soc_component *component,
struct snd_soc_card *card, *c;
int ret;
int i;
-
- mutex_lock(&client_mutex);
+ guard(mutex)(&client_mutex);
if (component->driver->endianness) {
for (i = 0; i < num_dai; i++) {
@@ -2910,8 +2904,6 @@ int snd_soc_add_component(struct snd_soc_component *component,
if (!component->regmap)
component->regmap = dev_get_regmap(component->dev,
NULL);
- if (component->regmap)
- snd_soc_component_setup_regmap(component);
}
/* see for_each_component */
@@ -2924,7 +2916,6 @@ err_cleanup:
if (ret < 0)
snd_soc_del_component_unlocked(component);
- mutex_unlock(&client_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_add_component);
@@ -2964,7 +2955,8 @@ void snd_soc_unregister_component_by_driver(struct device *dev,
if (component_driver)
driver_name = component_driver->name;
- mutex_lock(&client_mutex);
+ guard(mutex)(&client_mutex);
+
while (1) {
struct snd_soc_component *component = snd_soc_lookup_component_nolocked(dev, driver_name);
@@ -2973,7 +2965,6 @@ void snd_soc_unregister_component_by_driver(struct device *dev,
snd_soc_del_component_unlocked(component);
}
- mutex_unlock(&client_mutex);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_component_by_driver);
@@ -3509,7 +3500,6 @@ EXPORT_SYMBOL_GPL(snd_soc_get_stream_cpu);
int snd_soc_get_dai_id(struct device_node *ep)
{
- struct snd_soc_component *component;
struct snd_soc_dai_link_component dlc = {
.of_node = of_graph_get_port_parent(ep),
};
@@ -3523,11 +3513,13 @@ int snd_soc_get_dai_id(struct device_node *ep)
* Then, it should have .of_xlate_dai_id
*/
ret = -ENOTSUPP;
- mutex_lock(&client_mutex);
- component = soc_find_component(&dlc);
- if (component)
- ret = snd_soc_component_of_xlate_dai_id(component, ep);
- mutex_unlock(&client_mutex);
+
+ scoped_guard(mutex, &client_mutex) {
+ struct snd_soc_component *component = soc_find_component(&dlc);
+
+ if (component)
+ ret = snd_soc_component_of_xlate_dai_id(component, ep);
+ }
of_node_put(dlc.of_node);
@@ -3539,8 +3531,8 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_
{
struct snd_soc_component *pos;
int ret = -EPROBE_DEFER;
+ guard(mutex)(&client_mutex);
- mutex_lock(&client_mutex);
for_each_component(pos) {
struct device_node *component_of_node = soc_component_to_node(pos);
@@ -3595,7 +3587,6 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_
if (ret == 0)
dlc->of_node = args->np;
- mutex_unlock(&client_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_get_dlc);
@@ -3650,17 +3641,14 @@ struct snd_soc_dai *snd_soc_get_dai_via_args(const struct of_phandle_args *dai_a
{
struct snd_soc_dai *dai;
struct snd_soc_component *component;
+ guard(mutex)(&client_mutex);
- mutex_lock(&client_mutex);
for_each_component(component) {
for_each_component_dais(component, dai)
if (snd_soc_is_match_dai_args(dai->driver->dai_args, dai_args))
- goto found;
+ return dai;
}
- dai = NULL;
-found:
- mutex_unlock(&client_mutex);
- return dai;
+ return NULL;
}
EXPORT_SYMBOL_GPL(snd_soc_get_dai_via_args);
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index a1e05307067d..2f370fda1266 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -283,6 +283,46 @@ err:
EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
/**
+ * snd_soc_dai_set_tdm_idle() - Configure a DAI's TDM idle mode
+ * @dai: The DAI to configure
+ * @tx_mask: bitmask representing idle TX slots.
+ * @rx_mask: bitmask representing idle RX slots.
+ * @tx_mode: idle mode to set for TX slots.
+ * @rx_mode: idle mode to set for RX slots.
+ *
+ * This function configures the DAI to handle idle TDM slots in the
+ * specified manner. @tx_mode and @rx_mode can be one of
+ * SND_SOC_DAI_TDM_IDLE_NONE, SND_SOC_DAI_TDM_IDLE_ZERO,
+ * SND_SOC_DAI_TDM_IDLE_PULLDOWN, or SND_SOC_DAI_TDM_IDLE_HIZ.
+ * SND_SOC_TDM_IDLE_NONE represents the DAI's default/unset idle slot
+ * handling state and could be any of the other modes depending on the
+ * hardware behind the DAI. It is therefore undefined behaviour when set
+ * explicitly.
+ *
+ * Mode and mask can be set independently for both the TX and RX direction.
+ * Some hardware may ignore both TX and RX masks depending on its
+ * capabilities.
+ */
+int snd_soc_dai_set_tdm_idle(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int tx_mode, int rx_mode)
+{
+ int ret = -EOPNOTSUPP;
+
+ /* You can't write to the RX line */
+ if (rx_mode == SND_SOC_DAI_TDM_IDLE_ZERO)
+ return soc_dai_ret(dai, -EINVAL);
+
+ if (dai->driver->ops &&
+ dai->driver->ops->set_tdm_idle)
+ ret = dai->driver->ops->set_tdm_idle(dai, tx_mask, rx_mask,
+ tx_mode, rx_mode);
+
+ return soc_dai_ret(dai, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_idle);
+
+/**
* snd_soc_dai_set_channel_map - configure DAI audio channel map
* @dai: DAI
* @tx_num: how many TX channels
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 2768ba5bfc9f..d6192204e613 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -89,6 +89,7 @@ static int dapm_up_seq[] = {
[snd_soc_dapm_input] = 6,
[snd_soc_dapm_output] = 6,
[snd_soc_dapm_mux] = 7,
+ [snd_soc_dapm_mux_named_ctl] = 7,
[snd_soc_dapm_demux] = 7,
[snd_soc_dapm_dac] = 8,
[snd_soc_dapm_switch] = 9,
@@ -140,6 +141,7 @@ static int dapm_down_seq[] = {
[snd_soc_dapm_micbias] = 10,
[snd_soc_dapm_vmid] = 10,
[snd_soc_dapm_mux] = 11,
+ [snd_soc_dapm_mux_named_ctl] = 11,
[snd_soc_dapm_demux] = 11,
[snd_soc_dapm_aif_in] = 12,
[snd_soc_dapm_aif_out] = 12,
@@ -577,6 +579,7 @@ static int dapm_check_dynamic_path(
switch (sink->id) {
case snd_soc_dapm_mux:
+ case snd_soc_dapm_mux_named_ctl:
case snd_soc_dapm_switch:
case snd_soc_dapm_mixer:
case snd_soc_dapm_mixer_named_ctl:
@@ -668,6 +671,7 @@ static int dapm_add_path(
switch (wsink->id) {
case snd_soc_dapm_mux:
+ case snd_soc_dapm_mux_named_ctl:
ret = dapm_connect_mux(dapm, path, control, wsink);
if (ret != 0)
goto err;
@@ -766,6 +770,7 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
break;
case snd_soc_dapm_demux:
case snd_soc_dapm_mux:
+ case snd_soc_dapm_mux_named_ctl:
e = (struct soc_enum *)kcontrol->private_value;
if (e->autodisable) {
@@ -915,6 +920,7 @@ static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
break;
case snd_soc_dapm_demux:
case snd_soc_dapm_mux:
+ case snd_soc_dapm_mux_named_ctl:
data->widget->on_val = value >> data->widget->shift;
break;
default:
@@ -1198,6 +1204,7 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
wname_in_long_name = true;
kcname_in_long_name = true;
break;
+ case snd_soc_dapm_mux_named_ctl:
case snd_soc_dapm_mixer_named_ctl:
wname_in_long_name = false;
kcname_in_long_name = true;
@@ -1317,6 +1324,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
switch (w->id) {
case snd_soc_dapm_mux:
+ case snd_soc_dapm_mux_named_ctl:
dir = SND_SOC_DAPM_DIR_OUT;
type = "mux";
break;
@@ -2399,6 +2407,7 @@ static const char * const dapm_type_name[] = {
[snd_soc_dapm_input] = "input",
[snd_soc_dapm_output] = "output",
[snd_soc_dapm_mux] = "mux",
+ [snd_soc_dapm_mux_named_ctl] = "mux_named_ctl",
[snd_soc_dapm_demux] = "demux",
[snd_soc_dapm_mixer] = "mixer",
[snd_soc_dapm_mixer_named_ctl] = "mixer_named_ctl",
@@ -3347,6 +3356,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
dapm_new_mixer(w);
break;
case snd_soc_dapm_mux:
+ case snd_soc_dapm_mux_named_ctl:
case snd_soc_dapm_demux:
dapm_new_mux(w);
break;
@@ -3834,6 +3844,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
break;
case snd_soc_dapm_mux:
+ case snd_soc_dapm_mux_named_ctl:
case snd_soc_dapm_demux:
case snd_soc_dapm_switch:
case snd_soc_dapm_mixer:
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index dbec46703b35..6b8c65763c82 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -332,7 +332,7 @@ static const struct snd_soc_component_driver dmaengine_pcm_component = {
.hw_params = dmaengine_pcm_hw_params,
.trigger = dmaengine_pcm_trigger,
.pointer = dmaengine_pcm_pointer,
- .pcm_construct = dmaengine_pcm_new,
+ .pcm_new = dmaengine_pcm_new,
.sync_stop = dmaengine_pcm_sync_stop,
};
@@ -345,7 +345,7 @@ static const struct snd_soc_component_driver dmaengine_pcm_component_process = {
.trigger = dmaengine_pcm_trigger,
.pointer = dmaengine_pcm_pointer,
.copy = dmaengine_copy,
- .pcm_construct = dmaengine_pcm_new,
+ .pcm_new = dmaengine_pcm_new,
.sync_stop = dmaengine_pcm_sync_stop,
};
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index f966d4e13c7f..bbf277670718 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -110,37 +110,6 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
}
EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
-static int sdca_soc_q78_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val,
- unsigned int mask, unsigned int shift, int max,
- bool sx)
-{
- int val = reg_val;
-
- if (WARN_ON(!mc->shift))
- return -EINVAL;
-
- val = sign_extend32(val, mc->sign_bit);
- val = (((val * 100) >> 8) / (int)mc->shift);
- val -= mc->min;
-
- return val & mask;
-}
-
-static unsigned int sdca_soc_q78_ctl_to_reg(struct soc_mixer_control *mc, int val,
- unsigned int mask, unsigned int shift, int max)
-{
- unsigned int ret_val;
- int reg_val;
-
- if (WARN_ON(!mc->shift))
- return -EINVAL;
-
- reg_val = val + mc->min;
- ret_val = (int)((reg_val * mc->shift) << 8) / 100;
-
- return ret_val & mask;
-}
-
static int soc_mixer_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val,
unsigned int mask, unsigned int shift, int max,
bool sx)
@@ -234,27 +203,19 @@ static int soc_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol,
struct soc_mixer_control *mc, int mask, int max)
{
- unsigned int (*ctl_to_reg)(struct soc_mixer_control *, int, unsigned int, unsigned int, int);
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int val1, val_mask;
unsigned int val2 = 0;
bool double_r = false;
int ret;
- if (mc->sdca_q78) {
- ctl_to_reg = sdca_soc_q78_ctl_to_reg;
- val_mask = mask;
- } else {
- ctl_to_reg = soc_mixer_ctl_to_reg;
- val_mask = mask << mc->shift;
- }
-
ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[0], max);
if (ret)
return ret;
- val1 = ctl_to_reg(mc, ucontrol->value.integer.value[0],
+ val1 = soc_mixer_ctl_to_reg(mc, ucontrol->value.integer.value[0],
mask, mc->shift, max);
+ val_mask = mask << mc->shift;
if (snd_soc_volsw_is_stereo(mc)) {
ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[1], max);
@@ -262,10 +223,14 @@ static int soc_put_volsw(struct snd_kcontrol *kcontrol,
return ret;
if (mc->reg == mc->rreg) {
- val1 |= ctl_to_reg(mc, ucontrol->value.integer.value[1], mask, mc->rshift, max);
+ val1 |= soc_mixer_ctl_to_reg(mc,
+ ucontrol->value.integer.value[1],
+ mask, mc->rshift, max);
val_mask |= mask << mc->rshift;
} else {
- val2 = ctl_to_reg(mc, ucontrol->value.integer.value[1], mask, mc->shift, max);
+ val2 = soc_mixer_ctl_to_reg(mc,
+ ucontrol->value.integer.value[1],
+ mask, mc->shift, max);
double_r = true;
}
}
@@ -289,28 +254,21 @@ static int soc_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol,
struct soc_mixer_control *mc, int mask, int max, bool sx)
{
- int (*reg_to_ctl)(struct soc_mixer_control *, unsigned int, unsigned int,
- unsigned int, int, bool);
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg_val;
int val;
- if (mc->sdca_q78)
- reg_to_ctl = sdca_soc_q78_reg_to_ctl;
- else
- reg_to_ctl = soc_mixer_reg_to_ctl;
-
reg_val = snd_soc_component_read(component, mc->reg);
- val = reg_to_ctl(mc, reg_val, mask, mc->shift, max, sx);
+ val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max, sx);
ucontrol->value.integer.value[0] = val;
if (snd_soc_volsw_is_stereo(mc)) {
if (mc->reg == mc->rreg) {
- val = reg_to_ctl(mc, reg_val, mask, mc->rshift, max, sx);
+ val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->rshift, max, sx);
} else {
reg_val = snd_soc_component_read(component, mc->rreg);
- val = reg_to_ctl(mc, reg_val, mask, mc->shift, max, sx);
+ val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max, sx);
}
ucontrol->value.integer.value[1] = val;
@@ -514,9 +472,10 @@ int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_bytes *params = (void *)kcontrol->private_value;
+ int val_bytes = snd_soc_component_regmap_val_bytes(component);
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
- uinfo->count = params->num_regs * component->val_bytes;
+ uinfo->count = params->num_regs * val_bytes;
return 0;
}
@@ -527,18 +486,19 @@ int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_bytes *params = (void *)kcontrol->private_value;
+ int val_bytes = snd_soc_component_regmap_val_bytes(component);
int ret;
if (component->regmap)
ret = regmap_raw_read(component->regmap, params->base,
ucontrol->value.bytes.data,
- params->num_regs * component->val_bytes);
+ params->num_regs * val_bytes);
else
ret = -EINVAL;
/* Hide any masked bytes to ensure consistent data reporting */
if (ret == 0 && params->mask) {
- switch (component->val_bytes) {
+ switch (val_bytes) {
case 1:
ucontrol->value.bytes.data[0] &= ~params->mask;
break;
@@ -564,13 +524,14 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_bytes *params = (void *)kcontrol->private_value;
+ int val_bytes = snd_soc_component_regmap_val_bytes(component);
unsigned int val, mask;
int ret, len;
if (!component->regmap || !params->num_regs)
return -EINVAL;
- len = params->num_regs * component->val_bytes;
+ len = params->num_regs * val_bytes;
void *data __free(kfree) = kmemdup(ucontrol->value.bytes.data, len,
GFP_KERNEL | GFP_DMA);
@@ -589,7 +550,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
val &= params->mask;
- switch (component->val_bytes) {
+ switch (val_bytes) {
case 1:
((u8 *)data)[0] &= ~params->mask;
((u8 *)data)[0] |= val;
@@ -712,9 +673,10 @@ int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
+ int val_bytes = snd_soc_component_regmap_val_bytes(component);
unsigned int regbase = mc->regbase;
unsigned int regcount = mc->regcount;
- unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
+ unsigned int regwshift = val_bytes * BITS_PER_BYTE;
unsigned int regwmask = GENMASK(regwshift - 1, 0);
unsigned long mask = GENMASK(mc->nbits - 1, 0);
long val = 0;
@@ -756,9 +718,10 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
+ int val_bytes = snd_soc_component_regmap_val_bytes(component);
unsigned int regbase = mc->regbase;
unsigned int regcount = mc->regcount;
- unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
+ unsigned int regwshift = val_bytes * BITS_PER_BYTE;
unsigned int regwmask = GENMASK(regwshift - 1, 0);
unsigned long mask = GENMASK(mc->nbits - 1, 0);
long val = ucontrol->value.integer.value[0];
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index afa9fad4457f..9b12eedb77c3 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -423,8 +423,8 @@ void dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, int event)
snd_soc_dapm_stream_event(fe, dir, event);
}
-static void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
- struct snd_pcm_hw_params *params)
+void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
+ struct snd_pcm_hw_params *params)
{
if (params) {
dai->symmetric_rate = params_rate(params);
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 064b8d76b955..85679c8e0229 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -224,8 +224,11 @@ static inline void soc_control_err(struct soc_tplg *tplg,
struct snd_soc_tplg_ctl_hdr *hdr, const char *name)
{
dev_err(tplg->dev,
- "ASoC: no complete control IO handler for %s type (g,p,i) %d:%d:%d at 0x%lx\n",
- name, hdr->ops.get, hdr->ops.put, hdr->ops.info,
+ "ASoC: no complete control IO handler for %s type (g,p,i) %u:%u:%u at 0x%lx\n",
+ name,
+ le32_to_cpu(hdr->ops.get),
+ le32_to_cpu(hdr->ops.put),
+ le32_to_cpu(hdr->ops.info),
soc_tplg_get_offset(tplg));
}
@@ -238,17 +241,18 @@ static int soc_tplg_vendor_load(struct soc_tplg *tplg,
if (tplg->ops && tplg->ops->vendor_load)
ret = tplg->ops->vendor_load(tplg->comp, tplg->index, hdr);
else {
- dev_err(tplg->dev, "ASoC: no vendor load callback for ID %d\n",
- hdr->vendor_type);
+ dev_err(tplg->dev, "ASoC: no vendor load callback for ID %u\n",
+ le32_to_cpu(hdr->vendor_type));
return -EINVAL;
}
if (ret < 0)
dev_err(tplg->dev,
- "ASoC: vendor load failed at hdr offset %ld/0x%lx for type %d:%d\n",
+ "ASoC: vendor load failed at hdr offset %ld/0x%lx for type %u:%u\n",
soc_tplg_get_hdr_offset(tplg),
soc_tplg_get_hdr_offset(tplg),
- hdr->type, hdr->vendor_type);
+ le32_to_cpu(hdr->type),
+ le32_to_cpu(hdr->vendor_type));
return ret;
}
@@ -625,8 +629,8 @@ static int soc_tplg_create_tlv(struct soc_tplg *tplg,
/* TODO: add support for other TLV types */
default:
- dev_dbg(tplg->dev, "Unsupported TLV type %d\n",
- tplg_tlv->type);
+ dev_dbg(tplg->dev, "Unsupported TLV type %u\n",
+ le32_to_cpu(tplg_tlv->type));
return -EINVAL;
}
}
@@ -653,7 +657,7 @@ static int soc_tplg_control_dmixer_create(struct soc_tplg *tplg, struct snd_kcon
tplg->pos += sizeof(struct snd_soc_tplg_mixer_control) + le32_to_cpu(mc->priv.size);
dev_dbg(tplg->dev, "ASoC: adding mixer kcontrol %s with access 0x%x\n",
- mc->hdr.name, mc->hdr.access);
+ mc->hdr.name, le32_to_cpu(mc->hdr.access));
kc->name = devm_kstrdup(tplg->dev, mc->hdr.name, GFP_KERNEL);
if (!kc->name)
@@ -776,7 +780,7 @@ static int soc_tplg_control_denum_create(struct soc_tplg *tplg, struct snd_kcont
tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + le32_to_cpu(ec->priv.size));
- dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", ec->hdr.name, ec->items);
+ dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %u\n", ec->hdr.name, le32_to_cpu(ec->items));
kc->name = devm_kstrdup(tplg->dev, ec->hdr.name, GFP_KERNEL);
if (!kc->name)
@@ -811,8 +815,8 @@ static int soc_tplg_control_denum_create(struct soc_tplg *tplg, struct snd_kcont
}
break;
default:
- dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n",
- ec->hdr.ops.info, ec->hdr.name);
+ dev_err(tplg->dev, "ASoC: invalid enum control type %u for %s\n",
+ le32_to_cpu(ec->hdr.ops.info), ec->hdr.name);
return -EINVAL;
}
@@ -846,7 +850,7 @@ static int soc_tplg_control_dbytes_create(struct soc_tplg *tplg, struct snd_kcon
tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + le32_to_cpu(be->priv.size));
dev_dbg(tplg->dev, "ASoC: adding bytes kcontrol %s with access 0x%x\n",
- be->hdr.name, be->hdr.access);
+ be->hdr.name, le32_to_cpu(be->hdr.access));
kc->name = devm_kstrdup(tplg->dev, be->hdr.name, GFP_KERNEL);
if (!kc->name)
@@ -976,7 +980,7 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
int ret;
int i;
- dev_dbg(tplg->dev, "ASoC: adding %d kcontrols at 0x%lx\n", hdr->count,
+ dev_dbg(tplg->dev, "ASoC: adding %u kcontrols at 0x%lx\n", le32_to_cpu(hdr->count),
soc_tplg_get_offset(tplg));
for (i = 0; i < le32_to_cpu(hdr->count); i++) {
@@ -1003,8 +1007,8 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
}
if (ret < 0) {
- dev_err(tplg->dev, "ASoC: invalid control type: %d, index: %d at 0x%lx\n",
- control_hdr->type, i, soc_tplg_get_offset(tplg));
+ dev_err(tplg->dev, "ASoC: invalid control type: %u, index: %d at 0x%lx\n",
+ le32_to_cpu(control_hdr->type), i, soc_tplg_get_offset(tplg));
return ret;
}
}
@@ -1040,8 +1044,8 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
count, le32_to_cpu(hdr->payload_size), "graph"))
return -EINVAL;
- dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes for index %d\n", count,
- hdr->index);
+ dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes for index %u\n", count,
+ le32_to_cpu(hdr->index));
for (i = 0; i < count; i++) {
route = devm_kzalloc(tplg->dev, sizeof(*route), GFP_KERNEL);
@@ -1116,8 +1120,8 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
return -EINVAL;
- dev_dbg(tplg->dev, "ASoC: creating DAPM widget %s id %d\n",
- w->name, w->id);
+ dev_dbg(tplg->dev, "ASoC: creating DAPM widget %s id %u\n",
+ w->name, le32_to_cpu(w->id));
memset(&template, 0, sizeof(template));
@@ -1200,8 +1204,9 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
goto hdr_err;
break;
default:
- dev_err(tplg->dev, "ASoC: invalid widget control type %d:%d:%d\n",
- control_hdr->ops.get, control_hdr->ops.put,
+ dev_err(tplg->dev, "ASoC: invalid widget control type %u:%u:%u\n",
+ le32_to_cpu(control_hdr->ops.get),
+ le32_to_cpu(control_hdr->ops.put),
le32_to_cpu(control_hdr->ops.info));
ret = -EINVAL;
goto hdr_err;
@@ -1745,8 +1750,8 @@ static int soc_tplg_link_config(struct soc_tplg *tplg,
link = snd_soc_find_dai_link(tplg->comp->card, le32_to_cpu(cfg->id),
name, stream_name);
if (!link) {
- dev_err(tplg->dev, "ASoC: physical link %s (id %d) not exist\n",
- name, cfg->id);
+ dev_err(tplg->dev, "ASoC: physical link %s (id %u) not exist\n",
+ name, le32_to_cpu(cfg->id));
return -EINVAL;
}
@@ -1949,7 +1954,7 @@ static int soc_tplg_valid_header(struct soc_tplg *tplg,
{
if (le32_to_cpu(hdr->size) != sizeof(*hdr)) {
dev_err(tplg->dev,
- "ASoC: invalid header size for type %d at offset 0x%lx size 0x%zx.\n",
+ "ASoC: invalid header size for type %u at offset 0x%lx size 0x%zx.\n",
le32_to_cpu(hdr->type), soc_tplg_get_hdr_offset(tplg),
tplg->fw->size);
return -EINVAL;
@@ -1957,9 +1962,9 @@ static int soc_tplg_valid_header(struct soc_tplg *tplg,
if (soc_tplg_get_hdr_offset(tplg) + le32_to_cpu(hdr->payload_size) >= tplg->fw->size) {
dev_err(tplg->dev,
- "ASoC: invalid header of type %d at offset %ld payload_size %d\n",
+ "ASoC: invalid header of type %u at offset %ld payload_size %u\n",
le32_to_cpu(hdr->type), soc_tplg_get_hdr_offset(tplg),
- hdr->payload_size);
+ le32_to_cpu(hdr->payload_size));
return -EINVAL;
}
@@ -1967,7 +1972,7 @@ static int soc_tplg_valid_header(struct soc_tplg *tplg,
if (le32_to_cpu(hdr->magic) == SOC_TPLG_MAGIC_BIG_ENDIAN) {
dev_err(tplg->dev,
"ASoC: pass %d big endian not supported header got %x at offset 0x%lx size 0x%zx.\n",
- tplg->pass, hdr->magic,
+ tplg->pass, le32_to_cpu(hdr->magic),
soc_tplg_get_hdr_offset(tplg), tplg->fw->size);
return -EINVAL;
}
@@ -1975,7 +1980,7 @@ static int soc_tplg_valid_header(struct soc_tplg *tplg,
if (le32_to_cpu(hdr->magic) != SND_SOC_TPLG_MAGIC) {
dev_err(tplg->dev,
"ASoC: pass %d does not have a valid header got %x at offset 0x%lx size 0x%zx.\n",
- tplg->pass, hdr->magic,
+ tplg->pass, le32_to_cpu(hdr->magic),
soc_tplg_get_hdr_offset(tplg), tplg->fw->size);
return -EINVAL;
}
@@ -1985,7 +1990,7 @@ static int soc_tplg_valid_header(struct soc_tplg *tplg,
le32_to_cpu(hdr->abi) < SND_SOC_TPLG_ABI_VERSION_MIN) {
dev_err(tplg->dev,
"ASoC: pass %d invalid ABI version got 0x%x need 0x%x at offset 0x%lx size 0x%zx.\n",
- tplg->pass, hdr->abi,
+ tplg->pass, le32_to_cpu(hdr->abi),
SND_SOC_TPLG_ABI_VERSION, soc_tplg_get_hdr_offset(tplg),
tplg->fw->size);
return -EINVAL;
@@ -2054,9 +2059,11 @@ static int soc_tplg_load_header(struct soc_tplg *tplg,
if (tplg->pass == hdr_pass) {
dev_dbg(tplg->dev,
- "ASoC: Got 0x%x bytes of type %d version %d vendor %d at pass %d\n",
- hdr->payload_size, hdr->type, hdr->version,
- hdr->vendor_type, tplg->pass);
+ "ASoC: Got 0x%x bytes of type %u version %u vendor %u at pass %d\n",
+ le32_to_cpu(hdr->payload_size),
+ le32_to_cpu(hdr->type),
+ le32_to_cpu(hdr->version),
+ le32_to_cpu(hdr->vendor_type), tplg->pass);
return elem_load(tplg, hdr);
}
diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c
index 96570121aae0..93f2376585db 100644
--- a/sound/soc/sof/compress.c
+++ b/sound/soc/sof/compress.c
@@ -247,14 +247,15 @@ static int sof_compr_set_params(struct snd_soc_component *component,
ret = snd_sof_set_stream_data_offset(sdev, &spcm->stream[cstream->direction],
ipc_params_reply.posn_offset);
if (ret < 0) {
- dev_err(component->dev, "Invalid stream data offset for Compr %d\n",
- spcm->pcm.pcm_id);
+ dev_err(component->dev, "Invalid stream data offset for Compr %u\n",
+ le32_to_cpu(spcm->pcm.pcm_id));
goto out;
}
sstream->sampling_rate = params->codec.sample_rate;
sstream->channels = params->codec.ch_out;
sstream->sample_container_bytes = pcm->params.sample_container_bytes;
+ sstream->codec_params = params->codec;
spcm->prepared[cstream->direction] = true;
@@ -267,9 +268,10 @@ out:
static int sof_compr_get_params(struct snd_soc_component *component,
struct snd_compr_stream *cstream, struct snd_codec *params)
{
- /* TODO: we don't query the supported codecs for now, if the
- * application asks for an unsupported codec the set_params() will fail.
- */
+ struct sof_compr_stream *sstream = cstream->runtime->private_data;
+
+ *params = sstream->codec_params;
+
return 0;
}
@@ -379,6 +381,9 @@ static int sof_compr_pointer(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
+ if (!sstream->channels || !sstream->sample_container_bytes)
+ return -EBUSY;
+
tstamp->sampling_rate = sstream->sampling_rate;
tstamp->copied_total = sstream->copied_total;
tstamp->pcm_io_frames = div_u64(spcm->stream[cstream->direction].posn.dai_posn,
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index 1c04b5d9c0d8..5c1f3b427cdb 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -480,16 +480,20 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
struct snd_dma_buffer *dmab,
struct snd_pcm_hw_params *params)
{
- struct hdac_stream *hstream = &hext_stream->hstream;
- int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
+ struct hdac_stream *hstream;
+ int sd_offset;
int ret;
- u32 mask = 0x1 << hstream->index;
+ u32 mask;
if (!hext_stream) {
dev_err(sdev->dev, "error: no stream available\n");
return -ENODEV;
}
+ hstream = &hext_stream->hstream;
+ sd_offset = SOF_STREAM_SD_OFFSET(hstream);
+ mask = 0x1 << hstream->index;
+
if (!dmab) {
dev_err(sdev->dev, "error: no dma buffer allocated!\n");
return -ENODEV;
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 8a240dcb7fcb..b3d61d973ce4 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -1178,6 +1178,9 @@ static struct snd_soc_acpi_adr_device *find_acpi_adr_device(struct device *dev,
struct snd_soc_acpi_endpoint *endpoints;
int amp_group_id = 1;
+ if (sdw_device->id.mfg_id != codec_info_list[i].vendor_id)
+ continue;
+
if (sdw_device->id.part_id != codec_info_list[i].part_id)
continue;
@@ -1192,8 +1195,8 @@ static struct snd_soc_acpi_adr_device *find_acpi_adr_device(struct device *dev,
* dereference
*/
if (!name_prefix) {
- dev_err(dev, "codec_info_list name_prefix of part id %#x is missing\n",
- codec_info_list[i].part_id);
+ dev_err(dev, "codec_info_list name_prefix of part id %#x-%#x is missing\n",
+ codec_info_list[i].vendor_id, codec_info_list[i].part_id);
return NULL;
}
for (j = 0; j < codec_info_list[i].dai_num; j++) {
@@ -1227,6 +1230,16 @@ static struct snd_soc_acpi_adr_device *find_acpi_adr_device(struct device *dev,
return NULL;
}
+ /*
+ * codec_info_list[].is_amp is a codec-level override: for multi-function
+ * codecs we must treat the whole codec as an AMP when it is described as
+ * such in the codec info table, even if some endpoints were detected as
+ * non-AMP above. Callers/UCM rely on this to keep name_prefix and AMP
+ * indexing stable and backwards compatible.
+ */
+ if (codec_info_list[i].is_amp)
+ is_amp = true;
+
adr_dev[index].adr = ((u64)sdw_device->id.class_id & 0xFF) |
((u64)sdw_device->id.part_id & 0xFFFF) << 8 |
((u64)sdw_device->id.mfg_id & 0xFFFF) << 24 |
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index c12ffdcfe4e3..76812d8fb567 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -581,6 +581,7 @@ sof_ipc4_update_card_components_string(struct snd_sof_widget *swidget,
struct snd_soc_component *scomp = spcm->scomp;
struct snd_soc_card *card = scomp->card;
const char *pt_marker = "iec61937-pcm";
+ unsigned pcm_id = le32_to_cpu(spcm->pcm.pcm_id);
/*
* Update the card's components list with iec61937-pcm and a list of PCM
@@ -595,21 +596,21 @@ sof_ipc4_update_card_components_string(struct snd_sof_widget *swidget,
if (strstr(card->components, pt_marker))
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s,%d",
+ "%s,%u",
card->components,
- spcm->pcm.pcm_id);
+ pcm_id);
else
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s %s:%d",
+ "%s %s:%u",
card->components,
pt_marker,
- spcm->pcm.pcm_id);
+ pcm_id);
devm_kfree(card->dev, tmp);
} else {
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s:%d", pt_marker,
- spcm->pcm.pcm_id);
+ "%s:%u", pt_marker,
+ pcm_id);
}
if (!card->components)
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index 5b598d0940eb..b2071edeaea6 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -360,8 +360,8 @@ static int sof_pcm_prepare(struct snd_soc_component *component,
platform_params = &spcm->platform_params[substream->stream];
ret = sof_widget_list_setup(sdev, spcm, params, platform_params, dir);
if (ret < 0) {
- dev_err(sdev->dev, "failed widget list set up for pcm %d dir %d\n",
- spcm->pcm.pcm_id, dir);
+ dev_err(sdev->dev, "failed widget list set up for pcm %d dir %u\n",
+ le32_to_cpu(spcm->pcm.pcm_id), dir);
spcm->stream[dir].list = NULL;
snd_soc_dapm_dai_free_widgets(&list);
return ret;
@@ -651,8 +651,8 @@ static int sof_pcm_new(struct snd_soc_component *component,
return 0;
}
- dev_dbg(spcm->scomp->dev, "pcm%u (%s): Entry: pcm_construct\n",
- spcm->pcm.pcm_id, spcm->pcm.pcm_name);
+ dev_dbg(spcm->scomp->dev, "pcm%u (%s): Entry: pcm_new\n",
+ le32_to_cpu(spcm->pcm.pcm_id), spcm->pcm.pcm_name);
/* do we need to pre-allocate playback audio buffer pages */
if (!spcm->pcm.playback)
@@ -850,7 +850,7 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
pd->compress_ops = &sof_compressed_ops;
#endif
- pd->pcm_construct = sof_pcm_new;
+ pd->pcm_new = sof_pcm_new;
pd->ignore_machine = drv_name;
pd->be_pcm_base = SOF_BE_PCM_BASE;
pd->use_dai_pcm_id = true;
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 36082e764bf9..138e5fcc2dd0 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -411,11 +411,11 @@ struct snd_sof_dai_link {
struct snd_sof_tuple *tuples;
int num_tuples;
struct snd_soc_dai_link *link;
- struct snd_soc_tplg_hw_config *hw_configs;
int num_hw_configs;
int default_hw_cfg_id;
int type;
struct list_head list;
+ struct snd_soc_tplg_hw_config hw_configs[] __counted_by(num_hw_configs);
};
/* ASoC SOF DAPM widget */
@@ -641,17 +641,20 @@ void snd_sof_pcm_init_elapsed_work(struct work_struct *work);
*/
#define spcm_dbg(__spcm, __dir, __fmt, ...) \
dev_dbg((__spcm)->scomp->dev, "pcm%u (%s), dir %d: " __fmt, \
- (__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \
+ le32_to_cpu((__spcm)->pcm.pcm_id), \
+ (__spcm)->pcm.pcm_name, __dir, \
##__VA_ARGS__)
#define spcm_dbg_ratelimited(__spcm, __dir, __fmt, ...) \
dev_dbg_ratelimited((__spcm)->scomp->dev, "pcm%u (%s), dir %d: " __fmt, \
- (__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \
- ##__VA_ARGS__)
+ le32_to_cpu((__spcm)->pcm.pcm_id), \
+ (__spcm)->pcm.pcm_name, __dir, \
+ ##__VA_ARGS__)
#define spcm_err(__spcm, __dir, __fmt, ...) \
dev_err((__spcm)->scomp->dev, "%s: pcm%u (%s), dir %d: " __fmt, \
- __func__, (__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \
+ __func__, le32_to_cpu((__spcm)->pcm.pcm_id), \
+ (__spcm)->pcm.pcm_name, __dir, \
##__VA_ARGS__)
#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS)
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index 693d063830fa..38753b088fc1 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -17,6 +17,7 @@
#include <sound/sof/info.h>
#include <sound/sof/pm.h>
#include <sound/sof/trace.h>
+#include <sound/compress_params.h>
#include <uapi/sound/sof/fw.h>
#include <sound/sof/ext_manifest.h>
@@ -111,6 +112,7 @@ struct sof_compr_stream {
u32 sampling_rate;
u16 channels;
u16 sample_container_bytes;
+ struct snd_codec codec_params;
size_t posn_offset;
};
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index 35200d801fb7..63d582c65891 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -775,8 +775,8 @@ static int sof_parse_token_sets(struct snd_soc_component *scomp,
array);
break;
default:
- dev_err(scomp->dev, "error: unknown token type %d\n",
- array->type);
+ dev_err(scomp->dev, "error: unknown token type %u\n",
+ le32_to_cpu(array->type));
return -EINVAL;
}
@@ -880,7 +880,7 @@ skip:
ARRAY_SIZE(led_tokens), mc->priv.array,
le32_to_cpu(mc->priv.size));
if (ret != 0) {
- dev_err(scomp->dev, "error: parse led tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse led tokens failed %u\n",
le32_to_cpu(mc->priv.size));
goto err;
}
@@ -970,8 +970,8 @@ static int sof_control_load(struct snd_soc_component *scomp, int index,
struct snd_sof_control *scontrol;
int ret;
- dev_dbg(scomp->dev, "tplg: load control type %d name : %s\n",
- hdr->type, hdr->name);
+ dev_dbg(scomp->dev, "tplg: load control type %u name : %s\n",
+ le32_to_cpu(hdr->type), hdr->name);
scontrol = kzalloc_obj(*scontrol);
if (!scontrol)
@@ -1015,8 +1015,10 @@ static int sof_control_load(struct snd_soc_component *scomp, int index,
case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
case SND_SOC_TPLG_DAPM_CTL_PIN:
default:
- dev_warn(scomp->dev, "control type not supported %d:%d:%d\n",
- hdr->ops.get, hdr->ops.put, hdr->ops.info);
+ dev_warn(scomp->dev, "control type not supported %u:%u:%u\n",
+ le32_to_cpu(hdr->ops.get),
+ le32_to_cpu(hdr->ops.put),
+ le32_to_cpu(hdr->ops.info));
kfree(scontrol->name);
kfree(scontrol);
return 0;
@@ -1523,8 +1525,8 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
break;
case snd_soc_dapm_pga:
if (!le32_to_cpu(tw->num_kcontrols)) {
- dev_err(scomp->dev, "invalid kcontrol count %d for volume\n",
- tw->num_kcontrols);
+ dev_err(scomp->dev, "invalid kcontrol count %u for volume\n",
+ le32_to_cpu(tw->num_kcontrols));
ret = -EINVAL;
break;
}
@@ -1772,7 +1774,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index,
ARRAY_SIZE(stream_tokens), private->array,
le32_to_cpu(private->size));
if (ret) {
- dev_err(scomp->dev, "error: parse stream tokens failed %d\n",
+ dev_err(scomp->dev, "error: parse stream tokens failed %u\n",
le32_to_cpu(private->size));
return ret;
}
@@ -1906,18 +1908,12 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
return -EINVAL;
}
- slink = kzalloc_obj(*slink);
+ slink = kzalloc_flex(*slink, hw_configs, le32_to_cpu(cfg->num_hw_configs));
if (!slink)
return -ENOMEM;
slink->num_hw_configs = le32_to_cpu(cfg->num_hw_configs);
- slink->hw_configs = kmemdup_array(cfg->hw_config,
- slink->num_hw_configs, sizeof(*slink->hw_configs),
- GFP_KERNEL);
- if (!slink->hw_configs) {
- kfree(slink);
- return -ENOMEM;
- }
+ memcpy(slink->hw_configs, cfg->hw_config, le32_to_cpu(cfg->num_hw_configs) * sizeof(*slink->hw_configs));
slink->default_hw_cfg_id = le32_to_cpu(cfg->default_hw_config_id);
slink->link = link;
@@ -1930,7 +1926,6 @@ 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->hw_configs);
kfree(slink);
return ret;
}
@@ -2001,7 +1996,6 @@ 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->hw_configs);
kfree(slink);
return -ENOMEM;
}
@@ -2059,7 +2053,6 @@ out:
err:
kfree(slink->tuples);
- kfree(slink->hw_configs);
kfree(slink);
return ret;
@@ -2076,7 +2069,6 @@ static int sof_link_unload(struct snd_soc_component *scomp, struct snd_soc_dobj
kfree(slink->tuples);
list_del(&slink->list);
- kfree(slink->hw_configs);
kfree(slink);
dobj->private = NULL;
diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c
index 4ad8b1fc713a..b31b120a85de 100644
--- a/sound/soc/spear/spdif_in.c
+++ b/sound/soc/spear/spdif_in.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ALSA SoC SPDIF In Audio Layer for spear processors
*
* Copyright (C) 2012 ST Microelectronics
* Vipin Kumar <vipin.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
*/
#include <linux/clk.h>
diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c
index 469373d1bb41..c06f09c646a8 100644
--- a/sound/soc/spear/spdif_out.c
+++ b/sound/soc/spear/spdif_out.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ALSA SoC SPDIF Out Audio Layer for spear processors
*
* Copyright (C) 2012 ST Microelectronics
* Vipin Kumar <vipin.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
*/
#include <linux/clk.h>
diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c
index e8476da157cd..f222956e857c 100644
--- a/sound/soc/spear/spear_pcm.c
+++ b/sound/soc/spear/spear_pcm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ALSA PCM interface for ST SPEAr Processors
*
@@ -5,10 +6,6 @@
*
* Copyright (C) 2012 ST Microelectronics
* Rajeev Kumar<rajeevkumar.linux@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
*/
#include <linux/module.h>
diff --git a/sound/soc/sprd/sprd-pcm-dma.c b/sound/soc/sprd/sprd-pcm-dma.c
index d6b96cc2f708..cbf5bf82d96e 100644
--- a/sound/soc/sprd/sprd-pcm-dma.c
+++ b/sound/soc/sprd/sprd-pcm-dma.c
@@ -453,7 +453,7 @@ static const struct snd_soc_component_driver sprd_soc_component = {
.hw_free = sprd_pcm_hw_free,
.trigger = sprd_pcm_trigger,
.pointer = sprd_pcm_pointer,
- .pcm_construct = sprd_pcm_new,
+ .pcm_new = sprd_pcm_new,
.compress_ops = &sprd_platform_compress_ops,
};
diff --git a/sound/soc/starfive/Makefile b/sound/soc/starfive/Makefile
index 9e958f70ef51..cfe03c83d5f7 100644
--- a/sound/soc/starfive/Makefile
+++ b/sound/soc/starfive/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
# StarFive Platform Support
obj-$(CONFIG_SND_SOC_JH7110_PWMDAC) += jh7110_pwmdac.o
obj-$(CONFIG_SND_SOC_JH7110_TDM) += jh7110_tdm.o
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c
index 6d1ce030963c..45d35b887e4e 100644
--- a/sound/soc/sti/uniperif_player.c
+++ b/sound/soc/sti/uniperif_player.c
@@ -1028,8 +1028,13 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev,
return PTR_ERR(regmap);
}
- player->clk_sel = regmap_field_alloc(regmap, regfield[0]);
- player->valid_sel = regmap_field_alloc(regmap, regfield[1]);
+ player->clk_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[0]);
+ if (IS_ERR(player->clk_sel))
+ return PTR_ERR(player->clk_sel);
+
+ player->valid_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[1]);
+ if (IS_ERR(player->valid_sel))
+ return PTR_ERR(player->valid_sel);
return 0;
}
diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index 1797a91fea7a..0f6d32814c22 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -315,7 +315,7 @@ static const struct snd_soc_component_driver stm32_adfsdm_soc_platform = {
.hw_params = stm32_adfsdm_pcm_hw_params,
.trigger = stm32_adfsdm_trigger,
.pointer = stm32_adfsdm_pcm_pointer,
- .pcm_construct = stm32_adfsdm_pcm_new,
+ .pcm_new = stm32_adfsdm_pcm_new,
};
static const struct of_device_id stm32_adfsdm_of_match[] = {
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index 65de03ca3ad2..c2ec19437cd7 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -712,15 +712,10 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, host);
if (quirks->has_reset) {
- host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
- NULL);
- if (PTR_ERR(host->rst) == -EPROBE_DEFER) {
- ret = -EPROBE_DEFER;
- dev_err(&pdev->dev, "Failed to get reset: %d\n", ret);
- return ret;
- }
- if (!IS_ERR(host->rst))
- reset_control_deassert(host->rst);
+ host->rst = devm_reset_control_get_exclusive_deasserted(&pdev->dev, NULL);
+ if (IS_ERR(host->rst))
+ return dev_err_probe(&pdev->dev, PTR_ERR(host->rst),
+ "Failed to get reset\n");
}
ret = devm_snd_soc_register_component(&pdev->dev,
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 9dbd589879fb..fdc954028d62 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -229,6 +229,16 @@ config SND_SOC_TEGRA_WM8903
boards using the WM8093 codec. Currently, the supported boards are
Harmony, Ventana, Seaboard, Kaen, and Aebl.
+config SND_SOC_TEGRA_WM8962
+ tristate "SoC Audio support for Tegra boards using a WM8962 codec"
+ depends on I2C && INPUT && GPIOLIB
+ select SND_SOC_TEGRA_MACHINE_DRV
+ select SND_SOC_WM8962
+ help
+ Say Y or M here if you want to add support for SoC audio on Tegra
+ boards using the WM8962 codec. Currently, the supported boards are
+ Microsoft Surface RT.
+
config SND_SOC_TEGRA_WM9712
tristate "SoC Audio support for Tegra boards using a WM9712 codec"
depends on GPIOLIB
@@ -294,6 +304,15 @@ config SND_SOC_TEGRA_SGTL5000
boards using the SGTL5000 codec, such as Apalis T30, Apalis TK1 or
Colibri T30.
+config SND_SOC_TEGRA_CPCAP
+ tristate "SoC Audio support for Tegra boards using a CPCAP codec"
+ depends on I2C && GPIOLIB && MFD_CPCAP
+ select SND_SOC_TEGRA_MACHINE_DRV
+ select SND_SOC_CPCAP
+ help
+ Say Y or M here if you want to add support for SoC audio on Tegra
+ boards using the CPCAP codec, such as Motorola Atrix 4G or Droid X2.
+
endif
endmenu
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index defea7f53f11..3f396c87802e 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -43,9 +43,11 @@ obj-$(CONFIG_SND_SOC_TEGRA210_OPE) += snd-soc-tegra210-ope.o
# Tegra machine Support
snd-soc-tegra-wm8903-y := tegra_wm8903.o
+snd-soc-tegra-wm8962-y := tegra_wm8962.o
snd-soc-tegra-machine-y := tegra_asoc_machine.o
snd-soc-tegra-audio-graph-card-y := tegra_audio_graph_card.o
obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
+obj-$(CONFIG_SND_SOC_TEGRA_WM8962) += snd-soc-tegra-wm8962.o
obj-$(CONFIG_SND_SOC_TEGRA_MACHINE_DRV) += snd-soc-tegra-machine.o
obj-$(CONFIG_SND_SOC_TEGRA_AUDIO_GRAPH_CARD) += snd-soc-tegra-audio-graph-card.o
diff --git a/sound/soc/tegra/tegra186_asrc.c b/sound/soc/tegra/tegra186_asrc.c
index d2a5ec7c54cc..7135aa23a7fc 100644
--- a/sound/soc/tegra/tegra186_asrc.c
+++ b/sound/soc/tegra/tegra186_asrc.c
@@ -989,10 +989,9 @@ static int tegra186_asrc_platform_probe(struct platform_device *pdev)
asrc->regmap = devm_regmap_init_mmio(dev, regs,
&tegra186_asrc_regmap_config);
- if (IS_ERR(asrc->regmap)) {
- dev_err(dev, "regmap init failed\n");
- return PTR_ERR(asrc->regmap);
- }
+ if (IS_ERR(asrc->regmap))
+ return dev_err_probe(dev, PTR_ERR(asrc->regmap),
+ "regmap init failed\n");
asrc->soc_data = of_device_get_match_data(&pdev->dev);
@@ -1016,10 +1015,9 @@ static int tegra186_asrc_platform_probe(struct platform_device *pdev)
err = devm_snd_soc_register_component(dev, &tegra186_asrc_cmpnt,
tegra186_asrc_dais,
ARRAY_SIZE(tegra186_asrc_dais));
- if (err) {
- dev_err(dev, "can't register ASRC component, err: %d\n", err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "can't register ASRC component\n");
pm_runtime_enable(dev);
diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c
index 8816e4967331..7cf7d6dbfc35 100644
--- a/sound/soc/tegra/tegra186_dspk.c
+++ b/sound/soc/tegra/tegra186_dspk.c
@@ -496,31 +496,27 @@ static int tegra186_dspk_platform_probe(struct platform_device *pdev)
dev_set_drvdata(dev, dspk);
dspk->clk_dspk = devm_clk_get(dev, "dspk");
- if (IS_ERR(dspk->clk_dspk)) {
- dev_err(dev, "can't retrieve DSPK clock\n");
- return PTR_ERR(dspk->clk_dspk);
- }
+ if (IS_ERR(dspk->clk_dspk))
+ return dev_err_probe(dev, PTR_ERR(dspk->clk_dspk),
+ "can't retrieve DSPK clock\n");
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
return PTR_ERR(regs);
dspk->regmap = devm_regmap_init_mmio(dev, regs, &tegra186_dspk_regmap);
- if (IS_ERR(dspk->regmap)) {
- dev_err(dev, "regmap init failed\n");
- return PTR_ERR(dspk->regmap);
- }
+ if (IS_ERR(dspk->regmap))
+ return dev_err_probe(dev, PTR_ERR(dspk->regmap),
+ "regmap init failed\n");
regcache_cache_only(dspk->regmap, true);
err = devm_snd_soc_register_component(dev, &tegra186_dspk_cmpnt,
tegra186_dspk_dais,
ARRAY_SIZE(tegra186_dspk_dais));
- if (err) {
- dev_err(dev, "can't register DSPK component, err: %d\n",
- err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "can't register DSPK component\n");
pm_runtime_enable(dev);
diff --git a/sound/soc/tegra/tegra20_spdif.h b/sound/soc/tegra/tegra20_spdif.h
index ff4b79e2052f..26ab8d5c7f99 100644
--- a/sound/soc/tegra/tegra20_spdif.h
+++ b/sound/soc/tegra/tegra20_spdif.h
@@ -171,7 +171,7 @@
/*
* RX channel block data receive status:
- * 0=entire block not recieved yet.
+ * 0=entire block not received yet.
* 1=received entire block of channel status,
*/
#define TEGRA20_SPDIF_STATUS_IS_C (1 << 21)
diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c
index 0976779d29f2..a1c2757a3932 100644
--- a/sound/soc/tegra/tegra210_admaif.c
+++ b/sound/soc/tegra/tegra210_admaif.c
@@ -408,6 +408,7 @@ static int tegra_admaif_start(struct snd_soc_dai *dai, int direction)
reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
break;
default:
+ dev_err(dai->dev, "invalid stream direction: %d\n", direction);
return -EINVAL;
}
@@ -441,6 +442,7 @@ static int tegra_admaif_stop(struct snd_soc_dai *dai, int direction)
reset_reg = CH_RX_REG(TEGRA_ADMAIF_RX_SOFT_RESET, dai->id);
break;
default:
+ dev_err(dai->dev, "invalid stream direction: %d\n", direction);
return -EINVAL;
}
@@ -489,6 +491,7 @@ static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_SUSPEND:
return tegra_admaif_stop(dai, substream->stream);
default:
+ dev_err(dai->dev, "invalid trigger command: %d\n", cmd);
return -EINVAL;
}
}
@@ -839,7 +842,7 @@ static struct snd_kcontrol_new tegra264_admaif_controls[] = {
static const struct snd_soc_component_driver tegra210_admaif_cmpnt = {
.controls = tegra210_admaif_controls,
.num_controls = ARRAY_SIZE(tegra210_admaif_controls),
- .pcm_construct = tegra_pcm_construct,
+ .pcm_new = tegra_pcm_new,
.open = tegra_pcm_open,
.close = tegra_pcm_close,
.hw_params = tegra_pcm_hw_params,
@@ -849,7 +852,7 @@ static const struct snd_soc_component_driver tegra210_admaif_cmpnt = {
static const struct snd_soc_component_driver tegra186_admaif_cmpnt = {
.controls = tegra186_admaif_controls,
.num_controls = ARRAY_SIZE(tegra186_admaif_controls),
- .pcm_construct = tegra_pcm_construct,
+ .pcm_new = tegra_pcm_new,
.open = tegra_pcm_open,
.close = tegra_pcm_close,
.hw_params = tegra_pcm_hw_params,
@@ -859,7 +862,7 @@ static const struct snd_soc_component_driver tegra186_admaif_cmpnt = {
static const struct snd_soc_component_driver tegra264_admaif_cmpnt = {
.controls = tegra264_admaif_controls,
.num_controls = ARRAY_SIZE(tegra264_admaif_controls),
- .pcm_construct = tegra_pcm_construct,
+ .pcm_new = tegra_pcm_new,
.open = tegra_pcm_open,
.close = tegra_pcm_close,
.hw_params = tegra_pcm_hw_params,
@@ -958,18 +961,15 @@ static int tegra_admaif_probe(struct platform_device *pdev)
admaif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
admaif->soc_data->regmap_conf);
- if (IS_ERR(admaif->regmap)) {
- dev_err(&pdev->dev, "regmap init failed\n");
- return PTR_ERR(admaif->regmap);
- }
+ if (IS_ERR(admaif->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(admaif->regmap),
+ "regmap init failed\n");
regcache_cache_only(admaif->regmap, true);
err = tegra_isomgr_adma_register(&pdev->dev);
- if (err) {
- dev_err(&pdev->dev, "Failed to add interconnect path\n");
+ if (err)
return err;
- }
regmap_update_bits(admaif->regmap, admaif->soc_data->global_base +
TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1);
@@ -1009,11 +1009,9 @@ static int tegra_admaif_probe(struct platform_device *pdev)
admaif->soc_data->cmpnt,
admaif->soc_data->dais,
admaif->soc_data->num_ch);
- if (err) {
- dev_err(&pdev->dev,
- "can't register ADMAIF component, err: %d\n", err);
- return err;
- }
+ if (err)
+ return dev_err_probe(&pdev->dev, err,
+ "can't register ADMAIF component\n");
pm_runtime_enable(&pdev->dev);
diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c
index 95875c75ddf8..d2f742ffc59d 100644
--- a/sound/soc/tegra/tegra210_adx.c
+++ b/sound/soc/tegra/tegra210_adx.c
@@ -134,8 +134,11 @@ static int tegra210_adx_set_audio_cif(struct snd_soc_dai *dai,
memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
- if (channels < 1 || channels > adx->soc_data->max_ch)
+ if (channels < 1 || channels > adx->soc_data->max_ch) {
+ dev_err(dai->dev, "invalid channels: %u (max %u)\n",
+ channels, adx->soc_data->max_ch);
return -EINVAL;
+ }
switch (format) {
case SNDRV_PCM_FORMAT_S8:
@@ -149,6 +152,7 @@ static int tegra210_adx_set_audio_cif(struct snd_soc_dai *dai,
audio_bits = TEGRA_ACIF_BITS_32;
break;
default:
+ dev_err(dai->dev, "unsupported format: %d\n", format);
return -EINVAL;
}
@@ -693,10 +697,9 @@ static int tegra210_adx_platform_probe(struct platform_device *pdev)
adx->regmap = devm_regmap_init_mmio(dev, regs,
soc_data->regmap_conf);
- if (IS_ERR(adx->regmap)) {
- dev_err(dev, "regmap init failed\n");
- return PTR_ERR(adx->regmap);
- }
+ if (IS_ERR(adx->regmap))
+ return dev_err_probe(dev, PTR_ERR(adx->regmap),
+ "regmap init failed\n");
regcache_cache_only(adx->regmap, true);
@@ -717,10 +720,9 @@ static int tegra210_adx_platform_probe(struct platform_device *pdev)
err = devm_snd_soc_register_component(dev, &tegra210_adx_cmpnt,
tegra210_adx_dais,
ARRAY_SIZE(tegra210_adx_dais));
- if (err) {
- dev_err(dev, "can't register ADX component, err: %d\n", err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "can't register ADX component\n");
pm_runtime_enable(dev);
diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c
index 43a45f785d5b..ece33b7ff190 100644
--- a/sound/soc/tegra/tegra210_ahub.c
+++ b/sound/soc/tegra/tegra210_ahub.c
@@ -20,6 +20,7 @@ static int tegra_ahub_get_value_enum(struct snd_kcontrol *kctl,
struct snd_soc_component *cmpnt = snd_soc_dapm_kcontrol_to_component(kctl);
struct tegra_ahub *ahub = snd_soc_component_get_drvdata(cmpnt);
struct soc_enum *e = (struct soc_enum *)kctl->private_value;
+ int val_bytes = snd_soc_component_regmap_val_bytes(cmpnt);
unsigned int reg, i, bit_pos = 0;
/*
@@ -35,7 +36,7 @@ static int tegra_ahub_get_value_enum(struct snd_kcontrol *kctl,
if (reg_val) {
bit_pos = ffs(reg_val) +
- (8 * cmpnt->val_bytes * i);
+ (8 * val_bytes * i);
break;
}
}
@@ -59,6 +60,7 @@ static int tegra_ahub_put_value_enum(struct snd_kcontrol *kctl,
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kctl);
struct soc_enum *e = (struct soc_enum *)kctl->private_value;
struct snd_soc_dapm_update update[TEGRA_XBAR_UPDATE_MAX_REG] = { };
+ int val_bytes = snd_soc_component_regmap_val_bytes(cmpnt);
unsigned int *item = uctl->value.enumerated.item;
unsigned int value = e->values[item[0]];
unsigned int i, bit_pos, reg_idx = 0, reg_val = 0;
@@ -69,8 +71,8 @@ static int tegra_ahub_put_value_enum(struct snd_kcontrol *kctl,
if (value) {
/* Get the register index and value to set */
- reg_idx = (value - 1) / (8 * cmpnt->val_bytes);
- bit_pos = (value - 1) % (8 * cmpnt->val_bytes);
+ reg_idx = (value - 1) / (8 * val_bytes);
+ bit_pos = (value - 1) % (8 * val_bytes);
reg_val = BIT(bit_pos);
}
@@ -2265,10 +2267,9 @@ static int tegra_ahub_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ahub);
ahub->clk = devm_clk_get(&pdev->dev, "ahub");
- if (IS_ERR(ahub->clk)) {
- dev_err(&pdev->dev, "can't retrieve AHUB clock\n");
- return PTR_ERR(ahub->clk);
- }
+ if (IS_ERR(ahub->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(ahub->clk),
+ "can't retrieve AHUB clock\n");
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
@@ -2276,10 +2277,9 @@ static int tegra_ahub_probe(struct platform_device *pdev)
ahub->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
ahub->soc_data->regmap_config);
- if (IS_ERR(ahub->regmap)) {
- dev_err(&pdev->dev, "regmap init failed\n");
- return PTR_ERR(ahub->regmap);
- }
+ if (IS_ERR(ahub->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(ahub->regmap),
+ "regmap init failed\n");
regcache_cache_only(ahub->regmap, true);
@@ -2287,18 +2287,17 @@ static int tegra_ahub_probe(struct platform_device *pdev)
ahub->soc_data->cmpnt_drv,
ahub->soc_data->dai_drv,
ahub->soc_data->num_dais);
- if (err) {
- dev_err(&pdev->dev, "can't register AHUB component, err: %d\n",
- err);
- return err;
- }
+ if (err)
+ return dev_err_probe(&pdev->dev, err,
+ "can't register AHUB component\n");
pm_runtime_enable(&pdev->dev);
err = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
if (err) {
pm_runtime_disable(&pdev->dev);
- return err;
+ return dev_err_probe(&pdev->dev, err,
+ "failed to populate child nodes\n");
}
return 0;
diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c
index bfda82505298..d635046bbe81 100644
--- a/sound/soc/tegra/tegra210_amx.c
+++ b/sound/soc/tegra/tegra210_amx.c
@@ -163,6 +163,8 @@ static int tegra210_amx_set_audio_cif(struct snd_soc_dai *dai,
audio_bits = TEGRA_ACIF_BITS_32;
break;
default:
+ dev_err(dai->dev, "unsupported format: %d\n",
+ params_format(params));
return -EINVAL;
}
@@ -743,10 +745,9 @@ static int tegra210_amx_platform_probe(struct platform_device *pdev)
amx->regmap = devm_regmap_init_mmio(dev, regs,
amx->soc_data->regmap_conf);
- if (IS_ERR(amx->regmap)) {
- dev_err(dev, "regmap init failed\n");
- return PTR_ERR(amx->regmap);
- }
+ if (IS_ERR(amx->regmap))
+ return dev_err_probe(dev, PTR_ERR(amx->regmap),
+ "regmap init failed\n");
regcache_cache_only(amx->regmap, true);
@@ -767,10 +768,9 @@ static int tegra210_amx_platform_probe(struct platform_device *pdev)
err = devm_snd_soc_register_component(dev, &tegra210_amx_cmpnt,
tegra210_amx_dais,
ARRAY_SIZE(tegra210_amx_dais));
- if (err) {
- dev_err(dev, "can't register AMX component, err: %d\n", err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "can't register AMX component\n");
pm_runtime_enable(dev);
diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c
index 93def7ac4fde..3e42e2c75eb9 100644
--- a/sound/soc/tegra/tegra210_dmic.c
+++ b/sound/soc/tegra/tegra210_dmic.c
@@ -507,10 +507,9 @@ static int tegra210_dmic_probe(struct platform_device *pdev)
dev_set_drvdata(dev, dmic);
dmic->clk_dmic = devm_clk_get(dev, "dmic");
- if (IS_ERR(dmic->clk_dmic)) {
- dev_err(dev, "can't retrieve DMIC clock\n");
- return PTR_ERR(dmic->clk_dmic);
- }
+ if (IS_ERR(dmic->clk_dmic))
+ return dev_err_probe(dev, PTR_ERR(dmic->clk_dmic),
+ "can't retrieve DMIC clock\n");
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
@@ -518,20 +517,18 @@ static int tegra210_dmic_probe(struct platform_device *pdev)
dmic->regmap = devm_regmap_init_mmio(dev, regs,
&tegra210_dmic_regmap_config);
- if (IS_ERR(dmic->regmap)) {
- dev_err(dev, "regmap init failed\n");
- return PTR_ERR(dmic->regmap);
- }
+ if (IS_ERR(dmic->regmap))
+ return dev_err_probe(dev, PTR_ERR(dmic->regmap),
+ "regmap init failed\n");
regcache_cache_only(dmic->regmap, true);
err = devm_snd_soc_register_component(dev, &tegra210_dmic_compnt,
tegra210_dmic_dais,
ARRAY_SIZE(tegra210_dmic_dais));
- if (err) {
- dev_err(dev, "can't register DMIC component, err: %d\n", err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "can't register DMIC component\n");
pm_runtime_enable(dev);
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
index d8e02f0a3025..0259b137547c 100644
--- a/sound/soc/tegra/tegra210_i2s.c
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -161,6 +161,7 @@ static int tegra210_i2s_init(struct snd_soc_dapm_widget *w,
stream = SNDRV_PCM_STREAM_CAPTURE;
status_reg = TEGRA210_I2S_TX_STATUS + i2s->soc_data->tx_offset;
} else {
+ dev_err(dev, "invalid I2S direction register 0x%x\n", w->reg);
return -EINVAL;
}
@@ -235,6 +236,7 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
val = I2S_CTRL_MASTER_EN;
break;
default:
+ dev_err(dai->dev, "invalid clock provider format 0x%x\n", fmt);
return -EINVAL;
}
@@ -270,6 +272,7 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
tegra210_i2s_set_data_offset(i2s, 0);
break;
default:
+ dev_err(dai->dev, "invalid I2S frame format 0x%x\n", fmt);
return -EINVAL;
}
@@ -290,6 +293,7 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
val ^= I2S_CTRL_LRCK_POL_MASK;
break;
default:
+ dev_err(dai->dev, "invalid I2S clock inversion 0x%x\n", fmt);
return -EINVAL;
}
@@ -1070,10 +1074,9 @@ static int tegra210_i2s_probe(struct platform_device *pdev)
dev_set_drvdata(dev, i2s);
i2s->clk_i2s = devm_clk_get(dev, "i2s");
- if (IS_ERR(i2s->clk_i2s)) {
- dev_err(dev, "can't retrieve I2S bit clock\n");
- return PTR_ERR(i2s->clk_i2s);
- }
+ if (IS_ERR(i2s->clk_i2s))
+ return dev_err_probe(dev, PTR_ERR(i2s->clk_i2s),
+ "can't retrieve I2S bit clock\n");
/*
* Not an error, as this clock is needed only when some other I/O
@@ -1090,10 +1093,9 @@ static int tegra210_i2s_probe(struct platform_device *pdev)
i2s->regmap = devm_regmap_init_mmio(dev, regs,
i2s->soc_data->regmap_conf);
- if (IS_ERR(i2s->regmap)) {
- dev_err(dev, "regmap init failed\n");
- return PTR_ERR(i2s->regmap);
- }
+ if (IS_ERR(i2s->regmap))
+ return dev_err_probe(dev, PTR_ERR(i2s->regmap),
+ "regmap init failed\n");
tegra210_parse_client_convert(dev);
@@ -1108,10 +1110,9 @@ static int tegra210_i2s_probe(struct platform_device *pdev)
err = devm_snd_soc_register_component(dev, i2s->soc_data->i2s_cmpnt,
tegra210_i2s_dais,
ARRAY_SIZE(tegra210_i2s_dais));
- if (err) {
- dev_err(dev, "can't register I2S component, err: %d\n", err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "can't register I2S component\n");
pm_runtime_enable(dev);
diff --git a/sound/soc/tegra/tegra210_mbdrc.c b/sound/soc/tegra/tegra210_mbdrc.c
index 6a268dbb7197..f5d4a93dd6f1 100644
--- a/sound/soc/tegra/tegra210_mbdrc.c
+++ b/sound/soc/tegra/tegra210_mbdrc.c
@@ -307,13 +307,14 @@ static int tegra210_mbdrc_band_params_get(struct snd_kcontrol *kcontrol,
struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ int val_bytes = snd_soc_component_regmap_val_bytes(cmpnt);
u32 *data = (u32 *)ucontrol->value.bytes.data;
u32 regs = params->soc.base;
u32 mask = params->soc.mask;
u32 shift = params->shift;
unsigned int i;
- for (i = 0; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) {
+ for (i = 0; i < params->soc.num_regs; i++, regs += val_bytes) {
regmap_read(ope->mbdrc_regmap, regs, &data[i]);
data[i] = ((data[i] & mask) >> shift);
@@ -328,6 +329,7 @@ static int tegra210_mbdrc_band_params_put(struct snd_kcontrol *kcontrol,
struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ int val_bytes = snd_soc_component_regmap_val_bytes(cmpnt);
u32 *data = (u32 *)ucontrol->value.bytes.data;
u32 regs = params->soc.base;
u32 mask = params->soc.mask;
@@ -335,7 +337,7 @@ static int tegra210_mbdrc_band_params_put(struct snd_kcontrol *kcontrol,
bool change = false;
unsigned int i;
- for (i = 0; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) {
+ for (i = 0; i < params->soc.num_regs; i++, regs += val_bytes) {
bool update = false;
regmap_update_bits_check(ope->mbdrc_regmap, regs, mask,
@@ -353,13 +355,14 @@ static int tegra210_mbdrc_threshold_get(struct snd_kcontrol *kcontrol,
struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ int val_bytes = snd_soc_component_regmap_val_bytes(cmpnt);
u32 *data = (u32 *)ucontrol->value.bytes.data;
u32 regs = params->soc.base;
u32 num_regs = params->soc.num_regs;
u32 val;
unsigned int i;
- for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) {
+ for (i = 0; i < num_regs; i += 4, regs += val_bytes) {
regmap_read(ope->mbdrc_regmap, regs, &val);
data[i] = (val & TEGRA210_MBDRC_THRESH_1ST_MASK) >>
@@ -381,13 +384,14 @@ static int tegra210_mbdrc_threshold_put(struct snd_kcontrol *kcontrol,
struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ int val_bytes = snd_soc_component_regmap_val_bytes(cmpnt);
u32 *data = (u32 *)ucontrol->value.bytes.data;
u32 regs = params->soc.base;
u32 num_regs = params->soc.num_regs;
bool change = false;
unsigned int i;
- for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) {
+ for (i = 0; i < num_regs; i += 4, regs += val_bytes) {
bool update = false;
data[i] = (((data[i] >> TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
@@ -413,9 +417,10 @@ static int tegra210_mbdrc_biquad_coeffs_get(struct snd_kcontrol *kcontrol,
{
struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
+ int val_bytes = snd_soc_component_regmap_val_bytes(cmpnt);
u32 *data = (u32 *)ucontrol->value.bytes.data;
- memset(data, 0, params->soc.num_regs * cmpnt->val_bytes);
+ memset(data, 0, params->soc.num_regs * val_bytes);
return 0;
}
@@ -426,8 +431,9 @@ static int tegra210_mbdrc_biquad_coeffs_put(struct snd_kcontrol *kcontrol,
struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ int val_bytes = snd_soc_component_regmap_val_bytes(cmpnt);
u32 reg_ctrl = params->soc.base;
- u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+ u32 reg_data = reg_ctrl + val_bytes;
u32 *data = (u32 *)ucontrol->value.bytes.data;
tegra210_mbdrc_write_ram(ope->mbdrc_regmap, reg_ctrl, reg_data,
@@ -988,14 +994,14 @@ int tegra210_mbdrc_regmap_init(struct platform_device *pdev)
child = of_get_child_by_name(dev->of_node, "dynamic-range-compressor");
if (!child)
- return -ENODEV;
+ return dev_err_probe(dev, -ENODEV,
+ "missing 'dynamic-range-compressor' DT child node\n");
err = of_address_to_resource(child, 0, &mem);
of_node_put(child);
- if (err < 0) {
- dev_err(dev, "fail to get MBDRC resource\n");
- return err;
- }
+ if (err < 0)
+ return dev_err_probe(dev, err,
+ "failed to get MBDRC resource\n");
mem.flags = IORESOURCE_MEM;
regs = devm_ioremap_resource(dev, &mem);
@@ -1004,10 +1010,9 @@ int tegra210_mbdrc_regmap_init(struct platform_device *pdev)
ope->mbdrc_regmap = devm_regmap_init_mmio(dev, regs,
&tegra210_mbdrc_regmap_cfg);
- if (IS_ERR(ope->mbdrc_regmap)) {
- dev_err(dev, "regmap init failed\n");
- return PTR_ERR(ope->mbdrc_regmap);
- }
+ if (IS_ERR(ope->mbdrc_regmap))
+ return dev_err_probe(dev, PTR_ERR(ope->mbdrc_regmap),
+ "MBDRC regmap init failed\n");
regcache_cache_only(ope->mbdrc_regmap, true);
diff --git a/sound/soc/tegra/tegra210_mixer.c b/sound/soc/tegra/tegra210_mixer.c
index 6d3a2b76fd61..ce44117a0b9c 100644
--- a/sound/soc/tegra/tegra210_mixer.c
+++ b/sound/soc/tegra/tegra210_mixer.c
@@ -641,20 +641,18 @@ static int tegra210_mixer_platform_probe(struct platform_device *pdev)
mixer->regmap = devm_regmap_init_mmio(dev, regs,
&tegra210_mixer_regmap_config);
- if (IS_ERR(mixer->regmap)) {
- dev_err(dev, "regmap init failed\n");
- return PTR_ERR(mixer->regmap);
- }
+ if (IS_ERR(mixer->regmap))
+ return dev_err_probe(dev, PTR_ERR(mixer->regmap),
+ "regmap init failed\n");
regcache_cache_only(mixer->regmap, true);
err = devm_snd_soc_register_component(dev, &tegra210_mixer_cmpnt,
tegra210_mixer_dais,
ARRAY_SIZE(tegra210_mixer_dais));
- if (err) {
- dev_err(dev, "can't register MIXER component, err: %d\n", err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "can't register MIXER component\n");
pm_runtime_enable(dev);
diff --git a/sound/soc/tegra/tegra210_mvc.c b/sound/soc/tegra/tegra210_mvc.c
index 6cdc5e1f5507..2c299704ef4f 100644
--- a/sound/soc/tegra/tegra210_mvc.c
+++ b/sound/soc/tegra/tegra210_mvc.c
@@ -731,20 +731,18 @@ static int tegra210_mvc_platform_probe(struct platform_device *pdev)
mvc->regmap = devm_regmap_init_mmio(dev, regs,
&tegra210_mvc_regmap_config);
- if (IS_ERR(mvc->regmap)) {
- dev_err(dev, "regmap init failed\n");
- return PTR_ERR(mvc->regmap);
- }
+ if (IS_ERR(mvc->regmap))
+ return dev_err_probe(dev, PTR_ERR(mvc->regmap),
+ "regmap init failed\n");
regcache_cache_only(mvc->regmap, true);
err = devm_snd_soc_register_component(dev, &tegra210_mvc_cmpnt,
tegra210_mvc_dais,
ARRAY_SIZE(tegra210_mvc_dais));
- if (err) {
- dev_err(dev, "can't register MVC component, err: %d\n", err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "can't register MVC component\n");
pm_runtime_enable(dev);
diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c
index a440888dcdbd..ad4c400281e8 100644
--- a/sound/soc/tegra/tegra210_ope.c
+++ b/sound/soc/tegra/tegra210_ope.c
@@ -318,34 +318,28 @@ static int tegra210_ope_probe(struct platform_device *pdev)
ope->regmap = devm_regmap_init_mmio(dev, regs,
&tegra210_ope_regmap_config);
- if (IS_ERR(ope->regmap)) {
- dev_err(dev, "regmap init failed\n");
- return PTR_ERR(ope->regmap);
- }
+ if (IS_ERR(ope->regmap))
+ return dev_err_probe(dev, PTR_ERR(ope->regmap),
+ "regmap init failed\n");
regcache_cache_only(ope->regmap, true);
dev_set_drvdata(dev, ope);
err = tegra210_peq_regmap_init(pdev);
- if (err < 0) {
- dev_err(dev, "PEQ init failed\n");
+ if (err < 0)
return err;
- }
err = tegra210_mbdrc_regmap_init(pdev);
- if (err < 0) {
- dev_err(dev, "MBDRC init failed\n");
+ if (err < 0)
return err;
- }
err = devm_snd_soc_register_component(dev, &tegra210_ope_cmpnt,
tegra210_ope_dais,
ARRAY_SIZE(tegra210_ope_dais));
- if (err) {
- dev_err(dev, "can't register OPE component, err: %d\n", err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "can't register OPE component\n");
pm_runtime_enable(dev);
diff --git a/sound/soc/tegra/tegra210_peq.c b/sound/soc/tegra/tegra210_peq.c
index 2f72e9d541dc..9d5702a7ae3b 100644
--- a/sound/soc/tegra/tegra210_peq.c
+++ b/sound/soc/tegra/tegra210_peq.c
@@ -148,8 +148,9 @@ static int tegra210_peq_ram_get(struct snd_kcontrol *kcontrol,
struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ int val_bytes = snd_soc_component_regmap_val_bytes(cmpnt);
u32 i, reg_ctrl = params->soc.base;
- u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+ u32 reg_data = reg_ctrl + val_bytes;
s32 *data = (s32 *)biquad_coeff_buffer;
pm_runtime_get_sync(cmpnt->dev);
@@ -171,8 +172,9 @@ static int tegra210_peq_ram_put(struct snd_kcontrol *kcontrol,
struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ int val_bytes = snd_soc_component_regmap_val_bytes(cmpnt);
u32 i, reg_ctrl = params->soc.base;
- u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+ u32 reg_data = reg_ctrl + val_bytes;
s32 *data = (s32 *)biquad_coeff_buffer;
for (i = 0; i < params->soc.num_regs; i++)
@@ -408,14 +410,14 @@ int tegra210_peq_regmap_init(struct platform_device *pdev)
child = of_get_child_by_name(dev->of_node, "equalizer");
if (!child)
- return -ENODEV;
+ return dev_err_probe(dev, -ENODEV,
+ "missing 'equalizer' DT child node\n");
err = of_address_to_resource(child, 0, &mem);
of_node_put(child);
- if (err < 0) {
- dev_err(dev, "fail to get PEQ resource\n");
- return err;
- }
+ if (err < 0)
+ return dev_err_probe(dev, err,
+ "failed to get PEQ resource\n");
mem.flags = IORESOURCE_MEM;
regs = devm_ioremap_resource(dev, &mem);
@@ -423,10 +425,9 @@ int tegra210_peq_regmap_init(struct platform_device *pdev)
return PTR_ERR(regs);
ope->peq_regmap = devm_regmap_init_mmio(dev, regs,
&tegra210_peq_regmap_config);
- if (IS_ERR(ope->peq_regmap)) {
- dev_err(dev, "regmap init failed\n");
- return PTR_ERR(ope->peq_regmap);
- }
+ if (IS_ERR(ope->peq_regmap))
+ return dev_err_probe(dev, PTR_ERR(ope->peq_regmap),
+ "PEQ regmap init failed\n");
regcache_cache_only(ope->peq_regmap, true);
diff --git a/sound/soc/tegra/tegra210_sfc.c b/sound/soc/tegra/tegra210_sfc.c
index b298bf0421b1..a4b96445f1da 100644
--- a/sound/soc/tegra/tegra210_sfc.c
+++ b/sound/soc/tegra/tegra210_sfc.c
@@ -3598,20 +3598,18 @@ static int tegra210_sfc_platform_probe(struct platform_device *pdev)
sfc->regmap = devm_regmap_init_mmio(dev, regs,
&tegra210_sfc_regmap_config);
- if (IS_ERR(sfc->regmap)) {
- dev_err(dev, "regmap init failed\n");
- return PTR_ERR(sfc->regmap);
- }
+ if (IS_ERR(sfc->regmap))
+ return dev_err_probe(dev, PTR_ERR(sfc->regmap),
+ "regmap init failed\n");
regcache_cache_only(sfc->regmap, true);
err = devm_snd_soc_register_component(dev, &tegra210_sfc_cmpnt,
tegra210_sfc_dais,
ARRAY_SIZE(tegra210_sfc_dais));
- if (err) {
- dev_err(dev, "can't register SFC component, err: %d\n", err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "can't register SFC component\n");
pm_runtime_enable(&pdev->dev);
diff --git a/sound/soc/tegra/tegra_asoc_machine.c b/sound/soc/tegra/tegra_asoc_machine.c
index d48463ac16fc..50b23bbb637b 100644
--- a/sound/soc/tegra/tegra_asoc_machine.c
+++ b/sound/soc/tegra/tegra_asoc_machine.c
@@ -287,6 +287,25 @@ static unsigned int tegra_machine_mclk_rate_6mhz(unsigned int srate)
return mclk;
}
+static unsigned int tegra_machine_mclk_rate_cpcap(unsigned int srate)
+{
+ unsigned int mclk;
+
+ switch (srate) {
+ case 11025:
+ case 22050:
+ case 44100:
+ case 88200:
+ mclk = 26000000;
+ break;
+ default:
+ mclk = 256 * srate;
+ break;
+ }
+
+ return mclk;
+}
+
static int tegra_machine_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -413,7 +432,8 @@ static int tegra_machine_register_codec(struct device *dev, const char *name)
pdev = platform_device_register_simple(name, -1, NULL, 0);
if (IS_ERR(pdev))
- return PTR_ERR(pdev);
+ return dev_err_probe(dev, PTR_ERR(pdev),
+ "failed to register codec %s\n", name);
err = devm_add_action_or_reset(dev, tegra_machine_unregister_codec,
pdev);
@@ -449,32 +469,38 @@ int tegra_asoc_machine_probe(struct platform_device *pdev)
gpiod = devm_gpiod_get_optional(dev, "nvidia,hp-mute", GPIOD_OUT_HIGH);
machine->gpiod_hp_mute = gpiod;
if (IS_ERR(gpiod))
- return PTR_ERR(gpiod);
+ return dev_err_probe(dev, PTR_ERR(gpiod),
+ "failed to get hp-mute GPIO\n");
gpiod = devm_gpiod_get_optional(dev, "nvidia,hp-det", GPIOD_IN);
machine->gpiod_hp_det = gpiod;
if (IS_ERR(gpiod))
- return PTR_ERR(gpiod);
+ return dev_err_probe(dev, PTR_ERR(gpiod),
+ "failed to get hp-det GPIO\n");
gpiod = devm_gpiod_get_optional(dev, "nvidia,mic-det", GPIOD_IN);
machine->gpiod_mic_det = gpiod;
if (IS_ERR(gpiod))
- return PTR_ERR(gpiod);
+ return dev_err_probe(dev, PTR_ERR(gpiod),
+ "failed to get mic-det GPIO\n");
gpiod = devm_gpiod_get_optional(dev, "nvidia,spkr-en", GPIOD_OUT_LOW);
machine->gpiod_spkr_en = gpiod;
if (IS_ERR(gpiod))
- return PTR_ERR(gpiod);
+ return dev_err_probe(dev, PTR_ERR(gpiod),
+ "failed to get spkr-en GPIO\n");
gpiod = devm_gpiod_get_optional(dev, "nvidia,int-mic-en", GPIOD_OUT_LOW);
machine->gpiod_int_mic_en = gpiod;
if (IS_ERR(gpiod))
- return PTR_ERR(gpiod);
+ return dev_err_probe(dev, PTR_ERR(gpiod),
+ "failed to get int-mic-en GPIO\n");
gpiod = devm_gpiod_get_optional(dev, "nvidia,ext-mic-en", GPIOD_OUT_LOW);
machine->gpiod_ext_mic_en = gpiod;
if (IS_ERR(gpiod))
- return PTR_ERR(gpiod);
+ return dev_err_probe(dev, PTR_ERR(gpiod),
+ "failed to get ext-mic-en GPIO\n");
err = snd_soc_of_parse_card_name(card, "nvidia,model");
if (err)
@@ -530,22 +556,19 @@ int tegra_asoc_machine_probe(struct platform_device *pdev)
card->driver_name = "tegra";
machine->clk_pll_a = devm_clk_get(dev, "pll_a");
- if (IS_ERR(machine->clk_pll_a)) {
- dev_err(dev, "Can't retrieve clk pll_a\n");
- return PTR_ERR(machine->clk_pll_a);
- }
+ if (IS_ERR(machine->clk_pll_a))
+ return dev_err_probe(dev, PTR_ERR(machine->clk_pll_a),
+ "can't retrieve clk pll_a\n");
machine->clk_pll_a_out0 = devm_clk_get(dev, "pll_a_out0");
- if (IS_ERR(machine->clk_pll_a_out0)) {
- dev_err(dev, "Can't retrieve clk pll_a_out0\n");
- return PTR_ERR(machine->clk_pll_a_out0);
- }
+ if (IS_ERR(machine->clk_pll_a_out0))
+ return dev_err_probe(dev, PTR_ERR(machine->clk_pll_a_out0),
+ "can't retrieve clk pll_a_out0\n");
machine->clk_cdev1 = devm_clk_get(dev, "mclk");
- if (IS_ERR(machine->clk_cdev1)) {
- dev_err(dev, "Can't retrieve clk cdev1\n");
- return PTR_ERR(machine->clk_cdev1);
- }
+ if (IS_ERR(machine->clk_cdev1))
+ return dev_err_probe(dev, PTR_ERR(machine->clk_cdev1),
+ "can't retrieve clk cdev1\n");
/*
* If clock parents are not set in DT, configure here to use clk_out_1
@@ -559,28 +582,24 @@ int tegra_asoc_machine_probe(struct platform_device *pdev)
dev_warn(dev, "Please update DT to use assigned-clock-parents\n");
clk_extern1 = devm_clk_get(dev, "extern1");
- if (IS_ERR(clk_extern1)) {
- dev_err(dev, "Can't retrieve clk extern1\n");
- return PTR_ERR(clk_extern1);
- }
+ if (IS_ERR(clk_extern1))
+ return dev_err_probe(dev, PTR_ERR(clk_extern1),
+ "can't retrieve clk extern1\n");
err = clk_set_parent(clk_extern1, machine->clk_pll_a_out0);
- if (err < 0) {
- dev_err(dev, "Set parent failed for clk extern1\n");
- return err;
- }
+ if (err < 0)
+ return dev_err_probe(dev, err,
+ "set parent failed for clk extern1\n");
clk_out_1 = devm_clk_get(dev, "pmc_clk_out_1");
- if (IS_ERR(clk_out_1)) {
- dev_err(dev, "Can't retrieve pmc_clk_out_1\n");
- return PTR_ERR(clk_out_1);
- }
+ if (IS_ERR(clk_out_1))
+ return dev_err_probe(dev, PTR_ERR(clk_out_1),
+ "can't retrieve pmc_clk_out_1\n");
err = clk_set_parent(clk_out_1, clk_extern1);
- if (err < 0) {
- dev_err(dev, "Set parent failed for pmc_clk_out_1\n");
- return err;
- }
+ if (err < 0)
+ return dev_err_probe(dev, err,
+ "set parent failed for pmc_clk_out_1\n");
machine->clk_cdev1 = clk_out_1;
}
@@ -591,16 +610,14 @@ int tegra_asoc_machine_probe(struct platform_device *pdev)
* host controller and the external codec
*/
err = clk_set_rate(machine->clk_pll_a, 73728000);
- if (err) {
- dev_err(dev, "Can't set pll_a rate: %d\n", err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "can't set pll_a rate\n");
err = clk_set_rate(machine->clk_pll_a_out0, 24576000);
- if (err) {
- dev_err(dev, "Can't set pll_a_out0 rate: %d\n", err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "can't set pll_a_out0 rate\n");
machine->set_baseclock = 73728000;
machine->set_mclk = 24576000;
@@ -612,10 +629,9 @@ int tegra_asoc_machine_probe(struct platform_device *pdev)
* only needed for audio.
*/
err = clk_prepare_enable(machine->clk_cdev1);
- if (err) {
- dev_err(dev, "Can't enable cdev1: %d\n", err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "can't enable cdev1\n");
err = devm_snd_soc_register_card(dev, card);
if (err)
@@ -985,6 +1001,38 @@ static const struct tegra_asoc_data tegra_rt5631_data = {
.add_hp_jack = true,
};
+/* CPCAP machine */
+
+SND_SOC_DAILINK_DEFS(cpcap_hifi,
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "cpcap-hifi")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link tegra_cpcap_dai = {
+ .name = "CPCAP",
+ .stream_name = "CPCAP PCM",
+ .init = tegra_asoc_machine_init,
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBP_CFP,
+ SND_SOC_DAILINK_REG(cpcap_hifi),
+};
+
+static struct snd_soc_card snd_soc_tegra_cpcap = {
+ .components = "codec:cpcap",
+ .dai_link = &tegra_cpcap_dai,
+ .num_links = 1,
+ .fully_routed = true,
+};
+
+static const struct tegra_asoc_data tegra_cpcap_data = {
+ .mclk_rate = tegra_machine_mclk_rate_cpcap,
+ .card = &snd_soc_tegra_cpcap,
+ .add_common_dapm_widgets = true,
+ .add_common_controls = true,
+ .add_common_snd_ops = true,
+};
+
static const struct of_device_id tegra_machine_of_match[] = {
{ .compatible = "nvidia,tegra-audio-trimslice", .data = &tegra_trimslice_data },
{ .compatible = "nvidia,tegra-audio-max98090", .data = &tegra_max98090_data },
@@ -997,6 +1045,7 @@ static const struct of_device_id tegra_machine_of_match[] = {
{ .compatible = "nvidia,tegra-audio-rt5640", .data = &tegra_rt5640_data },
{ .compatible = "nvidia,tegra-audio-alc5632", .data = &tegra_rt5632_data },
{ .compatible = "nvidia,tegra-audio-rt5631", .data = &tegra_rt5631_data },
+ { .compatible = "nvidia,tegra-audio-cpcap", .data = &tegra_cpcap_data },
{},
};
MODULE_DEVICE_TABLE(of, tegra_machine_of_match);
diff --git a/sound/soc/tegra/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c
index ea10e6e8a9fe..b93a61db9ed0 100644
--- a/sound/soc/tegra/tegra_audio_graph_card.c
+++ b/sound/soc/tegra/tegra_audio_graph_card.c
@@ -174,20 +174,23 @@ static int tegra_audio_graph_card_probe(struct snd_soc_card *card)
{
struct simple_util_priv *simple = snd_soc_card_get_drvdata(card);
struct tegra_audio_priv *priv = simple_to_tegra_priv(simple);
+ int ret;
priv->clk_plla = devm_clk_get(card->dev, "pll_a");
- if (IS_ERR(priv->clk_plla)) {
- dev_err(card->dev, "Can't retrieve clk pll_a\n");
- return PTR_ERR(priv->clk_plla);
- }
+ if (IS_ERR(priv->clk_plla))
+ return dev_err_probe(card->dev, PTR_ERR(priv->clk_plla),
+ "can't retrieve clk pll_a\n");
priv->clk_plla_out0 = devm_clk_get(card->dev, "plla_out0");
- if (IS_ERR(priv->clk_plla_out0)) {
- dev_err(card->dev, "Can't retrieve clk plla_out0\n");
- return PTR_ERR(priv->clk_plla_out0);
- }
+ if (IS_ERR(priv->clk_plla_out0))
+ return dev_err_probe(card->dev, PTR_ERR(priv->clk_plla_out0),
+ "can't retrieve clk plla_out0\n");
+
+ ret = graph_util_card_probe(card);
+ if (ret < 0)
+ return dev_err_probe(card->dev, ret, "graph_util_card_probe failed\n");
- return graph_util_card_probe(card);
+ return ret;
}
static int tegra_audio_graph_probe(struct platform_device *pdev)
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 05d59e03b1c5..c490a9e66858 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -204,8 +204,8 @@ static int tegra_pcm_dma_allocate(struct device *dev, struct snd_soc_pcm_runtime
return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_WC, dev, size);
}
-int tegra_pcm_construct(struct snd_soc_component *component,
- struct snd_soc_pcm_runtime *rtd)
+int tegra_pcm_new(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtd)
{
struct device *dev = component->dev;
@@ -218,7 +218,7 @@ int tegra_pcm_construct(struct snd_soc_component *component,
return tegra_pcm_dma_allocate(dev, rtd, tegra_pcm_hardware.buffer_bytes_max);
}
-EXPORT_SYMBOL_GPL(tegra_pcm_construct);
+EXPORT_SYMBOL_GPL(tegra_pcm_new);
MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
MODULE_DESCRIPTION("Tegra PCM ASoC driver");
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index 2a36eea1740d..ad69ca9233da 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -20,8 +20,8 @@
#include <sound/dmaengine_pcm.h>
#include <sound/asound.h>
-int tegra_pcm_construct(struct snd_soc_component *component,
- struct snd_soc_pcm_runtime *rtd);
+int tegra_pcm_new(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtd);
int tegra_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream);
int tegra_pcm_close(struct snd_soc_component *component,
diff --git a/sound/soc/tegra/tegra_wm8962.c b/sound/soc/tegra/tegra_wm8962.c
new file mode 100644
index 000000000000..31f9d9181595
--- /dev/null
+++ b/sound/soc/tegra/tegra_wm8962.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * tegra_wm8962.c - Tegra machine ASoC driver for boards using WM8962 codec.
+ *
+ * Copyright (C) 2021-2024 Jonas Schwöbel <jonasschwoebel@yahoo.de>
+ * Svyatoslav Ryhel <clamor95@gmail.com>
+ *
+ * Based on tegra_wm8903 code copyright/by:
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+
+#include "../codecs/wm8962.h"
+
+#include "tegra_asoc_machine.h"
+
+static struct snd_soc_jack_pin tegra_wm8962_mic_jack_pins[] = {
+ { .pin = "Mic Jack", .mask = SND_JACK_MICROPHONE },
+};
+
+static unsigned int tegra_wm8962_mclk_rate(unsigned int srate)
+{
+ unsigned int mclk;
+
+ switch (srate) {
+ case 8000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 48000:
+ case 64000:
+ case 96000:
+ mclk = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ case 88200:
+ mclk = 11289600;
+ break;
+ default:
+ mclk = 12000000;
+ break;
+ }
+
+ return mclk;
+}
+
+static int tegra_wm8962_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct tegra_machine *machine = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ int err;
+
+ err = tegra_asoc_machine_init(rtd);
+ if (err)
+ return err;
+
+ if (!machine->gpiod_mic_det && machine->asoc->add_mic_jack) {
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_component *component = codec_dai->component;
+
+ err = snd_soc_card_jack_new_pins(rtd->card, "Mic Jack",
+ SND_JACK_MICROPHONE,
+ machine->mic_jack,
+ tegra_wm8962_mic_jack_pins,
+ ARRAY_SIZE(tegra_wm8962_mic_jack_pins));
+ if (err) {
+ dev_err(rtd->dev, "Mic Jack creation failed: %d\n", err);
+ return err;
+ }
+
+ wm8962_mic_detect(component, machine->mic_jack);
+ }
+
+ snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+
+ return 0;
+}
+
+static int tegra_wm8962_remove(struct snd_soc_card *card)
+{
+ struct snd_soc_dai_link *link = &card->dai_link[0];
+ struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card, link);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_component *component = codec_dai->component;
+
+ wm8962_mic_detect(component, NULL);
+
+ return 0;
+}
+
+SND_SOC_DAILINK_DEFS(wm8962_hifi,
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8962")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link tegra_wm8962_dai = {
+ .name = "WM8962",
+ .stream_name = "WM8962 PCM",
+ .init = tegra_wm8962_init,
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBC_CFC,
+ SND_SOC_DAILINK_REG(wm8962_hifi),
+};
+
+static struct snd_soc_card snd_soc_tegra_wm8962 = {
+ .components = "codec:wm8962",
+ .owner = THIS_MODULE,
+ .dai_link = &tegra_wm8962_dai,
+ .num_links = 1,
+ .remove = tegra_wm8962_remove,
+ .fully_routed = true,
+};
+
+static const struct tegra_asoc_data tegra_wm8962_data = {
+ .mclk_rate = tegra_wm8962_mclk_rate,
+ .card = &snd_soc_tegra_wm8962,
+ .add_common_dapm_widgets = true,
+ .add_common_controls = true,
+ .add_common_snd_ops = true,
+ .add_mic_jack = true,
+ .add_hp_jack = true,
+};
+
+static const struct of_device_id tegra_wm8962_of_match[] = {
+ { .compatible = "nvidia,tegra-audio-wm8962", .data = &tegra_wm8962_data },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tegra_wm8962_of_match);
+
+static struct platform_driver tegra_wm8962_driver = {
+ .driver = {
+ .name = "tegra-wm8962",
+ .of_match_table = tegra_wm8962_of_match,
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = tegra_asoc_machine_probe,
+};
+module_platform_driver(tegra_wm8962_driver);
+
+MODULE_AUTHOR("Jonas Schwöbel <jonasschwoebel@yahoo.de>");
+MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
+MODULE_DESCRIPTION("Tegra+WM8962 machine ASoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index 2d260fbc9b83..f229f847eaf4 100644
--- a/sound/soc/ti/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -274,6 +274,14 @@ static inline unsigned int mcasp_get_auxclk_fs_ratio(struct davinci_mcasp *mcasp
mcasp->auxclk_fs_ratio_tx : mcasp->auxclk_fs_ratio_rx;
}
+static inline bool mcasp_is_auxclk_enabled(struct davinci_mcasp *mcasp, int stream)
+{
+ if (mcasp->async_mode && stream == SNDRV_PCM_STREAM_CAPTURE)
+ return mcasp_get_reg(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG) & AHCLKRE;
+
+ return mcasp_get_reg(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG) & AHCLKXE;
+}
+
static void mcasp_start_rx(struct davinci_mcasp *mcasp)
{
if (mcasp->rxnumevt) { /* enable FIFO */
@@ -1337,33 +1345,42 @@ static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp,
int bclk_div_id, auxclk_div_id;
bool auxclk_enabled;
+ auxclk_enabled = mcasp_is_auxclk_enabled(mcasp, stream);
+
if (mcasp->async_mode && stream == SNDRV_PCM_STREAM_CAPTURE) {
- auxclk_enabled = mcasp_get_reg(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG) & AHCLKRE;
bclk_div_id = MCASP_CLKDIV_BCLK_RXONLY;
auxclk_div_id = MCASP_CLKDIV_AUXCLK_RXONLY;
} else if (mcasp->async_mode && stream == SNDRV_PCM_STREAM_PLAYBACK) {
- auxclk_enabled = mcasp_get_reg(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG) & AHCLKXE;
bclk_div_id = MCASP_CLKDIV_BCLK_TXONLY;
auxclk_div_id = MCASP_CLKDIV_AUXCLK_TXONLY;
} else {
- auxclk_enabled = mcasp_get_reg(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG) & AHCLKXE;
bclk_div_id = MCASP_CLKDIV_BCLK;
auxclk_div_id = MCASP_CLKDIV_AUXCLK;
}
- if (div > (ACLKXDIV_MASK + 1)) {
- if (auxclk_enabled) {
- aux_div = div / (ACLKXDIV_MASK + 1);
- if (div % (ACLKXDIV_MASK + 1))
- aux_div++;
+ if (div > (ACLKXDIV_MASK + 1) && auxclk_enabled) {
+ if (div <= (AHCLKXDIV_MASK + 1)) {
+ /* aux_div absorbs entire division; bclk_div = 1 */
+ aux_div = div;
+ if ((div + 1) <= (AHCLKXDIV_MASK + 1)) {
+ unsigned int err_lo = sysclk_freq / div -
+ bclk_freq;
+ unsigned int err_hi = bclk_freq -
+ sysclk_freq / (div + 1);
- sysclk_freq /= aux_div;
- div = sysclk_freq / bclk_freq;
- rem = sysclk_freq % bclk_freq;
- } else if (set) {
- dev_warn(mcasp->dev, "Too fast reference clock (%u)\n",
- sysclk_freq);
+ if (err_hi < err_lo)
+ aux_div = div + 1;
+ }
+ } else {
+ aux_div = DIV_ROUND_UP(div, ACLKXDIV_MASK + 1);
}
+
+ sysclk_freq /= aux_div;
+ div = sysclk_freq / bclk_freq;
+ rem = sysclk_freq % bclk_freq;
+ } else if (div > (ACLKXDIV_MASK + 1) && set) {
+ dev_warn(mcasp->dev, "Too fast reference clock (%u)\n",
+ sysclk_freq);
}
if (rem != 0) {
@@ -2823,6 +2840,8 @@ static int davinci_mcasp_runtime_resume(struct device *dev)
#endif
static const struct dev_pm_ops davinci_mcasp_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend,
davinci_mcasp_runtime_resume,
NULL)
diff --git a/sound/soc/uniphier/aio-dma.c b/sound/soc/uniphier/aio-dma.c
index 265d61723e99..c1ca55997103 100644
--- a/sound/soc/uniphier/aio-dma.c
+++ b/sound/soc/uniphier/aio-dma.c
@@ -226,7 +226,7 @@ static const struct snd_soc_component_driver uniphier_soc_platform = {
.trigger = uniphier_aiodma_trigger,
.pointer = uniphier_aiodma_pointer,
.mmap = uniphier_aiodma_mmap,
- .pcm_construct = uniphier_aiodma_new,
+ .pcm_new = uniphier_aiodma_new,
.compress_ops = &uniphier_aio_compress_ops,
};
diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c
index 04a4eae1bc92..8f7a76758535 100644
--- a/sound/soc/xilinx/xlnx_formatter_pcm.c
+++ b/sound/soc/xilinx/xlnx_formatter_pcm.c
@@ -582,7 +582,7 @@ static const struct snd_soc_component_driver xlnx_asoc_component = {
.hw_params = xlnx_formatter_pcm_hw_params,
.trigger = xlnx_formatter_pcm_trigger,
.pointer = xlnx_formatter_pcm_pointer,
- .pcm_construct = xlnx_formatter_pcm_new,
+ .pcm_new = xlnx_formatter_pcm_new,
};
static int xlnx_formatter_pcm_probe(struct platform_device *pdev)
diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c
index 678ded059b95..9ad86c54e3ea 100644
--- a/sound/soc/xtensa/xtfpga-i2s.c
+++ b/sound/soc/xtensa/xtfpga-i2s.c
@@ -481,7 +481,7 @@ static const struct snd_soc_component_driver xtfpga_i2s_component = {
.hw_params = xtfpga_pcm_hw_params,
.trigger = xtfpga_pcm_trigger,
.pointer = xtfpga_pcm_pointer,
- .pcm_construct = xtfpga_pcm_new,
+ .pcm_new = xtfpga_pcm_new,
.legacy_dai_naming = 1,
};
diff --git a/sound/usb/qcom/Makefile b/sound/usb/qcom/Makefile
index 6567727b66f0..aa8fcf8d2458 100644
--- a/sound/usb/qcom/Makefile
+++ b/sound/usb/qcom/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
snd-usb-audio-qmi-y := usb_audio_qmi_v01.o qc_audio_offload.o
snd-usb-audio-qmi-y += mixer_usb_offload.o
obj-$(CONFIG_SND_USB_AUDIO_QMI) += snd-usb-audio-qmi.o
diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h
index 7ce8c2a7d714..88bf9ef2c491 100644
--- a/sound/x86/intel_hdmi_audio.h
+++ b/sound/x86/intel_hdmi_audio.h
@@ -1,30 +1,10 @@
+/* SPDX-License-Identifier: MIT */
/*
* Copyright (C) 2016 Intel Corporation
* Authors: Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
* Ramesh Babu K V <ramesh.babu@intel.com>
* Vaibhav Agarwal <vaibhav.agarwal@intel.com>
* Jerome Anand <jerome.anand@intel.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _INTEL_HDMI_AUDIO_H_