aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/dsp/fsl,dsp.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,asrc.txt4
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,easrc.yaml101
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt1
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt25
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6adm.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6afe.txt46
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6asm.txt7
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6core.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip-i2s.yaml12
-rw-r--r--Documentation/devicetree/bindings/sound/rt1016.txt17
-rw-r--r--Documentation/devicetree/bindings/sound/simple-card.txt351
-rw-r--r--Documentation/devicetree/bindings/sound/simple-card.yaml484
-rw-r--r--Documentation/devicetree/bindings/sound/tlv320adcx140.yaml24
-rw-r--r--Documentation/devicetree/bindings/sound/wm8994.txt18
-rw-r--r--Documentation/devicetree/bindings/sound/zl38060.yaml69
-rw-r--r--drivers/soundwire/intel.c4
-rw-r--r--include/sound/soc-acpi.h2
-rw-r--r--include/sound/soc-component.h40
-rw-r--r--include/sound/soc-dai.h41
-rw-r--r--include/sound/soc-dapm.h2
-rw-r--r--include/sound/soc.h34
-rw-r--r--include/sound/sof.h5
-rw-r--r--include/sound/sof/channel_map.h2
-rw-r--r--include/sound/sof/control.h2
-rw-r--r--include/sound/sof/dai-imx.h2
-rw-r--r--include/sound/sof/dai-intel.h22
-rw-r--r--include/sound/sof/dai.h2
-rw-r--r--include/sound/sof/header.h2
-rw-r--r--include/sound/sof/info.h28
-rw-r--r--include/sound/sof/pm.h2
-rw-r--r--include/sound/sof/stream.h2
-rw-r--r--include/sound/sof/topology.h18
-rw-r--r--include/sound/sof/trace.h4
-rw-r--r--include/sound/sof/xtensa.h2
-rw-r--r--include/uapi/sound/skl-tplg-interface.h2
-rw-r--r--include/uapi/sound/sof/abi.h2
-rw-r--r--include/uapi/sound/sof/tokens.h8
-rw-r--r--sound/hda/intel-nhlt.c2
-rw-r--r--sound/pci/hda/patch_hdmi.c1
-rw-r--r--sound/soc/codecs/Kconfig24
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/ad1980.c2
-rw-r--r--sound/soc/codecs/ad73311.c2
-rw-r--r--sound/soc/codecs/cros_ec_codec.c17
-rw-r--r--sound/soc/codecs/cs47l15.c9
-rw-r--r--sound/soc/codecs/cs47l24.c8
-rw-r--r--sound/soc/codecs/cs47l35.c9
-rw-r--r--sound/soc/codecs/cs47l85.c9
-rw-r--r--sound/soc/codecs/cs47l90.c9
-rw-r--r--sound/soc/codecs/cs47l92.c9
-rw-r--r--sound/soc/codecs/dmic.c4
-rw-r--r--sound/soc/codecs/nau8810.c35
-rw-r--r--sound/soc/codecs/nau8810.h8
-rw-r--r--sound/soc/codecs/rl6231.c29
-rw-r--r--sound/soc/codecs/rl6231.h1
-rw-r--r--sound/soc/codecs/rt1015.c27
-rw-r--r--sound/soc/codecs/rt1015.h1
-rw-r--r--sound/soc/codecs/rt1016.c695
-rw-r--r--sound/soc/codecs/rt1016.h232
-rw-r--r--sound/soc/codecs/rt1308-sdw.c4
-rw-r--r--sound/soc/codecs/rt5677-spi.c12
-rw-r--r--sound/soc/codecs/rt5682.c198
-rw-r--r--sound/soc/codecs/tlv320adcx140.c41
-rw-r--r--sound/soc/codecs/tlv320adcx140.h3
-rw-r--r--sound/soc/codecs/wcd9335.c44
-rw-r--r--sound/soc/codecs/wcd934x.c30
-rw-r--r--sound/soc/codecs/wm5102.c9
-rw-r--r--sound/soc/codecs/wm5110.c8
-rw-r--r--sound/soc/codecs/wm8524.c4
-rw-r--r--sound/soc/codecs/wm8782.c2
-rw-r--r--sound/soc/codecs/wm8900.c6
-rw-r--r--sound/soc/codecs/wm8990.c98
-rw-r--r--sound/soc/codecs/wm8991.c8
-rw-r--r--sound/soc/codecs/wm8994.c8
-rw-r--r--sound/soc/codecs/wm_adsp.c18
-rw-r--r--sound/soc/codecs/wm_adsp.h18
-rw-r--r--sound/soc/codecs/zl38060.c638
-rw-r--r--sound/soc/fsl/Kconfig11
-rw-r--r--sound/soc/fsl/Makefile2
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c24
-rw-r--r--sound/soc/fsl/fsl_asrc.c309
-rw-r--r--sound/soc/fsl/fsl_asrc.h74
-rw-r--r--sound/soc/fsl/fsl_asrc_common.h106
-rw-r--r--sound/soc/fsl/fsl_asrc_dma.c54
-rw-r--r--sound/soc/fsl/fsl_easrc.c2117
-rw-r--r--sound/soc/fsl/fsl_easrc.h651
-rw-r--r--sound/soc/fsl/fsl_micfil.c4
-rw-r--r--sound/soc/hisilicon/hi6210-i2s.c16
-rw-r--r--sound/soc/intel/Kconfig8
-rw-r--r--sound/soc/intel/Makefile2
-rw-r--r--sound/soc/intel/atom/Makefile2
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.h2
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-compress.c43
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c2
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform.h2
-rw-r--r--sound/soc/intel/atom/sst/Makefile2
-rw-r--r--sound/soc/intel/boards/Kconfig59
-rw-r--r--sound/soc/intel/boards/Makefile6
-rw-r--r--sound/soc/intel/boards/bdw-rt5650.c29
-rw-r--r--sound/soc/intel/boards/bdw-rt5677.c26
-rw-r--r--sound/soc/intel/boards/broadwell.c26
-rw-r--r--sound/soc/intel/boards/bytcht_cx2072x.c2
-rw-r--r--sound/soc/intel/boards/cml_rt1011_rt5682.c224
-rw-r--r--sound/soc/intel/boards/ehl_rt5660.c323
-rw-r--r--sound/soc/intel/boards/glk_rt5682_max98357a.c2
-rw-r--r--sound/soc/intel/boards/hda_dsp_common.c2
-rw-r--r--sound/soc/intel/boards/hda_dsp_common.h2
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98357a.c2
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98927.c2
-rw-r--r--sound/soc/intel/boards/kbl_rt5660.c2
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_common.c2
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_common.h2
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_generic.c33
-rw-r--r--sound/soc/intel/boards/sof_da7219_max98373.c23
-rw-r--r--sound/soc/intel/boards/sof_maxim_common.c2
-rw-r--r--sound/soc/intel/boards/sof_maxim_common.h2
-rw-r--r--sound/soc/intel/boards/sof_pcm512x.c2
-rw-r--r--sound/soc/intel/boards/sof_rt5682.c2
-rw-r--r--sound/soc/intel/boards/sof_sdw.c57
-rw-r--r--sound/soc/intel/boards/sof_sdw_common.h2
-rw-r--r--sound/soc/intel/boards/sof_sdw_dmic.c2
-rw-r--r--sound/soc/intel/boards/sof_sdw_hdmi.c6
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt1308.c4
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt5682.c5
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt700.c5
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt711.c5
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt715.c2
-rw-r--r--sound/soc/intel/boards/sof_wm8804.c298
-rw-r--r--sound/soc/intel/common/Makefile2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-bxt-match.c2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cfl-match.c2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cml-match.c2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cnl-match.c2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-ehl-match.c9
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-glk-match.c2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-hda-match.c2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-icl-match.c2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-jsl-match.c2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-kbl-match.c2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-skl-match.c2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-tgl-match.c2
-rw-r--r--sound/soc/intel/common/soc-intel-quirks.h2
-rw-r--r--sound/soc/intel/haswell/sst-haswell-dsp.c185
-rw-r--r--sound/soc/intel/skylake/Makefile2
-rw-r--r--sound/soc/intel/skylake/skl-i2s.h2
-rw-r--r--sound/soc/intel/skylake/skl-ssp-clk.c2
-rw-r--r--sound/soc/intel/skylake/skl-sst-utils.c2
-rw-r--r--sound/soc/intel/skylake/skl-topology.c184
-rw-r--r--sound/soc/intel/skylake/skl-topology.h5
-rw-r--r--sound/soc/intel/skylake/skl.h2
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-pcm.c7
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c16
-rw-r--r--sound/soc/mxs/mxs-saif.c5
-rw-r--r--sound/soc/pxa/mmp-sspa.c349
-rw-r--r--sound/soc/pxa/mmp-sspa.h4
-rw-r--r--sound/soc/qcom/lpass-apq8016.c9
-rw-r--r--sound/soc/qcom/lpass-cpu.c235
-rw-r--r--sound/soc/qcom/lpass-lpaif-reg.h30
-rw-r--r--sound/soc/qcom/lpass.h4
-rw-r--r--sound/soc/qcom/qdsp6/q6asm-dai.c51
-rw-r--r--sound/soc/sh/rcar/gen.c8
-rw-r--r--sound/soc/sh/rcar/rsnd.h9
-rw-r--r--sound/soc/sh/rcar/ssi.c145
-rw-r--r--sound/soc/soc-compress.c231
-rw-r--r--sound/soc/soc-core.c145
-rw-r--r--sound/soc/soc-dai.c453
-rw-r--r--sound/soc/soc-dapm.c4
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c6
-rw-r--r--sound/soc/soc-pcm.c80
-rw-r--r--sound/soc/soc-topology.c2
-rw-r--r--sound/soc/sof/Makefile2
-rw-r--r--sound/soc/sof/compress.c9
-rw-r--r--sound/soc/sof/compress.h9
-rw-r--r--sound/soc/sof/control.c2
-rw-r--r--sound/soc/sof/core.c3
-rw-r--r--sound/soc/sof/debug.c2
-rw-r--r--sound/soc/sof/imx/Kconfig34
-rw-r--r--sound/soc/sof/imx/Makefile4
-rw-r--r--sound/soc/sof/imx/imx8.c2
-rw-r--r--sound/soc/sof/imx/imx8m.c279
-rw-r--r--sound/soc/sof/intel/Makefile2
-rw-r--r--sound/soc/sof/intel/apl.c2
-rw-r--r--sound/soc/sof/intel/bdw.c2
-rw-r--r--sound/soc/sof/intel/byt.c56
-rw-r--r--sound/soc/sof/intel/cnl.c2
-rw-r--r--sound/soc/sof/intel/hda-bus.c2
-rw-r--r--sound/soc/sof/intel/hda-codec.c7
-rw-r--r--sound/soc/sof/intel/hda-compress.c2
-rw-r--r--sound/soc/sof/intel/hda-ctrl.c2
-rw-r--r--sound/soc/sof/intel/hda-dai.c2
-rw-r--r--sound/soc/sof/intel/hda-dsp.c10
-rw-r--r--sound/soc/sof/intel/hda-ipc.c2
-rw-r--r--sound/soc/sof/intel/hda-ipc.h2
-rw-r--r--sound/soc/sof/intel/hda-loader.c11
-rw-r--r--sound/soc/sof/intel/hda-pcm.c2
-rw-r--r--sound/soc/sof/intel/hda-stream.c2
-rw-r--r--sound/soc/sof/intel/hda-trace.c2
-rw-r--r--sound/soc/sof/intel/hda.c18
-rw-r--r--sound/soc/sof/intel/hda.h2
-rw-r--r--sound/soc/sof/intel/intel-ipc.c2
-rw-r--r--sound/soc/sof/intel/shim.h2
-rw-r--r--sound/soc/sof/ipc.c2
-rw-r--r--sound/soc/sof/loader.c39
-rw-r--r--sound/soc/sof/nocodec.c8
-rw-r--r--sound/soc/sof/ops.c2
-rw-r--r--sound/soc/sof/ops.h2
-rw-r--r--sound/soc/sof/pcm.c18
-rw-r--r--sound/soc/sof/pm.c2
-rw-r--r--sound/soc/sof/probe.c2
-rw-r--r--sound/soc/sof/probe.h2
-rw-r--r--sound/soc/sof/sof-acpi-dev.c2
-rw-r--r--sound/soc/sof/sof-audio.c2
-rw-r--r--sound/soc/sof/sof-audio.h2
-rw-r--r--sound/soc/sof/sof-of-dev.c16
-rw-r--r--sound/soc/sof/sof-pci-dev.c4
-rw-r--r--sound/soc/sof/sof-priv.h4
-rw-r--r--sound/soc/sof/topology.c482
-rw-r--r--sound/soc/sof/trace.c2
-rw-r--r--sound/soc/sof/utils.c2
-rw-r--r--sound/soc/sof/xtensa/Makefile2
-rw-r--r--sound/soc/sof/xtensa/core.c2
-rw-r--r--sound/soc/sprd/sprd-pcm-compress.c49
-rw-r--r--sound/soc/sprd/sprd-pcm-dma.c2
-rw-r--r--sound/soc/sprd/sprd-pcm-dma.h2
-rw-r--r--sound/soc/tegra/tegra_wm8903.c20
-rw-r--r--sound/soc/ti/omap-mcbsp.c10
-rw-r--r--sound/soc/uniphier/aio-compress.c45
-rw-r--r--sound/soc/uniphier/aio-dma.c2
-rw-r--r--sound/soc/uniphier/aio.h2
-rw-r--r--sound/soc/ux500/mop500.c11
231 files changed, 9290 insertions, 2411 deletions
diff --git a/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml b/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml
index a5dc070d0ca7..3bbe9521c0bc 100644
--- a/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml
+++ b/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml
@@ -17,6 +17,8 @@ properties:
compatible:
enum:
- fsl,imx8qxp-dsp
+ - fsl,imx8qm-dsp
+ - fsl,imx8mp-dsp
reg:
description: Should contain register location and length
diff --git a/Documentation/devicetree/bindings/sound/fsl,asrc.txt b/Documentation/devicetree/bindings/sound/fsl,asrc.txt
index cb9a25165503..998b4c8a7f78 100644
--- a/Documentation/devicetree/bindings/sound/fsl,asrc.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,asrc.txt
@@ -51,6 +51,10 @@ Optional properties:
will be in use as default. Otherwise, the big endian
mode will be in use for all the device registers.
+ - fsl,asrc-format : Defines a mutual sample format used by DPCM Back
+ Ends, which can replace the fsl,asrc-width.
+ The value is 2 (S16_LE), or 6 (S24_LE).
+
Example:
asrc: asrc@2034000 {
diff --git a/Documentation/devicetree/bindings/sound/fsl,easrc.yaml b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml
new file mode 100644
index 000000000000..73cdcf053a9c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml
@@ -0,0 +1,101 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/fsl,easrc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP Asynchronous Sample Rate Converter (ASRC) Controller
+
+maintainers:
+ - Shengjiu Wang <[email protected]>
+
+properties:
+ $nodename:
+ pattern: "^easrc@.*"
+
+ compatible:
+ const: fsl,imx8mn-easrc
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: Peripheral clock
+
+ clock-names:
+ items:
+ - const: mem
+
+ dmas:
+ maxItems: 8
+
+ dma-names:
+ items:
+ - const: ctx0_rx
+ - const: ctx0_tx
+ - const: ctx1_rx
+ - const: ctx1_tx
+ - const: ctx2_rx
+ - const: ctx2_tx
+ - const: ctx3_rx
+ - const: ctx3_tx
+
+ firmware-name:
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/string
+ - const: imx/easrc/easrc-imx8mn.bin
+ description: The coefficient table for the filters
+
+ fsl,asrc-rate:
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ - minimum: 8000
+ - maximum: 192000
+ description: Defines a mutual sample rate used by DPCM Back Ends
+
+ fsl,asrc-format:
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ - enum: [2, 6, 10, 32, 36]
+ default: 2
+ description:
+ Defines a mutual sample format used by DPCM Back Ends
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - dmas
+ - dma-names
+ - firmware-name
+ - fsl,asrc-rate
+ - fsl,asrc-format
+
+examples:
+ - |
+ #include <dt-bindings/clock/imx8mn-clock.h>
+
+ easrc: easrc@300c0000 {
+ compatible = "fsl,imx8mn-easrc";
+ reg = <0x0 0x300c0000 0x0 0x10000>;
+ interrupts = <0x0 122 0x4>;
+ clocks = <&clk IMX8MN_CLK_ASRC_ROOT>;
+ clock-names = "mem";
+ dmas = <&sdma2 16 23 0> , <&sdma2 17 23 0>,
+ <&sdma2 18 23 0> , <&sdma2 19 23 0>,
+ <&sdma2 20 23 0> , <&sdma2 21 23 0>,
+ <&sdma2 22 23 0> , <&sdma2 23 23 0>;
+ dma-names = "ctx0_rx", "ctx0_tx",
+ "ctx1_rx", "ctx1_tx",
+ "ctx2_rx", "ctx2_tx",
+ "ctx3_rx", "ctx3_tx";
+ firmware-name = "imx/easrc/easrc-imx8mn.bin";
+ fsl,asrc-rate = <8000>;
+ fsl,asrc-format = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt
index a8f2b0c56c79..bbd581a8c5bc 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt
@@ -29,6 +29,7 @@ Optional properties:
- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in
- nvidia,int-mic-en-gpios : The GPIO that enables the internal microphone
- nvidia,ext-mic-en-gpios : The GPIO that enables the external microphone
+- nvidia,headset : The Mic Jack represents state of the headset microphone pin
Example:
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
index 21c648328be9..32c2cdb3d32f 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
@@ -30,6 +30,8 @@ Required properties:
- reg : Must contain an address for each entry in reg-names.
- reg-names : A list which must include the following entries:
* "lpass-lpaif"
+- #address-cells : Must be 1
+- #size-cells : Must be 0
@@ -37,6 +39,20 @@ Optional properties:
- qcom,adsp : Phandle for the audio DSP node
+By default, the driver uses up to 4 MI2S SD lines, for a total of 8 channels.
+The SD lines to use can be configured by adding subnodes for each of the DAIs.
+
+Required properties for each DAI (represented by a subnode):
+- reg : Must be one of the DAI IDs
+ (usually part of dt-bindings header)
+- qcom,playback-sd-lines: List of serial data lines to use for playback
+ Each SD line should be represented by a number from 0-3.
+- qcom,capture-sd-lines : List of serial data lines to use for capture
+ Each SD line should be represented by a number from 0-3.
+
+Note that adding a subnode changes the default to "no lines configured",
+so both playback and capture lines should be configured when a subnode is added.
+
Example:
lpass@28100000 {
@@ -51,4 +67,13 @@ lpass@28100000 {
reg = <0x28100000 0x10000>;
reg-names = "lpass-lpaif";
qcom,adsp = <&adsp>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* Optional to set different MI2S SD lines */
+ dai@3 {
+ reg = <MI2S_QUATERNARY>;
+ qcom,playback-sd-lines = <0 1>;
+ };
};
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6adm.txt b/Documentation/devicetree/bindings/sound/qcom,q6adm.txt
index bbae426cdfb1..15c353a20de8 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6adm.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,q6adm.txt
@@ -29,7 +29,7 @@ used by the apr service device.
Definition: Must be 0
= EXAMPLE
-q6adm@8 {
+apr-service@8 {
compatible = "qcom,q6adm";
reg = <APR_SVC_ADM>;
q6routing: routing {
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6afe.txt b/Documentation/devicetree/bindings/sound/qcom,q6afe.txt
index d74888b9f1bb..4916dd6a0896 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6afe.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,q6afe.txt
@@ -100,7 +100,7 @@ configuration of each dai. Must contain the following properties.
= EXAMPLE
-q6afe@4 {
+apr-service@4 {
compatible = "qcom,q6afe";
reg = <APR_SVC_AFE>;
@@ -110,12 +110,12 @@ q6afe@4 {
#address-cells = <1>;
#size-cells = <0>;
- hdmi@1 {
- reg = <1>;
+ dai@1 {
+ reg = <HDMI_RX>;
};
- tdm@24 {
- reg = <24>;
+ dai@24 {
+ reg = <PRIMARY_TDM_RX_0>;
qcom,tdm-sync-mode = <1>:
qcom,tdm-sync-src = <1>;
qcom,tdm-data-out = <0>;
@@ -125,8 +125,8 @@ q6afe@4 {
};
- tdm@25 {
- reg = <25>;
+ dai@25 {
+ reg = <PRIMARY_TDM_TX_0>;
qcom,tdm-sync-mode = <1>:
qcom,tdm-sync-src = <1>;
qcom,tdm-data-out = <0>;
@@ -135,43 +135,43 @@ q6afe@4 {
qcom,tdm-data-align = <0>;
};
- prim-mi2s-rx@16 {
- reg = <16>;
+ dai@16 {
+ reg = <PRIMARY_MI2S_RX>;
qcom,sd-lines = <0 2>;
};
- prim-mi2s-tx@17 {
- reg = <17>;
+ dai@17 {
+ reg = <PRIMARY_MI2S_TX>;
qcom,sd-lines = <1>;
};
- sec-mi2s-rx@18 {
- reg = <18>;
+ dai@18 {
+ reg = <SECONDARY_MI2S_RX>;
qcom,sd-lines = <0 3>;
};
- sec-mi2s-tx@19 {
- reg = <19>;
+ dai@19 {
+ reg = <SECONDARY_MI2S_TX>;
qcom,sd-lines = <1>;
};
- tert-mi2s-rx@20 {
- reg = <20>;
+ dai@20 {
+ reg = <TERTIARY_MI2S_RX>;
qcom,sd-lines = <1 3>;
};
- tert-mi2s-tx@21 {
- reg = <21>;
+ dai@21 {
+ reg = <TERTIARY_MI2S_TX>;
qcom,sd-lines = <0>;
};
- quat-mi2s-rx@22 {
- reg = <22>;
+ dai@22 {
+ reg = <QUATERNARY_MI2S_RX>;
qcom,sd-lines = <0>;
};
- quat-mi2s-tx@23 {
- reg = <23>;
+ dai@23 {
+ reg = <QUATERNARY_MI2S_TX>;
qcom,sd-lines = <1>;
};
};
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6asm.txt b/Documentation/devicetree/bindings/sound/qcom,q6asm.txt
index 9f5378c51686..6b9a88d0ea3f 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6asm.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,q6asm.txt
@@ -51,13 +51,16 @@ configuration of each dai. Must contain the following properties.
= EXAMPLE
-q6asm@7 {
+apr-service@7 {
compatible = "qcom,q6asm";
reg = <APR_SVC_ASM>;
q6asmdai: dais {
compatible = "qcom,q6asm-dais";
+ #address-cells = <1>;
+ #size-cells = <0>;
#sound-dai-cells = <1>;
- mm@0 {
+
+ dai@0 {
reg = <0>;
direction = <2>;
is-compress-dai;
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6core.txt b/Documentation/devicetree/bindings/sound/qcom,q6core.txt
index 7f36ff8bec18..5cd4cc9b1fde 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6core.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,q6core.txt
@@ -15,7 +15,7 @@ used by the apr service device.
example "qcom,q6core-v2.0"
= EXAMPLE
-q6core@3 {
+apr-service@3 {
compatible = "qcom,q6core";
reg = <APR_SVC_ADSP_CORE>;
};
diff --git a/Documentation/devicetree/bindings/sound/rockchip-i2s.yaml b/Documentation/devicetree/bindings/sound/rockchip-i2s.yaml
index a3ba2186d6a1..10f9d3ad0d48 100644
--- a/Documentation/devicetree/bindings/sound/rockchip-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/rockchip-i2s.yaml
@@ -24,6 +24,7 @@ properties:
- rockchip,rk3188-i2s
- rockchip,rk3228-i2s
- rockchip,rk3288-i2s
+ - rockchip,rk3308-i2s
- rockchip,rk3328-i2s
- rockchip,rk3366-i2s
- rockchip,rk3368-i2s
@@ -47,14 +48,15 @@ properties:
- const: i2s_hclk
dmas:
- items:
- - description: TX DMA Channel
- - description: RX DMA Channel
+ minItems: 1
+ maxItems: 2
dma-names:
- items:
- - const: tx
+ oneOf:
- const: rx
+ - items:
+ - const: tx
+ - const: rx
power-domains:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/sound/rt1016.txt b/Documentation/devicetree/bindings/sound/rt1016.txt
new file mode 100644
index 000000000000..2310f8ff259b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt1016.txt
@@ -0,0 +1,17 @@
+RT1016 Stereo Class D Audio Amplifier
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt1016".
+
+- reg : The I2C address of the device.
+
+
+Example:
+
+rt1016: codec@1a {
+ compatible = "realtek,rt1016";
+ reg = <0x1a>;
+};
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
deleted file mode 100644
index 79954cd6e37b..000000000000
--- a/Documentation/devicetree/bindings/sound/simple-card.txt
+++ /dev/null
@@ -1,351 +0,0 @@
-Simple-Card:
-
-Simple-Card specifies audio DAI connections of SoC <-> codec.
-
-Required properties:
-
-- compatible : "simple-audio-card"
-
-Optional properties:
-
-- simple-audio-card,name : User specified audio sound card name, one string
- property.
-- simple-audio-card,widgets : Please refer to widgets.txt.
-- simple-audio-card,routing : 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.
-- simple-audio-card,mclk-fs : Multiplication factor between stream rate and codec
- mclk. When defined, mclk-fs property defined in
- dai-link sub nodes are ignored.
-- simple-audio-card,hp-det-gpio : Reference to GPIO that signals when
- headphones are attached.
-- simple-audio-card,mic-det-gpio : Reference to GPIO that signals when
- a microphone is attached.
-- simple-audio-card,aux-devs : List of phandles pointing to auxiliary devices, such
- as amplifiers, to be added to the sound card.
-- simple-audio-card,pin-switches : List of strings containing the widget names for
- which pin switches must be created.
-
-Optional subnodes:
-
-- simple-audio-card,dai-link : Container for dai-link level
- properties and the CPU and CODEC
- sub-nodes. This container may be
- omitted when the card has only one
- DAI link. See the examples and the
- section below.
-
-Dai-link subnode properties and subnodes:
-
-If dai-link subnode is omitted and the subnode properties are directly
-under "sound"-node the subnode property and subnode names have to be
-prefixed with "simple-audio-card,"-prefix.
-
-Required dai-link subnodes:
-
-- cpu : CPU sub-node
-- codec : CODEC sub-node
-
-Optional dai-link subnode properties:
-
-- format : CPU/CODEC common audio format.
- "i2s", "right_j", "left_j" , "dsp_a"
- "dsp_b", "ac97", "pdm", "msb", "lsb"
-- frame-master : Indicates dai-link frame master.
- phandle to a cpu or codec subnode.
-- bitclock-master : Indicates dai-link bit clock master.
- phandle to a cpu or codec subnode.
-- bitclock-inversion : bool property. Add this if the
- dai-link uses bit clock inversion.
-- frame-inversion : bool property. Add this if the
- dai-link uses frame clock inversion.
-- mclk-fs : Multiplication factor between stream
- rate and codec mclk, applied only for
- the dai-link.
-
-For backward compatibility the frame-master and bitclock-master
-properties can be used as booleans in codec subnode to indicate if the
-codec is the dai-link frame or bit clock master. In this case there
-should be no dai-link node, the same properties should not be present
-at sound-node level, and the bitclock-inversion and frame-inversion
-properties should also be placed in the codec node if needed.
-
-Required CPU/CODEC subnodes properties:
-
-- sound-dai : phandle and port of CPU/CODEC
-
-Optional CPU/CODEC subnodes properties:
-
-- dai-tdm-slot-num : Please refer to tdm-slot.txt.
-- dai-tdm-slot-width : Please refer to tdm-slot.txt.
-- clocks / system-clock-frequency : specify subnode's clock if needed.
- it can be specified via "clocks" if system has
- clock node (= common clock), or "system-clock-frequency"
- (if system doens't support common clock)
- If a clock is specified, it is
- enabled with clk_prepare_enable()
- in dai startup() and disabled with
- clk_disable_unprepare() in dai
- shutdown().
- If a clock is specified and a
- multiplication factor is given with
- mclk-fs, the clock will be set to the
- calculated mclk frequency when the
- stream starts.
-- system-clock-direction-out : specifies clock direction as 'out' on
- initialization. It is useful for some aCPUs with
- fixed clocks.
-
--------------------------------------------
-Example 1 - single DAI link:
--------------------------------------------
-
-sound {
- compatible = "simple-audio-card";
- simple-audio-card,name = "VF610-Tower-Sound-Card";
- simple-audio-card,format = "left_j";
- simple-audio-card,bitclock-master = <&dailink0_master>;
- simple-audio-card,frame-master = <&dailink0_master>;
- simple-audio-card,widgets =
- "Microphone", "Microphone Jack",
- "Headphone", "Headphone Jack",
- "Speaker", "External Speaker";
- simple-audio-card,routing =
- "MIC_IN", "Microphone Jack",
- "Headphone Jack", "HP_OUT",
- "External Speaker", "LINE_OUT";
-
- simple-audio-card,cpu {
- sound-dai = <&sh_fsi2 0>;
- };
-
- dailink0_master: simple-audio-card,codec {
- sound-dai = <&ak4648>;
- clocks = <&osc>;
- };
-};
-
-&i2c0 {
- ak4648: ak4648@12 {
- #sound-dai-cells = <0>;
- compatible = "asahi-kasei,ak4648";
- reg = <0x12>;
- };
-};
-
-sh_fsi2: sh_fsi2@ec230000 {
- #sound-dai-cells = <1>;
- compatible = "renesas,sh_fsi2";
- reg = <0xec230000 0x400>;
- interrupt-parent = <&gic>;
- interrupts = <0 146 0x4>;
-};
-
--------------------------------------------
-Example 2 - many DAI links:
--------------------------------------------
-
-sound {
- compatible = "simple-audio-card";
- simple-audio-card,name = "Cubox Audio";
-
- simple-audio-card,dai-link@0 { /* I2S - HDMI */
- reg = <0>;
- format = "i2s";
- cpu {
- sound-dai = <&audio1 0>;
- };
- codec {
- sound-dai = <&tda998x 0>;
- };
- };
-
- simple-audio-card,dai-link@1 { /* S/PDIF - HDMI */
- reg = <1>;
- cpu {
- sound-dai = <&audio1 1>;
- };
- codec {
- sound-dai = <&tda998x 1>;
- };
- };
-
- simple-audio-card,dai-link@2 { /* S/PDIF - S/PDIF */
- reg = <2>;
- cpu {
- sound-dai = <&audio1 1>;
- };
- codec {
- sound-dai = <&spdif_codec>;
- };
- };
-};
-
--------------------------------------------
-Example 3 - route audio from IMX6 SSI2 through TLV320DAC3100 codec
-through TPA6130A2 amplifier to headphones:
--------------------------------------------
-
-&i2c0 {
- codec: tlv320dac3100@18 {
- compatible = "ti,tlv320dac3100";
- ...
- }
-
- amp: tpa6130a2@60 {
- compatible = "ti,tpa6130a2";
- ...
- }
-}
-
-sound {
- compatible = "simple-audio-card";
- ...
- simple-audio-card,widgets =
- "Headphone", "Headphone Jack";
- simple-audio-card,routing =
- "Headphone Jack", "HPLEFT",
- "Headphone Jack", "HPRIGHT",
- "LEFTIN", "HPL",
- "RIGHTIN", "HPR";
- simple-audio-card,aux-devs = <&amp>;
- simple-audio-card,cpu {
- sound-dai = <&ssi2>;
- };
- simple-audio-card,codec {
- sound-dai = <&codec>;
- clocks = ...
- };
-};
-
--------------------------------------------
-Example 4. Sampling Rate Conversion
--------------------------------------------
-
-sound {
- compatible = "simple-audio-card";
-
- simple-audio-card,name = "rsnd-ak4643";
- simple-audio-card,format = "left_j";
- simple-audio-card,bitclock-master = <&sndcodec>;
- simple-audio-card,frame-master = <&sndcodec>;
-
- simple-audio-card,convert-rate = <48000>;
-
- simple-audio-card,prefix = "ak4642";
- simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
- "DAI0 Capture", "ak4642 Capture";
-
- sndcpu: simple-audio-card,cpu {
- sound-dai = <&rcar_sound>;
- };
-
- sndcodec: simple-audio-card,codec {
- sound-dai = <&ak4643>;
- system-clock-frequency = <11289600>;
- };
-};
-
--------------------------------------------
-Example 5. 2 CPU 1 Codec (Mixing)
--------------------------------------------
-sound {
- compatible = "simple-audio-card";
-
- simple-audio-card,name = "rsnd-ak4643";
- simple-audio-card,format = "left_j";
- simple-audio-card,bitclock-master = <&dpcmcpu>;
- simple-audio-card,frame-master = <&dpcmcpu>;
-
- simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
- "ak4642 Playback", "DAI1 Playback";
-
- dpcmcpu: cpu@0 {
- sound-dai = <&rcar_sound 0>;
- };
-
- cpu@1 {
- sound-dai = <&rcar_sound 1>;
- };
-
- codec {
- prefix = "ak4642";
- sound-dai = <&ak4643>;
- clocks = <&audio_clock>;
- };
-};
-
--------------------------------------------
-Example 6 - many DAI links with DPCM:
--------------------------------------------
-
-CPU0 ------ ak4613
-CPU1 ------ PCM3168A-p /* DPCM 1ch/2ch */
-CPU2 --/ /* DPCM 3ch/4ch */
-CPU3 --/ /* DPCM 5ch/6ch */
-CPU4 --/ /* DPCM 7ch/8ch */
-CPU5 ------ PCM3168A-c
-
-sound {
- compatible = "simple-audio-card";
-
- simple-audio-card,routing =
- "pcm3168a Playback", "DAI1 Playback",
- "pcm3168a Playback", "DAI2 Playback",
- "pcm3168a Playback", "DAI3 Playback",
- "pcm3168a Playback", "DAI4 Playback";
-
- simple-audio-card,dai-link@0 {
- format = "left_j";
- bitclock-master = <&sndcpu0>;
- frame-master = <&sndcpu0>;
-
- sndcpu0: cpu {
- sound-dai = <&rcar_sound 0>;
- };
- codec {
- sound-dai = <&ak4613>;
- };
- };
- simple-audio-card,dai-link@1 {
- format = "i2s";
- bitclock-master = <&sndcpu1>;
- frame-master = <&sndcpu1>;
-
- convert-channels = <8>; /* TDM Split */
-
- sndcpu1: cpu@0 {
- sound-dai = <&rcar_sound 1>;
- };
- cpu@1 {
- sound-dai = <&rcar_sound 2>;
- };
- cpu@2 {
- sound-dai = <&rcar_sound 3>;
- };
- cpu@3 {
- sound-dai = <&rcar_sound 4>;
- };
- codec {
- mclk-fs = <512>;
- prefix = "pcm3168a";
- dai-tdm-slot-num = <8>;
- sound-dai = <&pcm3168a 0>;
- };
- };
- simple-audio-card,dai-link@2 {
- format = "i2s";
- bitclock-master = <&sndcpu2>;
- frame-master = <&sndcpu2>;
-
- sndcpu2: cpu {
- sound-dai = <&rcar_sound 5>;
- };
- codec {
- mclk-fs = <512>;
- prefix = "pcm3168a";
- sound-dai = <&pcm3168a 1>;
- };
- };
-};
diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml
new file mode 100644
index 000000000000..cb2bb5fac0e1
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/simple-card.yaml
@@ -0,0 +1,484 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/simple-card.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Simple Audio Card Driver Device Tree Bindings
+
+maintainers:
+ - Kuninori Morimoto <[email protected]>
+
+definitions:
+
+ frame-master:
+ description: Indicates dai-link frame master.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/phandle-array
+ - maxItems: 1
+
+ bitclock-master:
+ description: Indicates dai-link bit clock master
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/phandle-array
+ - maxItems: 1
+
+ frame-inversion:
+ description: dai-link uses frame clock inversion
+ $ref: /schemas/types.yaml#/definitions/flag
+
+ bitclock-inversion:
+ 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
+ mclk-fs, the clock will be set to the calculated mclk frequency
+ when the stream starts.
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ system-clock-direction-out:
+ description: |
+ specifies clock direction as 'out' on initialization.
+ It is useful for some aCPUs with fixed clocks.
+ $ref: /schemas/types.yaml#/definitions/flag
+
+ mclk-fs:
+ description: |
+ Multiplication factor between stream rate and codec mclk.
+ When defined, mclk-fs property defined in dai-link sub nodes are ignored.
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ aux-devs:
+ description: |
+ List of phandles pointing to auxiliary devices, such
+ as amplifiers, to be added to the sound card.
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+
+ convert-rate:
+ description: CPU to Codec rate convert.
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ convert-channels:
+ description: CPU to Codec rate channels.
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ prefix:
+ description: "device name prefix"
+ $ref: /schemas/types.yaml#/definitions/string
+
+ label:
+ maxItems: 1
+
+ routing:
+ 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.
+ $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+
+ widgets:
+ description: User specified audio sound widgets.
+ $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+
+ pin-switches:
+ description: the widget names for which pin switches must be created.
+ $ref: /schemas/types.yaml#/definitions/string-array
+
+ format:
+ description: audio format.
+ items:
+ enum:
+ - i2s
+ - right_j
+ - left_j
+ - dsp_a
+ - dsp_b
+ - ac97
+ - pdm
+ - msb
+ - lsb
+
+ dai:
+ type: object
+ properties:
+ sound-dai:
+ maxItems: 1
+
+ # common properties
+ mclk-fs:
+ $ref: "#/definitions/mclk-fs"
+ prefix:
+ $ref: "#/definitions/prefix"
+ frame-inversion:
+ $ref: "#/definitions/frame-inversion"
+ bitclock-inversion:
+ $ref: "#/definitions/bitclock-inversion"
+ frame-master:
+ $ref: /schemas/types.yaml#/definitions/flag
+ 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:
+ $ref: "#/definitions/system-clock-frequency"
+ system-clock-direction-out:
+ $ref: "#/definitions/system-clock-direction-out"
+ required:
+ - sound-dai
+
+properties:
+ compatible:
+ contains:
+ enum:
+ - simple-audio-card
+ - simple-scu-audio-card
+
+ "#address-cells":
+ const: 1
+ "#size-cells":
+ const: 0
+
+ label:
+ $ref: "#/definitions/label"
+
+ simple-audio-card,name:
+ description: User specified audio sound card name.
+ $ref: /schemas/types.yaml#/definitions/string
+
+# use patternProperties to avoid naming "xxx,yyy" issue
+patternProperties:
+ "^simple-audio-card,widgets$":
+ $ref: "#/definitions/widgets"
+ "^simple-audio-card,routing$":
+ $ref: "#/definitions/routing"
+ "^simple-audio-card,cpu(@[0-9a-f]+)?":
+ $ref: "#/definitions/dai"
+ "^simple-audio-card,codec(@[0-9a-f]+)?":
+ $ref: "#/definitions/dai"
+
+ # common properties
+ "^simple-audio-card,frame-master$":
+ $ref: "#/definitions/frame-master"
+ "^simple-audio-card,bitclock-master$":
+ $ref: "#/definitions/bitclock-master"
+ "^simple-audio-card,frame-inversion$":
+ $ref: "#/definitions/frame-inversion"
+ "^simple-audio-card,bitclock-inversion$":
+ $ref: "#/definitions/bitclock-inversion"
+ "^simple-audio-card,format$":
+ $ref: "#/definitions/format"
+ "^simple-audio-card,mclk-fs$":
+ $ref: "#/definitions/mclk-fs"
+ "^simple-audio-card,aux-devs$":
+ $ref: "#/definitions/aux-devs"
+ "^simple-audio-card,convert-rate$":
+ $ref: "#/definitions/convert-rate"
+ "^simple-audio-card,convert-channels$":
+ $ref: "#/definitions/convert-channels"
+ "^simple-audio-card,prefix$":
+ $ref: "#/definitions/prefix"
+ "^simple-audio-card,pin-switches$":
+ $ref: "#/definitions/pin-switches"
+ "^simple-audio-card,hp-det-gpio$":
+ maxItems: 1
+ "^simple-audio-card,mic-det-gpio$":
+ maxItems: 1
+
+ "^simple-audio-card,dai-link(@[0-9a-f]+)?$":
+ description: |
+ Container for dai-link level properties and the CPU and CODEC sub-nodes.
+ This container may be omitted when the card has only one DAI link.
+ type: object
+ properties:
+ reg:
+ maxItems: 1
+
+ # common properties
+ frame-master:
+ $ref: "#/definitions/frame-master"
+ bitclock-master:
+ $ref: "#/definitions/bitclock-master"
+ frame-inversion:
+ $ref: "#/definitions/frame-inversion"
+ bitclock-inversion:
+ $ref: "#/definitions/bitclock-inversion"
+ format:
+ $ref: "#/definitions/format"
+ mclk-fs:
+ $ref: "#/definitions/mclk-fs"
+ aux-devs:
+ $ref: "#/definitions/aux-devs"
+ convert-rate:
+ $ref: "#/definitions/convert-rate"
+ convert-channels:
+ $ref: "#/definitions/convert-channels"
+ prefix:
+ $ref: "#/definitions/prefix"
+ pin-switches:
+ $ref: "#/definitions/pin-switches"
+ hp-det-gpio:
+ maxItems: 1
+ mic-det-gpio:
+ maxItems: 1
+
+ patternProperties:
+ "^cpu(@[0-9a-f]+)?":
+ $ref: "#/definitions/dai"
+ "^codec(@[0-9a-f]+)?":
+ $ref: "#/definitions/dai"
+ additionalProperties: false
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+#--------------------
+# single DAI link
+#--------------------
+ - |
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "VF610-Tower-Sound-Card";
+ simple-audio-card,format = "left_j";
+ simple-audio-card,bitclock-master = <&dailink0_master>;
+ simple-audio-card,frame-master = <&dailink0_master>;
+ simple-audio-card,widgets =
+ "Microphone", "Microphone Jack",
+ "Headphone", "Headphone Jack",
+ "Speaker", "External Speaker";
+ simple-audio-card,routing =
+ "MIC_IN", "Microphone Jack",
+ "Headphone Jack", "HP_OUT",
+ "External Speaker", "LINE_OUT";
+
+ simple-audio-card,cpu {
+ sound-dai = <&sh_fsi2 0>;
+ };
+
+ dailink0_master: simple-audio-card,codec {
+ sound-dai = <&ak4648>;
+ clocks = <&osc>;
+ };
+ };
+
+#--------------------
+# Multi DAI links
+#--------------------
+ - |
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "Cubox Audio";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ simple-audio-card,dai-link@0 { /* I2S - HDMI */
+ reg = <0>;
+ format = "i2s";
+ cpu {
+ sound-dai = <&audio0>;
+ };
+ codec {
+ sound-dai = <&tda998x0>;
+ };
+ };
+
+ simple-audio-card,dai-link@1 { /* S/PDIF - HDMI */
+ reg = <1>;
+ cpu {
+ sound-dai = <&audio1>;
+ };
+ codec {
+ sound-dai = <&tda998x1>;
+ };
+ };
+
+ simple-audio-card,dai-link@2 { /* S/PDIF - S/PDIF */
+ reg = <2>;
+ cpu {
+ sound-dai = <&audio2>;
+ };
+ codec {
+ sound-dai = <&spdif_codec>;
+ };
+ };
+ };
+
+#--------------------
+# route audio from IMX6 SSI2 through TLV320DAC3100 codec
+# through TPA6130A2 amplifier to headphones:
+#--------------------
+ - |
+ sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,widgets =
+ "Headphone", "Headphone Jack";
+ simple-audio-card,routing =
+ "Headphone Jack", "HPLEFT",
+ "Headphone Jack", "HPRIGHT",
+ "LEFTIN", "HPL",
+ "RIGHTIN", "HPR";
+ simple-audio-card,aux-devs = <&amp>;
+ simple-audio-card,cpu {
+ sound-dai = <&ssi2>;
+ };
+ simple-audio-card,codec {
+ sound-dai = <&codec>;
+ clocks = <&clocks>;
+ };
+ };
+
+#--------------------
+# Sampling Rate Conversion
+#--------------------
+ - |
+ sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,name = "rsnd-ak4643";
+ simple-audio-card,format = "left_j";
+ simple-audio-card,bitclock-master = <&sndcodec>;
+ simple-audio-card,frame-master = <&sndcodec>;
+
+ simple-audio-card,convert-rate = <48000>;
+
+ simple-audio-card,prefix = "ak4642";
+ simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
+ "DAI0 Capture", "ak4642 Capture";
+
+ sndcpu: simple-audio-card,cpu {
+ sound-dai = <&rcar_sound>;
+ };
+
+ sndcodec: simple-audio-card,codec {
+ sound-dai = <&ak4643>;
+ system-clock-frequency = <11289600>;
+ };
+ };
+
+#--------------------
+# 2 CPU 1 Codec (Mixing)
+#--------------------
+ - |
+ sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,name = "rsnd-ak4643";
+ simple-audio-card,format = "left_j";
+ simple-audio-card,bitclock-master = <&dpcmcpu>;
+ simple-audio-card,frame-master = <&dpcmcpu>;
+
+ simple-audio-card,convert-rate = <48000>;
+ simple-audio-card,convert-channels = <2>;
+
+ simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
+ "ak4642 Playback", "DAI1 Playback";
+
+ dpcmcpu: simple-audio-card,cpu@0 {
+ sound-dai = <&rcar_sound 0>;
+ };
+
+ simple-audio-card,cpu@1 {
+ sound-dai = <&rcar_sound 1>;
+ };
+
+ simple-audio-card,codec {
+ prefix = "ak4642";
+ sound-dai = <&ak4643>;
+ clocks = <&audio_clock>;
+ };
+ };
+
+#--------------------
+# Multi DAI links with DPCM:
+#
+# CPU0 ------ ak4613
+# CPU1 ------ PCM3168A-p /* DPCM 1ch/2ch */
+# CPU2 --/ /* DPCM 3ch/4ch */
+# CPU3 --/ /* DPCM 5ch/6ch */
+# CPU4 --/ /* DPCM 7ch/8ch */
+# CPU5 ------ PCM3168A-c
+#--------------------
+ - |
+ sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,routing =
+ "pcm3168a Playback", "DAI1 Playback",
+ "pcm3168a Playback", "DAI2 Playback",
+ "pcm3168a Playback", "DAI3 Playback",
+ "pcm3168a Playback", "DAI4 Playback";
+
+ simple-audio-card,dai-link@0 {
+ format = "left_j";
+ bitclock-master = <&sndcpu0>;
+ frame-master = <&sndcpu0>;
+
+ sndcpu0: cpu {
+ sound-dai = <&rcar_sound 0>;
+ };
+ codec {
+ sound-dai = <&ak4613>;
+ };
+ };
+
+ simple-audio-card,dai-link@1 {
+ format = "i2s";
+ bitclock-master = <&sndcpu1>;
+ frame-master = <&sndcpu1>;
+
+ convert-channels = <8>; /* TDM Split */
+
+ sndcpu1: cpu@0 {
+ sound-dai = <&rcar_sound 1>;
+ };
+ cpu@1 {
+ sound-dai = <&rcar_sound 2>;
+ };
+ cpu@2 {
+ sound-dai = <&rcar_sound 3>;
+ };
+ cpu@3 {
+ sound-dai = <&rcar_sound 4>;
+ };
+ codec {
+ mclk-fs = <512>;
+ prefix = "pcm3168a";
+ dai-tdm-slot-num = <8>;
+ sound-dai = <&pcm3168a 0>;
+ };
+ };
+
+ simple-audio-card,dai-link@2 {
+ format = "i2s";
+ bitclock-master = <&sndcpu2>;
+ frame-master = <&sndcpu2>;
+
+ sndcpu2: cpu {
+ sound-dai = <&rcar_sound 5>;
+ };
+ codec {
+ mclk-fs = <512>;
+ prefix = "pcm3168a";
+ sound-dai = <&pcm3168a 1>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/tlv320adcx140.yaml b/Documentation/devicetree/bindings/sound/tlv320adcx140.yaml
index ab2268c0ee67..daa6cc0e031b 100644
--- a/Documentation/devicetree/bindings/sound/tlv320adcx140.yaml
+++ b/Documentation/devicetree/bindings/sound/tlv320adcx140.yaml
@@ -63,6 +63,29 @@ properties:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2]
+ ti,pdm-edge-select:
+ description: |
+ Defines the PDMCLK sampling edge configuration for the PDM inputs. This
+ array is defined as <PDMIN1 PDMIN2 PDMIN3 PDMIN4>.
+
+ 0 - (default) Odd channel is latched on the negative edge and even
+ channel is latched on the the positive edge.
+ 1 - Odd channel is latched on the positive edge and even channel is
+ latched on the the negative edge.
+
+ PDMIN1 - PDMCLK latching edge used for channel 1 and 2 data
+ PDMIN2 - PDMCLK latching edge used for channel 3 and 4 data
+ PDMIN3 - PDMCLK latching edge used for channel 5 and 6 data
+ PDMIN4 - PDMCLK latching edge used for channel 7 and 8 data
+
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32-array
+ - minItems: 1
+ maxItems: 4
+ items:
+ maximum: 1
+ default: [0, 0, 0, 0]
+
required:
- compatible
- reg
@@ -77,6 +100,7 @@ examples:
compatible = "ti,tlv320adc5140";
reg = <0x4c>;
ti,mic-bias-source = <6>;
+ ti,pdm-edge-select = <0 1 0 1>;
reset-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
};
};
diff --git a/Documentation/devicetree/bindings/sound/wm8994.txt b/Documentation/devicetree/bindings/sound/wm8994.txt
index 68cccc4653ba..367b58ce1bb9 100644
--- a/Documentation/devicetree/bindings/sound/wm8994.txt
+++ b/Documentation/devicetree/bindings/sound/wm8994.txt
@@ -14,9 +14,15 @@ Required properties:
- #gpio-cells : Must be 2. The first cell is the pin number and the
second cell is used to specify optional parameters (currently unused).
- - AVDD2-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply, CPVDD-supply,
- SPKVDD1-supply, SPKVDD2-supply : power supplies for the device, as covered
- in Documentation/devicetree/bindings/regulator/regulator.txt
+ - power supplies for the device, as covered in
+ Documentation/devicetree/bindings/regulator/regulator.txt, depending
+ on compatible:
+ - for wlf,wm1811 and wlf,wm8958:
+ AVDD1-supply, AVDD2-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply,
+ DCVDD-supply, CPVDD-supply, SPKVDD1-supply, SPKVDD2-supply
+ - for wlf,wm8994:
+ AVDD1-supply, AVDD2-supply, DBVDD-supply, DCVDD-supply, CPVDD-supply,
+ SPKVDD1-supply, SPKVDD2-supply
Optional properties:
@@ -73,11 +79,11 @@ wm8994: codec@1a {
lineout1-se;
+ AVDD1-supply = <&regulator>;
AVDD2-supply = <&regulator>;
CPVDD-supply = <&regulator>;
- DBVDD1-supply = <&regulator>;
- DBVDD2-supply = <&regulator>;
- DBVDD3-supply = <&regulator>;
+ DBVDD-supply = <&regulator>;
+ DCVDD-supply = <&regulator>;
SPKVDD1-supply = <&regulator>;
SPKVDD2-supply = <&regulator>;
};
diff --git a/Documentation/devicetree/bindings/sound/zl38060.yaml b/Documentation/devicetree/bindings/sound/zl38060.yaml
new file mode 100644
index 000000000000..338e2a13c775
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/zl38060.yaml
@@ -0,0 +1,69 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/zl38060.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ZL38060 Connected Home Audio Processor from Microsemi.
+
+description: |
+ The ZL38060 is a "Connected Home Audio Processor" from Microsemi,
+ which consists of a Digital Signal Processor (DSP), several Digital
+ Audio Interfaces (DAIs), analog outputs, and a block of 14 GPIOs.
+
+maintainers:
+ - Jaroslav Kysela <[email protected]>
+ - Takashi Iwai <[email protected]>
+
+properties:
+ compatible:
+ const: mscc,zl38060
+
+ reg:
+ description:
+ SPI device address.
+ maxItems: 1
+
+ spi-max-frequency:
+ maximum: 24000000
+
+ reset-gpios:
+ description:
+ A GPIO line handling reset of the chip. As the line is active low,
+ it should be marked GPIO_ACTIVE_LOW (see ../gpio/gpio.txt)
+ maxItems: 1
+
+ '#gpio-cells':
+ const: 2
+
+ gpio-controller: true
+
+ '#sound-dai-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - '#gpio-cells'
+ - gpio-controller
+ - '#sound-dai-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ spi0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ codec: zl38060@0 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ #sound-dai-cells = <0>;
+ compatible = "mscc,zl38060";
+ reg = <0>;
+ spi-max-frequency = <12000000>;
+ reset-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
+ };
+ };
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 3c83e76c6bf9..ed8d576bf5dc 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -669,11 +669,11 @@ static int sdw_stream_setup(struct snd_pcm_substream *substream,
/* Set stream pointer on all CODEC DAIs */
for (i = 0; i < rtd->num_codecs; i++) {
- ret = snd_soc_dai_set_sdw_stream(rtd->codec_dais[i], sdw_stream,
+ ret = snd_soc_dai_set_sdw_stream(asoc_rtd_to_codec(rtd, i), sdw_stream,
substream->stream);
if (ret < 0) {
dev_err(dai->dev, "failed to set stream pointer on codec dai %s",
- rtd->codec_dais[i]->name);
+ asoc_rtd_to_codec(rtd, i)->name);
goto release_stream;
}
}
diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h
index 392e953d561e..d2e9e3b4d7ea 100644
--- a/include/sound/soc-acpi.h
+++ b/include/sound/soc-acpi.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0-only
*
* Copyright (C) 2013-15, Intel Corporation. All rights reserved.
*/
diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h
index 154d02fbbfed..864983b09846 100644
--- a/include/sound/soc-component.h
+++ b/include/sound/soc-component.h
@@ -25,6 +25,44 @@
order++)
/* component interface */
+struct snd_compress_ops {
+ int (*open)(struct snd_soc_component *component,
+ struct snd_compr_stream *stream);
+ int (*free)(struct snd_soc_component *component,
+ struct snd_compr_stream *stream);
+ int (*set_params)(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_params *params);
+ int (*get_params)(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_codec *params);
+ int (*set_metadata)(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_metadata *metadata);
+ int (*get_metadata)(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_metadata *metadata);
+ int (*trigger)(struct snd_soc_component *component,
+ struct snd_compr_stream *stream, int cmd);
+ int (*pointer)(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_tstamp *tstamp);
+ int (*copy)(struct snd_soc_component *component,
+ struct snd_compr_stream *stream, char __user *buf,
+ size_t count);
+ int (*mmap)(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct vm_area_struct *vma);
+ int (*ack)(struct snd_soc_component *component,
+ struct snd_compr_stream *stream, size_t bytes);
+ int (*get_caps)(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_caps *caps);
+ int (*get_codec_caps)(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_codec_caps *codec);
+};
+
struct snd_soc_component_driver {
const char *name;
@@ -108,7 +146,7 @@ struct snd_soc_component_driver {
struct snd_pcm_substream *substream,
struct vm_area_struct *vma);
- const struct snd_compr_ops *compr_ops;
+ const struct snd_compress_ops *compress_ops;
/* probe ordering - for components with runtime dependencies */
int probe_order;
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index b33abe93b905..2a0a5af1c1ae 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -154,22 +154,47 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
struct snd_pcm_substream *substream);
void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
struct snd_pcm_substream *substream);
-int snd_soc_dai_prepare(struct snd_soc_dai *dai,
- struct snd_pcm_substream *substream);
-int snd_soc_dai_trigger(struct snd_soc_dai *dai,
- struct snd_pcm_substream *substream, int cmd);
-int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai,
- struct snd_pcm_substream *substream, int cmd);
snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
struct snd_pcm_substream *substream);
void snd_soc_dai_suspend(struct snd_soc_dai *dai);
void snd_soc_dai_resume(struct snd_soc_dai *dai);
-int snd_soc_dai_probe(struct snd_soc_dai *dai);
-int snd_soc_dai_remove(struct snd_soc_dai *dai);
int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
struct snd_soc_pcm_runtime *rtd, int num);
bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream);
+int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order);
+int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order);
+int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd);
+int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream);
+int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, int cmd);
+int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
+ int cmd);
+
+int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream);
+void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream);
+int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream, int cmd);
+int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_params *params);
+int snd_soc_dai_compr_get_params(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream,
+ struct snd_codec *params);
+int snd_soc_dai_compr_ack(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream,
+ size_t bytes);
+int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_tstamp *tstamp);
+int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_metadata *metadata);
+int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_metadata *metadata);
+
struct snd_soc_dai_ops {
/*
* DAI clocking configuration, all optional.
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 08495f8d86dc..cc3dcb815282 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -689,7 +689,7 @@ struct snd_soc_dapm_context {
/* A list of widgets associated with an object, typically a snd_kcontrol */
struct snd_soc_dapm_widget_list {
int num_widgets;
- struct snd_soc_dapm_widget *widgets[0];
+ struct snd_soc_dapm_widget *widgets[];
};
#define for_each_dapm_widgets(list, i, widget) \
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 946f88a6c63d..69a82487fa9b 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1146,14 +1146,16 @@ struct snd_soc_pcm_runtime {
/* runtime devices */
struct snd_pcm *pcm;
struct snd_compr *compr;
- struct snd_soc_dai *codec_dai;
- struct snd_soc_dai *cpu_dai;
- struct snd_soc_dai **dais;
- struct snd_soc_dai **codec_dais;
+ /*
+ * dais = cpu_dai + codec_dai
+ * see
+ * soc_new_pcm_runtime()
+ * asoc_rtd_to_cpu()
+ * asoc_rtd_to_codec()
+ */
+ struct snd_soc_dai **dais;
unsigned int num_codecs;
-
- struct snd_soc_dai **cpu_dais;
unsigned int num_cpus;
struct delayed_work delayed_work;
@@ -1170,28 +1172,28 @@ struct snd_soc_pcm_runtime {
unsigned int fe_compr:1; /* for Dynamic PCM */
int num_components;
- struct snd_soc_component *components[0]; /* CPU/Codec/Platform */
+ struct snd_soc_component *components[]; /* CPU/Codec/Platform */
};
/* see soc_new_pcm_runtime() */
#define asoc_rtd_to_cpu(rtd, n) (rtd)->dais[n]
#define asoc_rtd_to_codec(rtd, n) (rtd)->dais[n + (rtd)->num_cpus]
#define for_each_rtd_components(rtd, i, component) \
- for ((i) = 0; \
+ for ((i) = 0, component = NULL; \
((i) < rtd->num_components) && ((component) = rtd->components[i]);\
(i)++)
#define for_each_rtd_cpu_dais(rtd, i, dai) \
for ((i) = 0; \
- ((i) < rtd->num_cpus) && ((dai) = rtd->cpu_dais[i]); \
+ ((i) < rtd->num_cpus) && ((dai) = asoc_rtd_to_cpu(rtd, i)); \
(i)++)
#define for_each_rtd_cpu_dais_rollback(rtd, i, dai) \
- for (; (--(i) >= 0) && ((dai) = rtd->cpu_dais[i]);)
+ for (; (--(i) >= 0) && ((dai) = asoc_rtd_to_cpu(rtd, i));)
#define for_each_rtd_codec_dais(rtd, i, dai) \
for ((i) = 0; \
- ((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \
+ ((i) < rtd->num_codecs) && ((dai) = asoc_rtd_to_codec(rtd, i)); \
(i)++)
#define for_each_rtd_codec_dais_rollback(rtd, i, dai) \
- for (; (--(i) >= 0) && ((dai) = rtd->codec_dais[i]);)
+ for (; (--(i) >= 0) && ((dai) = asoc_rtd_to_codec(rtd, i));)
#define for_each_rtd_dais(rtd, i, dai) \
for ((i) = 0; \
((i) < (rtd)->num_cpus + (rtd)->num_codecs) && \
@@ -1268,13 +1270,13 @@ static inline void *snd_soc_card_get_drvdata(struct snd_soc_card *card)
static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
{
if (mc->reg == mc->rreg && mc->shift == mc->rshift)
- return 0;
+ return false;
/*
* mc->reg == mc->rreg && mc->shift != mc->rshift, or
* mc->reg != mc->rreg means that the control is
* stereo (bits in one register or in two registers)
*/
- return 1;
+ return true;
}
static inline unsigned int snd_soc_enum_val_to_item(struct soc_enum *e,
@@ -1384,8 +1386,8 @@ struct snd_soc_dai *snd_soc_card_get_codec_dai(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd;
list_for_each_entry(rtd, &card->rtd_list, list) {
- if (!strcmp(rtd->codec_dai->name, dai_name))
- return rtd->codec_dai;
+ if (!strcmp(asoc_rtd_to_codec(rtd, 0)->name, dai_name))
+ return asoc_rtd_to_codec(rtd, 0);
}
return NULL;
diff --git a/include/sound/sof.h b/include/sound/sof.h
index a0cbca021230..f3e716c8ce1c 100644
--- a/include/sound/sof.h
+++ b/include/sound/sof.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -27,6 +27,9 @@ struct snd_sof_pdata {
struct device *dev;
+ /* indicate how many first bytes shouldn't be loaded into DSP memory. */
+ size_t fw_offset;
+
/*
* notification callback used if the hardware initialization
* can take time or is handled in a workqueue. This callback
diff --git a/include/sound/sof/channel_map.h b/include/sound/sof/channel_map.h
index 21044eb5f377..fd3a30fcf756 100644
--- a/include/sound/sof/channel_map.h
+++ b/include/sound/sof/channel_map.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
diff --git a/include/sound/sof/control.h b/include/sound/sof/control.h
index 6080ea0facd7..7379a33d7247 100644
--- a/include/sound/sof/control.h
+++ b/include/sound/sof/control.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
diff --git a/include/sound/sof/dai-imx.h b/include/sound/sof/dai-imx.h
index ff9088dcc6f2..ca8325353d41 100644
--- a/include/sound/sof/dai-imx.h
+++ b/include/sound/sof/dai-imx.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* Copyright 2019 NXP
*
diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h
index 04e48227f542..136adf6686e2 100644
--- a/include/sound/sof/dai-intel.h
+++ b/include/sound/sof/dai-intel.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -49,6 +49,9 @@
/* bclk idle */
#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_IDLE_HIGH BIT(5)
+/* DMIC max. four controllers for eight microphone channels */
+#define SOF_DAI_INTEL_DMIC_NUM_CTRL 4
+
/* SSP Configuration Request - SOF_IPC_DAI_SSP_CONFIG */
struct sof_ipc_dai_ssp_params {
struct sof_ipc_hdr hdr;
@@ -85,15 +88,19 @@ struct sof_ipc_dai_ssp_params {
struct sof_ipc_dai_hda_params {
struct sof_ipc_hdr hdr;
uint32_t link_dma_ch;
+ uint32_t rate;
+ uint32_t channels;
} __packed;
/* ALH Configuration Request - SOF_IPC_DAI_ALH_CONFIG */
struct sof_ipc_dai_alh_params {
struct sof_ipc_hdr hdr;
uint32_t stream_id;
+ uint32_t rate;
+ uint32_t channels;
/* reserved for future use */
- uint32_t reserved[15];
+ uint32_t reserved[13];
} __packed;
/* DMIC Configuration Request - SOF_IPC_DAI_DMIC_CONFIG */
@@ -135,7 +142,7 @@ struct sof_ipc_dai_dmic_pdm_ctrl {
* version number used in configuration data is checked vs. version used by
* device driver src/drivers/dmic.c need to match. It is incremented from
* initial value 1 if updates done for the to driver would alter the operation
- * of the microhone.
+ * of the microphone.
*
* Note: The microphone clock (pdmclk_min, pdmclk_max, duty_min, duty_max)
* parameters need to be set as defined in microphone data sheet. E.g. clock
@@ -170,12 +177,13 @@ struct sof_ipc_dai_dmic_params {
uint32_t fifo_fs; /**< FIFO sample rate in Hz (8000..96000) */
uint32_t reserved_1; /**< Reserved */
uint16_t fifo_bits; /**< FIFO word length (16 or 32) */
- uint16_t reserved_2; /**< Reserved */
+ uint16_t fifo_bits_b; /**< Deprecated since firmware ABI 3.0.1 */
uint16_t duty_min; /**< Min. mic clock duty cycle in % (20..80) */
uint16_t duty_max; /**< Max. mic clock duty cycle in % (min..80) */
- uint32_t num_pdm_active; /**< Number of active pdm controllers */
+ uint32_t num_pdm_active; /**< Number of active pdm controllers. */
+ /**< Range is 1..SOF_DAI_INTEL_DMIC_NUM_CTRL */
uint32_t wake_up_time; /**< Time from clock start to data (us) */
uint32_t min_clock_on_time; /**< Min. time that clk is kept on (us) */
@@ -184,8 +192,8 @@ struct sof_ipc_dai_dmic_params {
/* reserved for future use */
uint32_t reserved[5];
- /**< variable number of pdm controller config */
- struct sof_ipc_dai_dmic_pdm_ctrl pdm[0];
+ /**< PDM controllers configuration */
+ struct sof_ipc_dai_dmic_pdm_ctrl pdm[SOF_DAI_INTEL_DMIC_NUM_CTRL];
} __packed;
#endif
diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h
index 2565edd336f1..34f135adf8ec 100644
--- a/include/sound/sof/dai.h
+++ b/include/sound/sof/dai.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h
index b79479575cc8..2d35997ace40 100644
--- a/include/sound/sof/header.h
+++ b/include/sound/sof/header.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
diff --git a/include/sound/sof/info.h b/include/sound/sof/info.h
index 438a11fcf272..5a55ba8b7e56 100644
--- a/include/sound/sof/info.h
+++ b/include/sound/sof/info.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -31,6 +31,8 @@ enum sof_ipc_ext_data {
SOF_IPC_EXT_UNUSED = 0,
SOF_IPC_EXT_WINDOW = 1,
SOF_IPC_EXT_CC_INFO = 2,
+ SOF_IPC_EXT_PROBE_INFO = 3,
+ SOF_IPC_EXT_USER_ABI_INFO = 4,
};
/* FW version - SOF_IPC_GLB_VERSION */
@@ -109,9 +111,27 @@ struct sof_ipc_cc_version {
/* reserved for future use */
uint32_t reserved[4];
- char name[16]; /* null terminated compiler name */
- char optim[4]; /* null terminated compiler -O flag value */
- char desc[]; /* null terminated compiler description */
+ uint8_t name[16]; /* null terminated compiler name */
+ uint8_t optim[4]; /* null terminated compiler -O flag value */
+ uint8_t desc[32]; /* null terminated compiler description */
} __packed;
+/* extended data: Probe setup */
+struct sof_ipc_probe_support {
+ struct sof_ipc_ext_data_hdr ext_hdr;
+
+ uint32_t probe_points_max;
+ uint32_t injection_dmas_max;
+
+ /* reserved for future use */
+ uint32_t reserved[2];
+} __packed;
+
+/* extended data: user abi version(s) */
+struct sof_ipc_user_abi_version {
+ struct sof_ipc_ext_data_hdr ext_hdr;
+
+ uint32_t abi_dbg_version;
+} __packed;
+
#endif
diff --git a/include/sound/sof/pm.h b/include/sound/sof/pm.h
index 3cf2e0f39d94..366aa6ec442b 100644
--- a/include/sound/sof/pm.h
+++ b/include/sound/sof/pm.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
diff --git a/include/sound/sof/stream.h b/include/sound/sof/stream.h
index 7facefb541b3..58a0d49977d6 100644
--- a/include/sound/sof/stream.h
+++ b/include/sound/sof/stream.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h
index 402e0250c508..872de52b3144 100644
--- a/include/sound/sof/topology.h
+++ b/include/sound/sof/topology.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -37,6 +37,7 @@ enum sof_comp_type {
SOF_COMP_SELECTOR, /**< channel selector component */
SOF_COMP_DEMUX,
SOF_COMP_ASRC, /**< Asynchronous sample rate converter */
+ SOF_COMP_DCBLOCK,
/* keep FILEREAD/FILEWRITE as the last ones */
SOF_COMP_FILEREAD = 10000, /**< host test based file IO */
SOF_COMP_FILEWRITE = 10001, /**< host test based file IO */
@@ -75,11 +76,23 @@ struct sof_ipc_comp {
#define SOF_MEM_CAPS_CACHE (1 << 6) /**< cacheable */
#define SOF_MEM_CAPS_EXEC (1 << 7) /**< executable */
+/*
+ * overrun will cause ring buffer overwrite, instead of XRUN.
+ */
+#define SOF_BUF_OVERRUN_PERMITTED BIT(0)
+
+/*
+ * underrun will cause readback of 0s, instead of XRUN.
+ */
+#define SOF_BUF_UNDERRUN_PERMITTED BIT(1)
+
/* create new component buffer - SOF_IPC_TPLG_BUFFER_NEW */
struct sof_ipc_buffer {
struct sof_ipc_comp comp;
uint32_t size; /**< buffer size in bytes */
uint32_t caps; /**< SOF_MEM_CAPS_ */
+ uint32_t flags; /**< SOF_BUF_ flags defined above */
+ uint32_t reserved; /**< reserved for future use */
} __packed;
/* generic component config data - must always be after struct sof_ipc_comp */
@@ -206,6 +219,7 @@ enum sof_ipc_process_type {
SOF_PROCESS_CHAN_SELECTOR, /**< Channel Selector */
SOF_PROCESS_MUX,
SOF_PROCESS_DEMUX,
+ SOF_PROCESS_DCBLOCK,
};
/* generic "effect", "codec" or proprietary processing component */
@@ -218,7 +232,7 @@ struct sof_ipc_comp_process {
/* reserved for future use */
uint32_t reserved[7];
- unsigned char data[0];
+ uint8_t data[0];
} __packed;
/* frees components, buffers and pipelines
diff --git a/include/sound/sof/trace.h b/include/sound/sof/trace.h
index fda6e8f6ead4..c31a94a13ce0 100644
--- a/include/sound/sof/trace.h
+++ b/include/sound/sof/trace.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -72,7 +72,7 @@ struct sof_ipc_dma_trace_posn {
struct sof_ipc_panic_info {
struct sof_ipc_hdr hdr;
uint32_t code; /* SOF_IPC_PANIC_ */
- char filename[SOF_TRACE_FILENAME_SIZE];
+ uint8_t filename[SOF_TRACE_FILENAME_SIZE];
uint32_t linenum;
} __packed;
diff --git a/include/sound/sof/xtensa.h b/include/sound/sof/xtensa.h
index dd53d36b34e1..87a07e520415 100644
--- a/include/sound/sof/xtensa.h
+++ b/include/sound/sof/xtensa.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
diff --git a/include/uapi/sound/skl-tplg-interface.h b/include/uapi/sound/skl-tplg-interface.h
index 9eee32f5e407..a93c0decfdd5 100644
--- a/include/uapi/sound/skl-tplg-interface.h
+++ b/include/uapi/sound/skl-tplg-interface.h
@@ -18,6 +18,8 @@
*/
#define SKL_CONTROL_TYPE_BYTE_TLV 0x100
#define SKL_CONTROL_TYPE_MIC_SELECT 0x102
+#define SKL_CONTROL_TYPE_MULTI_IO_SELECT 0x103
+#define SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC 0x104
#define HDA_SST_CFG_MAX 900 /* size of copier cfg*/
#define MAX_IN_QUEUE 8
diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h
index 5995b79d6df1..d54be303090f 100644
--- a/include/uapi/sound/sof/abi.h
+++ b/include/uapi/sound/sof/abi.h
@@ -26,7 +26,7 @@
/* SOF ABI version major, minor and patch numbers */
#define SOF_ABI_MAJOR 3
-#define SOF_ABI_MINOR 13
+#define SOF_ABI_MINOR 16
#define SOF_ABI_PATCH 0
/* SOF ABI version number. Format within 32bit word is MMmmmppp */
diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h
index 2a25cd8da503..5941e2eb1588 100644
--- a/include/uapi/sound/sof/tokens.h
+++ b/include/uapi/sound/sof/tokens.h
@@ -126,4 +126,12 @@
#define SOF_TKN_MUTE_LED_USE 1300
#define SOF_TKN_MUTE_LED_DIRECTION 1301
+/* ALH */
+#define SOF_TKN_INTEL_ALH_RATE 1400
+#define SOF_TKN_INTEL_ALH_CH 1401
+
+/* HDA */
+#define SOF_TKN_INTEL_HDA_RATE 1500
+#define SOF_TKN_INTEL_HDA_CH 1501
+
#endif
diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c
index 99a23fe7fab9..73d4f8c4f4c7 100644
--- a/sound/hda/intel-nhlt.c
+++ b/sound/hda/intel-nhlt.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2015-2019 Intel Corporation
#include <linux/acpi.h>
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index bb287a916dae..403baca89452 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -4156,6 +4156,7 @@ HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi),
HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI", patch_i915_icl_hdmi),
HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI", patch_i915_tgl_hdmi),
HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi),
+HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi),
HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi),
HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi),
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index e60e0b6a689c..44b8c4cde4f3 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -272,6 +272,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_WM9712
imply SND_SOC_WM9713
imply SND_SOC_WSA881X
+ imply SND_SOC_ZL38060
help
Normally ASoC codec drivers are only built if a machine driver which
uses them is also built since they are only usable with a machine
@@ -717,7 +718,7 @@ config SND_SOC_L3
config SND_SOC_DA7210
tristate
- depends on I2C
+ depends on SND_SOC_I2C_AND_SPI
config SND_SOC_DA7213
tristate "Dialog DA7213 CODEC"
@@ -1136,10 +1137,13 @@ config SND_SOC_RT5677_SPI
config SND_SOC_RT5682
tristate
depends on I2C || SOUNDWIRE
+ depends on SOUNDWIRE || !SOUNDWIRE
+ depends on I2C || !I2C
config SND_SOC_RT5682_SDW
tristate "Realtek RT5682 Codec - SDW"
depends on SOUNDWIRE
+ depends on I2C || !I2C
select SND_SOC_RT5682
select REGMAP_SOUNDWIRE
@@ -1569,7 +1573,7 @@ config SND_SOC_WM8978
config SND_SOC_WM8983
tristate
- depends on I2C
+ depends on SND_SOC_I2C_AND_SPI
config SND_SOC_WM8985
tristate "Wolfson Microelectronics WM8985 and WM8758 codec driver"
@@ -1620,19 +1624,19 @@ config SND_SOC_WM9090
config SND_SOC_WM9705
tristate
- depends on SND_SOC_AC97_BUS
+ depends on SND_SOC_AC97_BUS || AC97_BUS_NEW
select REGMAP_AC97
select AC97_BUS_COMPAT if AC97_BUS_NEW
config SND_SOC_WM9712
tristate
- depends on SND_SOC_AC97_BUS
+ depends on SND_SOC_AC97_BUS || AC97_BUS_NEW
select REGMAP_AC97
select AC97_BUS_COMPAT if AC97_BUS_NEW
config SND_SOC_WM9713
tristate
- depends on SND_SOC_AC97_BUS
+ depends on SND_SOC_AC97_BUS || AC97_BUS_NEW
select REGMAP_AC97
select AC97_BUS_COMPAT if AC97_BUS_NEW
@@ -1645,6 +1649,16 @@ config SND_SOC_WSA881X
This enables support for Qualcomm WSA8810/WSA8815 Class-D
Smart Speaker Amplifier.
+config SND_SOC_ZL38060
+ tristate "Microsemi ZL38060 Connected Home Audio Processor"
+ depends on SPI_MASTER
+ select GPIOLIB
+ select REGMAP
+ help
+ Support for ZL38060 Connected Home Audio Processor from Microsemi,
+ which consists of a Digital Signal Processor (DSP), several Digital
+ Audio Interfaces (DAIs), analog outputs, and a block of 14 GPIOs.
+
config SND_SOC_ZX_AUD96P22
tristate "ZTE ZX AUD96P22 CODEC"
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 03533157cda6..a603532c7af5 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -288,6 +288,7 @@ snd-soc-wm9712-objs := wm9712.o
snd-soc-wm9713-objs := wm9713.o
snd-soc-wm-hubs-objs := wm_hubs.o
snd-soc-wsa881x-objs := wsa881x.o
+snd-soc-zl38060-objs := zl38060.o
snd-soc-zx-aud96p22-objs := zx_aud96p22.o
# Amp
snd-soc-max9877-objs := max9877.o
@@ -588,6 +589,7 @@ 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_HUBS) += snd-soc-wm-hubs.o
obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o
+obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o
obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o
# Amp
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index c4414c725c1f..43b1337bac37 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -2,7 +2,7 @@
/*
* ad1980.c -- ALSA Soc AD1980 codec support
*
- * Copyright: Analog Device Inc.
+ * Copyright: Analog Devices Inc.
* Author: Roy Huang <[email protected]>
* Cliff Cai <[email protected]>
*/
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
index 10daf61f0294..b98bf19f594e 100644
--- a/sound/soc/codecs/ad73311.c
+++ b/sound/soc/codecs/ad73311.c
@@ -2,7 +2,7 @@
/*
* ad73311.c -- ALSA Soc AD73311 codec support
*
- * Copyright: Analog Device Inc.
+ * Copyright: Analog Devices Inc.
* Author: Cliff Cai <[email protected]>
*/
diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c
index d3dc42aa6825..1948bc6971f6 100644
--- a/sound/soc/codecs/cros_ec_codec.c
+++ b/sound/soc/codecs/cros_ec_codec.c
@@ -108,22 +108,23 @@ static int calculate_sha256(struct cros_ec_codec_priv *priv,
uint8_t *buf, uint32_t size, uint8_t *digest)
{
struct crypto_shash *tfm;
+ struct shash_desc *desc;
tfm = crypto_alloc_shash("sha256", CRYPTO_ALG_TYPE_SHASH, 0);
if (IS_ERR(tfm)) {
dev_err(priv->dev, "can't alloc shash\n");
return PTR_ERR(tfm);
}
-
- {
- SHASH_DESC_ON_STACK(desc, tfm);
-
- desc->tfm = tfm;
-
- crypto_shash_digest(desc, buf, size, digest);
- shash_desc_zero(desc);
+ desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
+ if (!desc) {
+ crypto_free_shash(tfm);
+ return -ENOMEM;
}
+ desc->tfm = tfm;
+ crypto_shash_digest(desc, buf, size, digest);
+ shash_desc_zero(desc);
+ kfree(desc);
crypto_free_shash(tfm);
#ifdef DEBUG
diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c
index 8d1869bf7f9c..402c6b7c7014 100644
--- a/sound/soc/codecs/cs47l15.c
+++ b/sound/soc/codecs/cs47l15.c
@@ -1229,11 +1229,10 @@ static struct snd_soc_dai_driver cs47l15_dai[] = {
},
};
-static int cs47l15_open(struct snd_compr_stream *stream)
+static int cs47l15_open(struct snd_soc_component *component,
+ struct snd_compr_stream *stream)
{
struct snd_soc_pcm_runtime *rtd = stream->private_data;
- struct snd_soc_component *component =
- snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component);
struct madera_priv *priv = &cs47l15->core;
struct madera *madera = priv->madera;
@@ -1329,7 +1328,7 @@ static unsigned int cs47l15_digital_vu[] = {
MADERA_DAC_DIGITAL_VOLUME_5R,
};
-static const struct snd_compr_ops cs47l15_compr_ops = {
+static const struct snd_compress_ops cs47l15_compress_ops = {
.open = &cs47l15_open,
.free = &wm_adsp_compr_free,
.set_params = &wm_adsp_compr_set_params,
@@ -1345,7 +1344,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l15 = {
.set_sysclk = &madera_set_sysclk,
.set_pll = &cs47l15_set_fll,
.name = DRV_NAME,
- .compr_ops = &cs47l15_compr_ops,
+ .compress_ops = &cs47l15_compress_ops,
.controls = cs47l15_snd_controls,
.num_controls = ARRAY_SIZE(cs47l15_snd_controls),
.dapm_widgets = cs47l15_dapm_widgets,
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index 6b0570f59630..f6d173d0120e 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -1068,10 +1068,10 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
},
};
-static int cs47l24_open(struct snd_compr_stream *stream)
+static int cs47l24_open(struct snd_soc_component *component,
+ struct snd_compr_stream *stream)
{
struct snd_soc_pcm_runtime *rtd = stream->private_data;
- struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct cs47l24_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->core.arizona;
int n_adsp;
@@ -1178,7 +1178,7 @@ static unsigned int cs47l24_digital_vu[] = {
ARIZONA_DAC_DIGITAL_VOLUME_4L,
};
-static struct snd_compr_ops cs47l24_compr_ops = {
+static struct snd_compress_ops cs47l24_compress_ops = {
.open = cs47l24_open,
.free = wm_adsp_compr_free,
.set_params = wm_adsp_compr_set_params,
@@ -1194,7 +1194,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l24 = {
.set_sysclk = arizona_set_sysclk,
.set_pll = cs47l24_set_fll,
.name = DRV_NAME,
- .compr_ops = &cs47l24_compr_ops,
+ .compress_ops = &cs47l24_compress_ops,
.controls = cs47l24_snd_controls,
.num_controls = ARRAY_SIZE(cs47l24_snd_controls),
.dapm_widgets = cs47l24_dapm_widgets,
diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c
index 18839807c9d1..d7538d50bbd3 100644
--- a/sound/soc/codecs/cs47l35.c
+++ b/sound/soc/codecs/cs47l35.c
@@ -1504,11 +1504,10 @@ static struct snd_soc_dai_driver cs47l35_dai[] = {
},
};
-static int cs47l35_open(struct snd_compr_stream *stream)
+static int cs47l35_open(struct snd_soc_component *component,
+ struct snd_compr_stream *stream)
{
struct snd_soc_pcm_runtime *rtd = stream->private_data;
- struct snd_soc_component *component =
- snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct cs47l35 *cs47l35 = snd_soc_component_get_drvdata(component);
struct madera_priv *priv = &cs47l35->core;
struct madera *madera = priv->madera;
@@ -1622,7 +1621,7 @@ static unsigned int cs47l35_digital_vu[] = {
MADERA_DAC_DIGITAL_VOLUME_5R,
};
-static const struct snd_compr_ops cs47l35_compr_ops = {
+static const struct snd_compress_ops cs47l35_compress_ops = {
.open = &cs47l35_open,
.free = &wm_adsp_compr_free,
.set_params = &wm_adsp_compr_set_params,
@@ -1638,7 +1637,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l35 = {
.set_sysclk = &madera_set_sysclk,
.set_pll = &cs47l35_set_fll,
.name = DRV_NAME,
- .compr_ops = &cs47l35_compr_ops,
+ .compress_ops = &cs47l35_compress_ops,
.controls = cs47l35_snd_controls,
.num_controls = ARRAY_SIZE(cs47l35_snd_controls),
.dapm_widgets = cs47l35_dapm_widgets,
diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c
index a575113207f0..9de991adad74 100644
--- a/sound/soc/codecs/cs47l85.c
+++ b/sound/soc/codecs/cs47l85.c
@@ -2447,11 +2447,10 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
},
};
-static int cs47l85_open(struct snd_compr_stream *stream)
+static int cs47l85_open(struct snd_soc_component *component,
+ struct snd_compr_stream *stream)
{
struct snd_soc_pcm_runtime *rtd = stream->private_data;
- struct snd_soc_component *component =
- snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct cs47l85 *cs47l85 = snd_soc_component_get_drvdata(component);
struct madera_priv *priv = &cs47l85->core;
struct madera *madera = priv->madera;
@@ -2566,7 +2565,7 @@ static const unsigned int cs47l85_digital_vu[] = {
MADERA_DAC_DIGITAL_VOLUME_6R,
};
-static const struct snd_compr_ops cs47l85_compr_ops = {
+static const struct snd_compress_ops cs47l85_compress_ops = {
.open = &cs47l85_open,
.free = &wm_adsp_compr_free,
.set_params = &wm_adsp_compr_set_params,
@@ -2582,7 +2581,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l85 = {
.set_sysclk = &madera_set_sysclk,
.set_pll = &cs47l85_set_fll,
.name = DRV_NAME,
- .compr_ops = &cs47l85_compr_ops,
+ .compress_ops = &cs47l85_compress_ops,
.controls = cs47l85_snd_controls,
.num_controls = ARRAY_SIZE(cs47l85_snd_controls),
.dapm_widgets = cs47l85_dapm_widgets,
diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c
index 81a1311b14e6..2715b5da0415 100644
--- a/sound/soc/codecs/cs47l90.c
+++ b/sound/soc/codecs/cs47l90.c
@@ -2358,11 +2358,10 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
},
};
-static int cs47l90_open(struct snd_compr_stream *stream)
+static int cs47l90_open(struct snd_soc_component *component,
+ struct snd_compr_stream *stream)
{
struct snd_soc_pcm_runtime *rtd = stream->private_data;
- struct snd_soc_component *component =
- snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct cs47l90 *cs47l90 = snd_soc_component_get_drvdata(component);
struct madera_priv *priv = &cs47l90->core;
struct madera *madera = priv->madera;
@@ -2473,7 +2472,7 @@ static unsigned int cs47l90_digital_vu[] = {
MADERA_DAC_DIGITAL_VOLUME_5R,
};
-static const struct snd_compr_ops cs47l90_compr_ops = {
+static const struct snd_compress_ops cs47l90_compress_ops = {
.open = &cs47l90_open,
.free = &wm_adsp_compr_free,
.set_params = &wm_adsp_compr_set_params,
@@ -2489,7 +2488,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l90 = {
.set_sysclk = &madera_set_sysclk,
.set_pll = &cs47l90_set_fll,
.name = DRV_NAME,
- .compr_ops = &cs47l90_compr_ops,
+ .compress_ops = &cs47l90_compress_ops,
.controls = cs47l90_snd_controls,
.num_controls = ARRAY_SIZE(cs47l90_snd_controls),
.dapm_widgets = cs47l90_dapm_widgets,
diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c
index 15fc213d178d..108d28007185 100644
--- a/sound/soc/codecs/cs47l92.c
+++ b/sound/soc/codecs/cs47l92.c
@@ -1830,11 +1830,10 @@ static struct snd_soc_dai_driver cs47l92_dai[] = {
},
};
-static int cs47l92_open(struct snd_compr_stream *stream)
+static int cs47l92_open(struct snd_soc_component *component,
+ struct snd_compr_stream *stream)
{
struct snd_soc_pcm_runtime *rtd = stream->private_data;
- struct snd_soc_component *component =
- snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component);
struct madera_priv *priv = &cs47l92->core;
struct madera *madera = priv->madera;
@@ -1933,7 +1932,7 @@ static unsigned int cs47l92_digital_vu[] = {
MADERA_DAC_DIGITAL_VOLUME_5R,
};
-static const struct snd_compr_ops cs47l92_compr_ops = {
+static const struct snd_compress_ops cs47l92_compress_ops = {
.open = &cs47l92_open,
.free = &wm_adsp_compr_free,
.set_params = &wm_adsp_compr_set_params,
@@ -1949,7 +1948,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l92 = {
.set_sysclk = &madera_set_sysclk,
.set_pll = &cs47l92_set_fll,
.name = DRV_NAME,
- .compr_ops = &cs47l92_compr_ops,
+ .compress_ops = &cs47l92_compress_ops,
.controls = cs47l92_snd_controls,
.num_controls = ARRAY_SIZE(cs47l92_snd_controls),
.dapm_widgets = cs47l92_dapm_widgets,
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index f5560a49b9e5..5d079d90fd3b 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -59,14 +59,14 @@ static int dmic_aif_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
if (dmic->gpio_en)
- gpiod_set_value(dmic->gpio_en, 1);
+ gpiod_set_value_cansleep(dmic->gpio_en, 1);
if (dmic->wakeup_delay)
msleep(dmic->wakeup_delay);
break;
case SND_SOC_DAPM_POST_PMD:
if (dmic->gpio_en)
- gpiod_set_value(dmic->gpio_en, 0);
+ gpiod_set_value_cansleep(dmic->gpio_en, 0);
break;
}
diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c
index de26758c30a8..efe9fb3fb225 100644
--- a/sound/soc/codecs/nau8810.c
+++ b/sound/soc/codecs/nau8810.c
@@ -355,6 +355,8 @@ static const struct snd_kcontrol_new nau8810_snd_controls[] = {
/* Speaker Output Mixer */
static const struct snd_kcontrol_new nau8810_speaker_mixer_controls[] = {
+ SOC_DAPM_SINGLE("AUX Bypass Switch", NAU8810_REG_SPKMIX,
+ NAU8810_AUXSPK_SFT, 1, 0),
SOC_DAPM_SINGLE("Line Bypass Switch", NAU8810_REG_SPKMIX,
NAU8810_BYPSPK_SFT, 1, 0),
SOC_DAPM_SINGLE("PCM Playback Switch", NAU8810_REG_SPKMIX,
@@ -363,6 +365,8 @@ static const struct snd_kcontrol_new nau8810_speaker_mixer_controls[] = {
/* Mono Output Mixer */
static const struct snd_kcontrol_new nau8810_mono_mixer_controls[] = {
+ SOC_DAPM_SINGLE("AUX Bypass Switch", NAU8810_REG_MONOMIX,
+ NAU8810_AUXMOUT_SFT, 1, 0),
SOC_DAPM_SINGLE("Line Bypass Switch", NAU8810_REG_MONOMIX,
NAU8810_BYPMOUT_SFT, 1, 0),
SOC_DAPM_SINGLE("PCM Playback Switch", NAU8810_REG_MONOMIX,
@@ -371,6 +375,8 @@ static const struct snd_kcontrol_new nau8810_mono_mixer_controls[] = {
/* PGA Mute */
static const struct snd_kcontrol_new nau8810_pgaboost_mixer_controls[] = {
+ SOC_DAPM_SINGLE("AUX PGA Switch", NAU8810_REG_ADCBOOST,
+ NAU8810_AUXBSTGAIN_SFT, 0x7, 0),
SOC_DAPM_SINGLE("PGA Mute Switch", NAU8810_REG_PGAGAIN,
NAU8810_PGAMT_SFT, 1, 1),
SOC_DAPM_SINGLE("PMIC PGA Switch", NAU8810_REG_ADCBOOST,
@@ -379,6 +385,8 @@ static const struct snd_kcontrol_new nau8810_pgaboost_mixer_controls[] = {
/* Input PGA */
static const struct snd_kcontrol_new nau8810_inpga[] = {
+ SOC_DAPM_SINGLE("AUX Switch", NAU8810_REG_INPUT_SIGNAL,
+ NAU8810_AUXPGA_SFT, 1, 0),
SOC_DAPM_SINGLE("MicN Switch", NAU8810_REG_INPUT_SIGNAL,
NAU8810_NMICPGA_SFT, 1, 0),
SOC_DAPM_SINGLE("MicP Switch", NAU8810_REG_INPUT_SIGNAL,
@@ -401,6 +409,23 @@ static int check_mclk_select_pll(struct snd_soc_dapm_widget *source,
return (value & NAU8810_CLKM_MASK);
}
+static int check_mic_enabled(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(source->dapm);
+ struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
+ unsigned int value;
+
+ regmap_read(nau8810->regmap, NAU8810_REG_INPUT_SIGNAL, &value);
+ if (value & NAU8810_PMICPGA_EN || value & NAU8810_NMICPGA_EN)
+ return 1;
+ regmap_read(nau8810->regmap, NAU8810_REG_ADCBOOST, &value);
+ if (value & NAU8810_PMICBSTGAIN_MASK)
+ return 1;
+ return 0;
+}
+
static const struct snd_soc_dapm_widget nau8810_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("Speaker Mixer", NAU8810_REG_POWER3,
NAU8810_SPKMX_EN_SFT, 0, &nau8810_speaker_mixer_controls[0],
@@ -425,6 +450,8 @@ static const struct snd_soc_dapm_widget nau8810_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("Input Boost Stage", NAU8810_REG_POWER2,
NAU8810_BST_EN_SFT, 0, nau8810_pgaboost_mixer_controls,
ARRAY_SIZE(nau8810_pgaboost_mixer_controls)),
+ SND_SOC_DAPM_PGA("AUX Input", NAU8810_REG_POWER1,
+ NAU8810_AUX_EN_SFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("Mic Bias", NAU8810_REG_POWER1,
NAU8810_MICBIAS_EN_SFT, 0, NULL, 0),
@@ -434,6 +461,7 @@ static const struct snd_soc_dapm_widget nau8810_dapm_widgets[] = {
SND_SOC_DAPM_SWITCH("Digital Loopback", SND_SOC_NOPM, 0, 0,
&nau8810_loopback),
+ SND_SOC_DAPM_INPUT("AUX"),
SND_SOC_DAPM_INPUT("MICN"),
SND_SOC_DAPM_INPUT("MICP"),
SND_SOC_DAPM_OUTPUT("MONOOUT"),
@@ -445,10 +473,12 @@ static const struct snd_soc_dapm_route nau8810_dapm_routes[] = {
{"DAC", NULL, "PLL", check_mclk_select_pll},
/* Mono output mixer */
+ {"Mono Mixer", "AUX Bypass Switch", "AUX Input"},
{"Mono Mixer", "PCM Playback Switch", "DAC"},
{"Mono Mixer", "Line Bypass Switch", "Input Boost Stage"},
/* Speaker output mixer */
+ {"Speaker Mixer", "AUX Bypass Switch", "AUX Input"},
{"Speaker Mixer", "PCM Playback Switch", "DAC"},
{"Speaker Mixer", "Line Bypass Switch", "Input Boost Stage"},
@@ -463,13 +493,16 @@ static const struct snd_soc_dapm_route nau8810_dapm_routes[] = {
/* Input Boost Stage */
{"ADC", NULL, "Input Boost Stage"},
{"ADC", NULL, "PLL", check_mclk_select_pll},
+ {"Input Boost Stage", "AUX PGA Switch", "AUX Input"},
{"Input Boost Stage", "PGA Mute Switch", "Input PGA"},
{"Input Boost Stage", "PMIC PGA Switch", "MICP"},
/* Input PGA */
- {"Input PGA", NULL, "Mic Bias"},
+ {"Input PGA", NULL, "Mic Bias", check_mic_enabled},
+ {"Input PGA", "AUX Switch", "AUX Input"},
{"Input PGA", "MicN Switch", "MICN"},
{"Input PGA", "MicP Switch", "MICP"},
+ {"AUX Input", NULL, "AUX"},
/* Digital Looptack */
{"Digital Loopback", "Switch", "ADC"},
diff --git a/sound/soc/codecs/nau8810.h b/sound/soc/codecs/nau8810.h
index 1ada31883dc6..6a7cacbe044a 100644
--- a/sound/soc/codecs/nau8810.h
+++ b/sound/soc/codecs/nau8810.h
@@ -69,6 +69,7 @@
/* NAU8810_REG_POWER1 (0x1) */
#define NAU8810_DCBUF_EN (0x1 << 8)
+#define NAU8810_AUX_EN_SFT 6
#define NAU8810_PLL_EN_SFT 5
#define NAU8810_MICBIAS_EN_SFT 4
#define NAU8810_ABIAS_EN (0x1 << 3)
@@ -228,7 +229,10 @@
/* NAU8810_REG_INPUT_SIGNAL (0x2C) */
#define NAU8810_PMICPGA_SFT 0
+#define NAU8810_PMICPGA_EN (0x1 << NAU8810_PMICPGA_SFT)
#define NAU8810_NMICPGA_SFT 1
+#define NAU8810_NMICPGA_EN (0x1 << NAU8810_NMICPGA_SFT)
+#define NAU8810_AUXPGA_SFT 2
/* NAU8810_REG_PGAGAIN (0x2D) */
#define NAU8810_PGAGAIN_SFT 0
@@ -236,12 +240,15 @@
#define NAU8810_PGAZC_SFT 7
/* NAU8810_REG_ADCBOOST (0x2F) */
+#define NAU8810_AUXBSTGAIN_SFT 0
#define NAU8810_PMICBSTGAIN_SFT 4
+#define NAU8810_PMICBSTGAIN_MASK (0x7 << NAU8810_PMICBSTGAIN_SFT)
#define NAU8810_PGABST_SFT 8
/* NAU8810_REG_SPKMIX (0x32) */
#define NAU8810_DACSPK_SFT 0
#define NAU8810_BYPSPK_SFT 1
+#define NAU8810_AUXSPK_SFT 5
/* NAU8810_REG_SPKGAIN (0x36) */
#define NAU8810_SPKGAIN_SFT 0
@@ -251,6 +258,7 @@
/* NAU8810_REG_MONOMIX (0x38) */
#define NAU8810_DACMOUT_SFT 0
#define NAU8810_BYPMOUT_SFT 1
+#define NAU8810_AUXMOUT_SFT 2
#define NAU8810_MOUTMXMT_SFT 6
diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c
index d181c217d835..2586d1cafc0c 100644
--- a/sound/soc/codecs/rl6231.c
+++ b/sound/soc/codecs/rl6231.c
@@ -97,12 +97,13 @@ struct pll_calc_map {
int n;
int m;
bool m_bp;
+ bool k_bp;
};
static const struct pll_calc_map pll_preset_table[] = {
- {19200000, 4096000, 23, 14, 1, false},
- {19200000, 24576000, 3, 30, 3, false},
- {3840000, 24576000, 3, 30, 0, true},
+ {19200000, 4096000, 23, 14, 1, false, false},
+ {19200000, 24576000, 3, 30, 3, false, false},
+ {3840000, 24576000, 3, 30, 0, true, false},
};
static unsigned int find_best_div(unsigned int in,
@@ -128,7 +129,7 @@ static unsigned int find_best_div(unsigned int in,
* rl6231_pll_calc - Calcualte PLL M/N/K code.
* @freq_in: external clock provided to codec.
* @freq_out: target clock which codec works on.
- * @pll_code: Pointer to structure with M, N, K and bypass flag.
+ * @pll_code: Pointer to structure with M, N, K, m_bypass and k_bypass flag.
*
* Calcualte M/N/K code to configure PLL for codec.
*
@@ -143,7 +144,7 @@ int rl6231_pll_calc(const unsigned int freq_in,
unsigned int red, pll_out, in_t, out_t, div, div_t;
unsigned int red_t = abs(freq_out - freq_in);
unsigned int f_in, f_out, f_max;
- bool bypass = false;
+ bool m_bypass = false, k_bypass = false;
if (RL6231_PLL_INP_MAX < freq_in || RL6231_PLL_INP_MIN > freq_in)
return -EINVAL;
@@ -154,7 +155,8 @@ int rl6231_pll_calc(const unsigned int freq_in,
k = pll_preset_table[i].k;
m = pll_preset_table[i].m;
n = pll_preset_table[i].n;
- bypass = pll_preset_table[i].m_bp;
+ m_bypass = pll_preset_table[i].m_bp;
+ k_bypass = pll_preset_table[i].k_bp;
pr_debug("Use preset PLL parameter table\n");
goto code_find;
}
@@ -172,12 +174,14 @@ int rl6231_pll_calc(const unsigned int freq_in,
f_in = freq_in / div;
f_out = freq_out / div;
k = min_k;
+ if (min_k < -1)
+ min_k = -1;
for (k_t = min_k; k_t <= max_k; k_t++) {
for (n_t = 0; n_t <= max_n; n_t++) {
in_t = f_in * (n_t + 2);
pll_out = f_out * (k_t + 2);
if (in_t == pll_out) {
- bypass = true;
+ m_bypass = true;
n = n_t;
k = k_t;
goto code_find;
@@ -185,7 +189,7 @@ int rl6231_pll_calc(const unsigned int freq_in,
out_t = in_t / (k_t + 2);
red = abs(f_out - out_t);
if (red < red_t) {
- bypass = true;
+ m_bypass = true;
n = n_t;
m = 0;
k = k_t;
@@ -197,7 +201,7 @@ int rl6231_pll_calc(const unsigned int freq_in,
out_t = in_t / ((m_t + 2) * (k_t + 2));
red = abs(f_out - out_t);
if (red < red_t) {
- bypass = false;
+ m_bypass = false;
n = n_t;
m = m_t;
k = k_t;
@@ -211,8 +215,13 @@ int rl6231_pll_calc(const unsigned int freq_in,
pr_debug("Only get approximation about PLL\n");
code_find:
+ if (k == -1) {
+ k_bypass = true;
+ k = 0;
+ }
- pll_code->m_bp = bypass;
+ pll_code->m_bp = m_bypass;
+ pll_code->k_bp = k_bypass;
pll_code->m_code = m;
pll_code->n_code = n;
pll_code->k_code = k;
diff --git a/sound/soc/codecs/rl6231.h b/sound/soc/codecs/rl6231.h
index 6d8ed0377296..928082750860 100644
--- a/sound/soc/codecs/rl6231.h
+++ b/sound/soc/codecs/rl6231.h
@@ -18,6 +18,7 @@
struct rl6231_pll_code {
bool m_bp; /* Indicates bypass m code or not. */
+ bool k_bp; /* Indicates bypass k code or not. */
int m_code;
int n_code;
int k_code;
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c
index bb310bc7febd..5eb07a430ae3 100644
--- a/sound/soc/codecs/rt1015.c
+++ b/sound/soc/codecs/rt1015.c
@@ -780,6 +780,14 @@ static int rt1015_set_component_pll(struct snd_soc_component *component,
freq_out == rt1015->pll_out)
return 0;
+ if (source == RT1015_PLL_S_BCLK) {
+ if (rt1015->bclk_ratio == 0) {
+ dev_err(component->dev,
+ "Can not support bclk ratio as 0.\n");
+ return -EINVAL;
+ }
+ }
+
switch (source) {
case RT1015_PLL_S_MCLK:
snd_soc_component_update_bits(component, RT1015_CLK2,
@@ -819,12 +827,30 @@ static int rt1015_set_component_pll(struct snd_soc_component *component,
return 0;
}
+static int rt1015_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
+
+ rt1015->bclk_ratio = ratio;
+
+ if (ratio == 50) {
+ dev_dbg(component->dev, "Unsupport bclk ratio\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int rt1015_probe(struct snd_soc_component *component)
{
struct rt1015_priv *rt1015 =
snd_soc_component_get_drvdata(component);
rt1015->component = component;
+ rt1015->bclk_ratio = 0;
snd_soc_component_write(component, RT1015_BAT_RPO_STEP1, 0x061c);
return 0;
@@ -844,6 +870,7 @@ static void rt1015_remove(struct snd_soc_component *component)
static struct snd_soc_dai_ops rt1015_aif_dai_ops = {
.hw_params = rt1015_hw_params,
.set_fmt = rt1015_set_dai_fmt,
+ .set_bclk_ratio = rt1015_set_bclk_ratio,
};
static struct snd_soc_dai_driver rt1015_dai[] = {
diff --git a/sound/soc/codecs/rt1015.h b/sound/soc/codecs/rt1015.h
index ef3745a4faae..6fbe802082c4 100644
--- a/sound/soc/codecs/rt1015.h
+++ b/sound/soc/codecs/rt1015.h
@@ -362,6 +362,7 @@ struct rt1015_priv {
int sysclk_src;
int lrck;
int bclk;
+ int bclk_ratio;
int id;
int pll_src;
int pll_in;
diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c
new file mode 100644
index 000000000000..a23d368ab4da
--- /dev/null
+++ b/sound/soc/codecs/rt1016.c
@@ -0,0 +1,695 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// rt1016.c -- RT1016 ALSA SoC audio amplifier driver
+//
+// Copyright 2020 Realtek Semiconductor Corp.
+// Author: Oder Chiou <[email protected]>
+//
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#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>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rl6231.h"
+#include "rt1016.h"
+
+static const struct reg_sequence rt1016_patch[] = {
+ {RT1016_VOL_CTRL_3, 0x8900},
+ {RT1016_ANA_CTRL_1, 0xa002},
+ {RT1016_ANA_CTRL_2, 0x0002},
+ {RT1016_CLOCK_4, 0x6700},
+ {RT1016_CLASSD_3, 0xdc55},
+ {RT1016_CLASSD_4, 0x376a},
+ {RT1016_CLASSD_5, 0x009f},
+};
+
+static const struct reg_default rt1016_reg[] = {
+ {0x00, 0x0000},
+ {0x01, 0x5400},
+ {0x02, 0x5506},
+ {0x03, 0xf800},
+ {0x04, 0x0000},
+ {0x05, 0xbfbf},
+ {0x06, 0x8900},
+ {0x07, 0xa002},
+ {0x08, 0x0000},
+ {0x09, 0x0000},
+ {0x0a, 0x0000},
+ {0x0c, 0x0000},
+ {0x0d, 0x0000},
+ {0x0e, 0x10ec},
+ {0x0f, 0x6595},
+ {0x11, 0x0002},
+ {0x1c, 0x0000},
+ {0x1d, 0x0000},
+ {0x1e, 0x0000},
+ {0x1f, 0xf000},
+ {0x20, 0x0000},
+ {0x21, 0x6000},
+ {0x22, 0x0000},
+ {0x23, 0x6700},
+ {0x24, 0x0000},
+ {0x25, 0x0000},
+ {0x26, 0x0000},
+ {0x40, 0x0018},
+ {0x60, 0x00a5},
+ {0x80, 0x0010},
+ {0x81, 0x0009},
+ {0x82, 0x0000},
+ {0x83, 0x0000},
+ {0xa0, 0x0700},
+ {0xc0, 0x0080},
+ {0xc1, 0x02a0},
+ {0xc2, 0x1400},
+ {0xc3, 0x0a4a},
+ {0xc4, 0x552a},
+ {0xc5, 0x087e},
+ {0xc6, 0x0020},
+ {0xc7, 0xa833},
+ {0xc8, 0x0433},
+ {0xc9, 0x8040},
+ {0xca, 0xdc55},
+ {0xcb, 0x376a},
+ {0xcc, 0x009f},
+ {0xcf, 0x0020},
+};
+
+static bool rt1016_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT1016_ANA_FLAG:
+ case RT1016_VERSION2_ID:
+ case RT1016_VERSION1_ID:
+ case RT1016_VENDER_ID:
+ case RT1016_DEVICE_ID:
+ case RT1016_TEST_SIGNAL:
+ case RT1016_SC_CTRL_1:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool rt1016_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT1016_RESET:
+ case RT1016_PADS_CTRL_1:
+ case RT1016_PADS_CTRL_2:
+ case RT1016_I2C_CTRL:
+ case RT1016_VOL_CTRL_1:
+ case RT1016_VOL_CTRL_2:
+ case RT1016_VOL_CTRL_3:
+ case RT1016_ANA_CTRL_1:
+ case RT1016_MUX_SEL:
+ case RT1016_RX_I2S_CTRL:
+ case RT1016_ANA_FLAG:
+ case RT1016_VERSION2_ID:
+ case RT1016_VERSION1_ID:
+ case RT1016_VENDER_ID:
+ case RT1016_DEVICE_ID:
+ case RT1016_ANA_CTRL_2:
+ case RT1016_TEST_SIGNAL:
+ case RT1016_TEST_CTRL_1:
+ case RT1016_TEST_CTRL_2:
+ case RT1016_TEST_CTRL_3:
+ case RT1016_CLOCK_1:
+ case RT1016_CLOCK_2:
+ case RT1016_CLOCK_3:
+ case RT1016_CLOCK_4:
+ case RT1016_CLOCK_5:
+ case RT1016_CLOCK_6:
+ case RT1016_CLOCK_7:
+ case RT1016_I2S_CTRL:
+ case RT1016_DAC_CTRL_1:
+ case RT1016_SC_CTRL_1:
+ case RT1016_SC_CTRL_2:
+ case RT1016_SC_CTRL_3:
+ case RT1016_SC_CTRL_4:
+ case RT1016_SIL_DET:
+ case RT1016_SYS_CLK:
+ case RT1016_BIAS_CUR:
+ case RT1016_DAC_CTRL_2:
+ case RT1016_LDO_CTRL:
+ case RT1016_CLASSD_1:
+ case RT1016_PLL1:
+ case RT1016_PLL2:
+ case RT1016_PLL3:
+ case RT1016_CLASSD_2:
+ case RT1016_CLASSD_OUT:
+ case RT1016_CLASSD_3:
+ case RT1016_CLASSD_4:
+ case RT1016_CLASSD_5:
+ case RT1016_PWR_CTRL:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
+
+static const struct snd_kcontrol_new rt1016_snd_controls[] = {
+ SOC_DOUBLE_TLV("DAC Playback Volume", RT1016_VOL_CTRL_2,
+ RT1016_L_VOL_SFT, RT1016_R_VOL_SFT, 191, 0, dac_vol_tlv),
+ SOC_DOUBLE("DAC Playback Switch", RT1016_VOL_CTRL_1,
+ RT1016_DA_MUTE_L_SFT, RT1016_DA_MUTE_R_SFT, 1, 1),
+};
+
+static int rt1016_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(source->dapm);
+ struct rt1016_priv *rt1016 = snd_soc_component_get_drvdata(component);
+
+ if (rt1016->sysclk_src == RT1016_SCLK_S_PLL)
+ return 1;
+ else
+ return 0;
+}
+
+/* Interface data select */
+static const char * const rt1016_data_select[] = {
+ "L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1016_if_data_swap_enum,
+ RT1016_I2S_CTRL, RT1016_I2S_DATA_SWAP_SFT, rt1016_data_select);
+
+static const struct snd_kcontrol_new rt1016_if_data_swap_mux =
+ SOC_DAPM_ENUM("Data Swap Mux", rt1016_if_data_swap_enum);
+
+static const struct snd_soc_dapm_widget rt1016_dapm_widgets[] = {
+ SND_SOC_DAPM_MUX("Data Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt1016_if_data_swap_mux),
+
+ SND_SOC_DAPM_SUPPLY("DAC Filter", RT1016_CLOCK_3,
+ RT1016_PWR_DAC_FILTER_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAMOD", RT1016_CLOCK_3, RT1016_PWR_DACMOD_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("FIFO", RT1016_CLOCK_3, RT1016_PWR_CLK_FIFO_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Pure DC", RT1016_CLOCK_3,
+ RT1016_PWR_CLK_PUREDC_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("CLK Silence Det", RT1016_CLOCK_3,
+ RT1016_PWR_SIL_DET_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("RC 25M", RT1016_CLOCK_3, RT1016_PWR_RC_25M_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PLL1", RT1016_CLOCK_3, RT1016_PWR_PLL1_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ANA CTRL", RT1016_CLOCK_3, RT1016_PWR_ANA_CTRL_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("CLK SYS", RT1016_CLOCK_3, RT1016_PWR_CLK_SYS_BIT,
+ 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("LRCK Det", RT1016_CLOCK_4, RT1016_PWR_LRCK_DET_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BCLK Det", RT1016_CLOCK_4, RT1016_PWR_BCLK_DET_BIT,
+ 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("CKGEN DAC", RT1016_DAC_CTRL_2,
+ RT1016_CKGEN_DAC_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("VCM SLOW", RT1016_CLASSD_1, RT1016_VCM_SLOW_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Silence Det", RT1016_SIL_DET,
+ RT1016_SIL_DET_EN_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PLL2", RT1016_PLL2, RT1016_PLL2_EN_BIT, 0, NULL,
+ 0),
+
+ SND_SOC_DAPM_SUPPLY_S("BG1 BG2", 1, RT1016_PWR_CTRL,
+ RT1016_PWR_BG_1_2_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("MBIAS BG", 1, RT1016_PWR_CTRL,
+ RT1016_PWR_MBIAS_BG_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("PLL", 1, RT1016_PWR_CTRL, RT1016_PWR_PLL_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("BASIC", 1, RT1016_PWR_CTRL, RT1016_PWR_BASIC_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("CLASS D", 1, RT1016_PWR_CTRL,
+ RT1016_PWR_CLSD_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("25M", 1, RT1016_PWR_CTRL, RT1016_PWR_25M_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DACL", 1, RT1016_PWR_CTRL, RT1016_PWR_DACL_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DACR", 1, RT1016_PWR_CTRL, RT1016_PWR_DACR_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("LDO2", 1, RT1016_PWR_CTRL, RT1016_PWR_LDO2_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("VREF", 1, RT1016_PWR_CTRL, RT1016_PWR_VREF_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("MBIAS", 1, RT1016_PWR_CTRL, RT1016_PWR_MBIAS_BIT,
+ 0, NULL, 0),
+
+ SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_OUTPUT("SPO"),
+};
+
+static const struct snd_soc_dapm_route rt1016_dapm_routes[] = {
+ { "Data Swap Mux", "L/R", "AIFRX" },
+ { "Data Swap Mux", "R/L", "AIFRX" },
+ { "Data Swap Mux", "L/L", "AIFRX" },
+ { "Data Swap Mux", "R/R", "AIFRX" },
+
+ { "DAC", NULL, "DAC Filter" },
+ { "DAC", NULL, "DAMOD" },
+ { "DAC", NULL, "FIFO" },
+ { "DAC", NULL, "Pure DC" },
+ { "DAC", NULL, "Silence Det" },
+ { "DAC", NULL, "ANA CTRL" },
+ { "DAC", NULL, "CLK SYS" },
+ { "DAC", NULL, "LRCK Det" },
+ { "DAC", NULL, "BCLK Det" },
+ { "DAC", NULL, "CKGEN DAC" },
+ { "DAC", NULL, "VCM SLOW" },
+
+ { "PLL", NULL, "PLL1" },
+ { "PLL", NULL, "PLL2" },
+ { "25M", NULL, "RC 25M" },
+ { "Silence Det", NULL, "CLK Silence Det" },
+
+ { "DAC", NULL, "Data Swap Mux" },
+ { "DAC", NULL, "BG1 BG2" },
+ { "DAC", NULL, "MBIAS BG" },
+ { "DAC", NULL, "PLL", rt1016_is_sys_clk_from_pll},
+ { "DAC", NULL, "BASIC" },
+ { "DAC", NULL, "CLASS D" },
+ { "DAC", NULL, "25M" },
+ { "DAC", NULL, "DACL" },
+ { "DAC", NULL, "DACR" },
+ { "DAC", NULL, "LDO2" },
+ { "DAC", NULL, "VREF" },
+ { "DAC", NULL, "MBIAS" },
+
+ { "SPO", NULL, "DAC" },
+};
+
+static int rt1016_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1016_priv *rt1016 = snd_soc_component_get_drvdata(component);
+ int pre_div, bclk_ms, frame_size;
+ unsigned int val_len = 0;
+
+ rt1016->lrck = params_rate(params);
+ pre_div = rl6231_get_clk_info(rt1016->sysclk, rt1016->lrck);
+ if (pre_div < 0) {
+ dev_err(component->dev, "Unsupported clock rate\n");
+ return -EINVAL;
+ }
+
+ frame_size = snd_soc_params_to_frame_size(params);
+ if (frame_size < 0) {
+ dev_err(component->dev, "Unsupported frame size: %d\n",
+ frame_size);
+ return -EINVAL;
+ }
+
+ bclk_ms = frame_size > 32;
+ rt1016->bclk = rt1016->lrck * (32 << bclk_ms);
+
+ if (bclk_ms && rt1016->master)
+ snd_soc_component_update_bits(component, RT1016_I2S_CTRL,
+ RT1016_I2S_BCLK_MS_MASK, RT1016_I2S_BCLK_MS_64);
+
+ dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+ rt1016->lrck, pre_div, dai->id);
+
+ switch (params_width(params)) {
+ case 16:
+ val_len = RT1016_I2S_DL_16;
+ break;
+ case 20:
+ val_len = RT1016_I2S_DL_20;
+ break;
+ case 24:
+ val_len = RT1016_I2S_DL_24;
+ break;
+ case 32:
+ val_len = RT1016_I2S_DL_32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component, RT1016_I2S_CTRL,
+ RT1016_I2S_DL_MASK, val_len);
+ snd_soc_component_update_bits(component, RT1016_CLOCK_2,
+ RT1016_FS_PD_MASK | RT1016_OSR_PD_MASK,
+ ((pre_div + 3) << RT1016_FS_PD_SFT) |
+ (pre_div << RT1016_OSR_PD_SFT));
+
+ return 0;
+}
+
+static int rt1016_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1016_priv *rt1016 = snd_soc_component_get_drvdata(component);
+ unsigned int reg_val = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ reg_val |= RT1016_I2S_MS_M;
+ rt1016->master = 1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ reg_val |= RT1016_I2S_MS_S;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg_val |= RT1016_I2S_BCLK_POL_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg_val |= RT1016_I2S_DF_LEFT;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_A:
+ reg_val |= RT1016_I2S_DF_PCM_A;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_B:
+ reg_val |= RT1016_I2S_DF_PCM_B;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component, RT1016_I2S_CTRL,
+ RT1016_I2S_MS_MASK | RT1016_I2S_BCLK_POL_MASK |
+ RT1016_I2S_DF_MASK, reg_val);
+
+ return 0;
+}
+
+static int rt1016_set_component_sysclk(struct snd_soc_component *component,
+ int clk_id, int source, unsigned int freq, int dir)
+{
+ struct rt1016_priv *rt1016 = snd_soc_component_get_drvdata(component);
+ unsigned int reg_val = 0;
+
+ if (freq == rt1016->sysclk && clk_id == rt1016->sysclk_src)
+ return 0;
+
+ switch (clk_id) {
+ case RT1016_SCLK_S_MCLK:
+ reg_val |= RT1016_CLK_SYS_SEL_MCLK;
+ break;
+
+ case RT1016_SCLK_S_PLL:
+ reg_val |= RT1016_CLK_SYS_SEL_PLL;
+ break;
+
+ default:
+ dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+ return -EINVAL;
+ }
+
+ rt1016->sysclk = freq;
+ rt1016->sysclk_src = clk_id;
+
+ dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n",
+ freq, clk_id);
+
+ snd_soc_component_update_bits(component, RT1016_CLOCK_1,
+ RT1016_CLK_SYS_SEL_MASK, reg_val);
+
+ return 0;
+}
+
+static int rt1016_set_component_pll(struct snd_soc_component *component,
+ int pll_id, int source, unsigned int freq_in,
+ unsigned int freq_out)
+{
+ struct rt1016_priv *rt1016 = snd_soc_component_get_drvdata(component);
+ struct rl6231_pll_code pll_code;
+ int ret;
+
+ if (!freq_in || !freq_out) {
+ dev_dbg(component->dev, "PLL disabled\n");
+
+ rt1016->pll_in = 0;
+ rt1016->pll_out = 0;
+
+ return 0;
+ }
+
+ if (source == rt1016->pll_src && freq_in == rt1016->pll_in &&
+ freq_out == rt1016->pll_out)
+ return 0;
+
+ switch (source) {
+ case RT1016_PLL_S_MCLK:
+ snd_soc_component_update_bits(component, RT1016_CLOCK_1,
+ RT1016_PLL_SEL_MASK, RT1016_PLL_SEL_MCLK);
+ break;
+
+ case RT1016_PLL_S_BCLK:
+ snd_soc_component_update_bits(component, RT1016_CLOCK_1,
+ RT1016_PLL_SEL_MASK, RT1016_PLL_SEL_BCLK);
+ break;
+
+ default:
+ dev_err(component->dev, "Unknown PLL Source %d\n", source);
+ return -EINVAL;
+ }
+
+ ret = rl6231_pll_calc(freq_in, freq_out * 4, &pll_code);
+ if (ret < 0) {
+ dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+ return ret;
+ }
+
+ dev_dbg(component->dev, "mbypass=%d m=%d n=%d kbypass=%d k=%d\n",
+ pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+ pll_code.n_code, pll_code.k_bp,
+ (pll_code.k_bp ? 0 : pll_code.k_code));
+
+ snd_soc_component_write(component, RT1016_PLL1,
+ (pll_code.m_bp ? 0 : pll_code.m_code) << RT1016_PLL_M_SFT |
+ pll_code.m_bp << RT1016_PLL_M_BP_SFT | pll_code.n_code);
+ snd_soc_component_write(component, RT1016_PLL2,
+ pll_code.k_bp << RT1016_PLL_K_BP_SFT |
+ (pll_code.k_bp ? 0 : pll_code.k_code));
+
+ rt1016->pll_in = freq_in;
+ rt1016->pll_out = freq_out;
+ rt1016->pll_src = source;
+
+ return 0;
+}
+
+static int rt1016_probe(struct snd_soc_component *component)
+{
+ struct rt1016_priv *rt1016 =
+ snd_soc_component_get_drvdata(component);
+
+ rt1016->component = component;
+
+ return 0;
+}
+
+static void rt1016_remove(struct snd_soc_component *component)
+{
+ struct rt1016_priv *rt1016 = snd_soc_component_get_drvdata(component);
+
+ regmap_write(rt1016->regmap, RT1016_RESET, 0);
+}
+
+#define RT1016_STEREO_RATES SNDRV_PCM_RATE_8000_48000
+#define RT1016_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static struct snd_soc_dai_ops rt1016_aif_dai_ops = {
+ .hw_params = rt1016_hw_params,
+ .set_fmt = rt1016_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver rt1016_dai[] = {
+ {
+ .name = "rt1016-aif",
+ .id = 0,
+ .playback = {
+ .stream_name = "AIF Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT1016_STEREO_RATES,
+ .formats = RT1016_FORMATS,
+ },
+ .ops = &rt1016_aif_dai_ops,
+ }
+};
+
+#ifdef CONFIG_PM
+static int rt1016_suspend(struct snd_soc_component *component)
+{
+ struct rt1016_priv *rt1016 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(rt1016->regmap, true);
+ regcache_mark_dirty(rt1016->regmap);
+
+ return 0;
+}
+
+static int rt1016_resume(struct snd_soc_component *component)
+{
+ struct rt1016_priv *rt1016 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(rt1016->regmap, false);
+ regcache_sync(rt1016->regmap);
+
+ return 0;
+}
+#else
+#define rt1016_suspend NULL
+#define rt1016_resume NULL
+#endif
+
+static const struct snd_soc_component_driver soc_component_dev_rt1016 = {
+ .probe = rt1016_probe,
+ .remove = rt1016_remove,
+ .suspend = rt1016_suspend,
+ .resume = rt1016_resume,
+ .controls = rt1016_snd_controls,
+ .num_controls = ARRAY_SIZE(rt1016_snd_controls),
+ .dapm_widgets = rt1016_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt1016_dapm_widgets),
+ .dapm_routes = rt1016_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt1016_dapm_routes),
+ .set_sysclk = rt1016_set_component_sysclk,
+ .set_pll = rt1016_set_component_pll,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
+};
+
+static const struct regmap_config rt1016_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = RT1016_PWR_CTRL,
+ .volatile_reg = rt1016_volatile_register,
+ .readable_reg = rt1016_readable_register,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = rt1016_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt1016_reg),
+};
+
+static const struct i2c_device_id rt1016_i2c_id[] = {
+ { "rt1016", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rt1016_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rt1016_of_match[] = {
+ { .compatible = "realtek,rt1016", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt1016_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static struct acpi_device_id rt1016_acpi_match[] = {
+ {"10EC1016", 0,},
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, rt1016_acpi_match);
+#endif
+
+static int rt1016_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rt1016_priv *rt1016;
+ int ret;
+ unsigned int val;
+
+ rt1016 = devm_kzalloc(&i2c->dev, sizeof(struct rt1016_priv),
+ GFP_KERNEL);
+ if (rt1016 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, rt1016);
+
+ rt1016->regmap = devm_regmap_init_i2c(i2c, &rt1016_regmap);
+ if (IS_ERR(rt1016->regmap)) {
+ ret = PTR_ERR(rt1016->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ regmap_read(rt1016->regmap, RT1016_DEVICE_ID, &val);
+ if (val != RT1016_DEVICE_ID_VAL) {
+ dev_err(&i2c->dev,
+ "Device with ID register %x is not rt1016\n", val);
+ return -ENODEV;
+ }
+
+ regmap_write(rt1016->regmap, RT1016_RESET, 0);
+
+ ret = regmap_register_patch(rt1016->regmap, rt1016_patch,
+ ARRAY_SIZE(rt1016_patch));
+ if (ret != 0)
+ dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+ return devm_snd_soc_register_component(&i2c->dev,
+ &soc_component_dev_rt1016,
+ rt1016_dai, ARRAY_SIZE(rt1016_dai));
+}
+
+static void rt1016_i2c_shutdown(struct i2c_client *client)
+{
+ struct rt1016_priv *rt1016 = i2c_get_clientdata(client);
+
+ regmap_write(rt1016->regmap, RT1016_RESET, 0);
+}
+
+static struct i2c_driver rt1016_i2c_driver = {
+ .driver = {
+ .name = "rt1016",
+ .of_match_table = of_match_ptr(rt1016_of_match),
+ .acpi_match_table = ACPI_PTR(rt1016_acpi_match),
+ },
+ .probe = rt1016_i2c_probe,
+ .shutdown = rt1016_i2c_shutdown,
+ .id_table = rt1016_i2c_id,
+};
+module_i2c_driver(rt1016_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT1016 driver");
+MODULE_AUTHOR("Oder Chiou <[email protected]>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt1016.h b/sound/soc/codecs/rt1016.h
new file mode 100644
index 000000000000..041d6a5a6f46
--- /dev/null
+++ b/sound/soc/codecs/rt1016.h
@@ -0,0 +1,232 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * rt1016.h -- RT1016 ALSA SoC audio amplifier driver
+ *
+ * Copyright 2020 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT1016_H__
+#define __RT1016_H__
+
+#define RT1016_DEVICE_ID_VAL 0x6595
+
+#define RT1016_RESET 0x00
+#define RT1016_PADS_CTRL_1 0x01
+#define RT1016_PADS_CTRL_2 0x02
+#define RT1016_I2C_CTRL 0x03
+#define RT1016_VOL_CTRL_1 0x04
+#define RT1016_VOL_CTRL_2 0x05
+#define RT1016_VOL_CTRL_3 0x06
+#define RT1016_ANA_CTRL_1 0x07
+#define RT1016_MUX_SEL 0x08
+#define RT1016_RX_I2S_CTRL 0x09
+#define RT1016_ANA_FLAG 0x0a
+#define RT1016_VERSION2_ID 0x0c
+#define RT1016_VERSION1_ID 0x0d
+#define RT1016_VENDER_ID 0x0e
+#define RT1016_DEVICE_ID 0x0f
+#define RT1016_ANA_CTRL_2 0x11
+#define RT1016_TEST_SIGNAL 0x1c
+#define RT1016_TEST_CTRL_1 0x1d
+#define RT1016_TEST_CTRL_2 0x1e
+#define RT1016_TEST_CTRL_3 0x1f
+#define RT1016_CLOCK_1 0x20
+#define RT1016_CLOCK_2 0x21
+#define RT1016_CLOCK_3 0x22
+#define RT1016_CLOCK_4 0x23
+#define RT1016_CLOCK_5 0x24
+#define RT1016_CLOCK_6 0x25
+#define RT1016_CLOCK_7 0x26
+#define RT1016_I2S_CTRL 0x40
+#define RT1016_DAC_CTRL_1 0x60
+#define RT1016_SC_CTRL_1 0x80
+#define RT1016_SC_CTRL_2 0x81
+#define RT1016_SC_CTRL_3 0x82
+#define RT1016_SC_CTRL_4 0x83
+#define RT1016_SIL_DET 0xa0
+#define RT1016_SYS_CLK 0xc0
+#define RT1016_BIAS_CUR 0xc1
+#define RT1016_DAC_CTRL_2 0xc2
+#define RT1016_LDO_CTRL 0xc3
+#define RT1016_CLASSD_1 0xc4
+#define RT1016_PLL1 0xc5
+#define RT1016_PLL2 0xc6
+#define RT1016_PLL3 0xc7
+#define RT1016_CLASSD_2 0xc8
+#define RT1016_CLASSD_OUT 0xc9
+#define RT1016_CLASSD_3 0xca
+#define RT1016_CLASSD_4 0xcb
+#define RT1016_CLASSD_5 0xcc
+#define RT1016_PWR_CTRL 0xcf
+
+/* global definition */
+#define RT1016_L_VOL_MASK (0xff << 8)
+#define RT1016_L_VOL_SFT 8
+#define RT1016_R_VOL_MASK (0xff)
+#define RT1016_R_VOL_SFT 0
+
+/* 0x04 */
+#define RT1016_DA_MUTE_L_SFT 7
+#define RT1016_DA_MUTE_R_SFT 6
+
+/* 0x20 */
+#define RT1016_CLK_SYS_SEL_MASK (0x1 << 15)
+#define RT1016_CLK_SYS_SEL_SFT 15
+#define RT1016_CLK_SYS_SEL_MCLK (0x0 << 15)
+#define RT1016_CLK_SYS_SEL_PLL (0x1 << 15)
+#define RT1016_PLL_SEL_MASK (0x1 << 13)
+#define RT1016_PLL_SEL_SFT 13
+#define RT1016_PLL_SEL_MCLK (0x0 << 13)
+#define RT1016_PLL_SEL_BCLK (0x1 << 13)
+
+/* 0x21 */
+#define RT1016_FS_PD_MASK (0x7 << 13)
+#define RT1016_FS_PD_SFT 13
+#define RT1016_OSR_PD_MASK (0x3 << 10)
+#define RT1016_OSR_PD_SFT 10
+
+/* 0x22 */
+#define RT1016_PWR_DAC_FILTER (0x1 << 11)
+#define RT1016_PWR_DAC_FILTER_BIT 11
+#define RT1016_PWR_DACMOD (0x1 << 10)
+#define RT1016_PWR_DACMOD_BIT 10
+#define RT1016_PWR_CLK_FIFO (0x1 << 9)
+#define RT1016_PWR_CLK_FIFO_BIT 9
+#define RT1016_PWR_CLK_PUREDC (0x1 << 8)
+#define RT1016_PWR_CLK_PUREDC_BIT 8
+#define RT1016_PWR_SIL_DET (0x1 << 7)
+#define RT1016_PWR_SIL_DET_BIT 7
+#define RT1016_PWR_RC_25M (0x1 << 6)
+#define RT1016_PWR_RC_25M_BIT 6
+#define RT1016_PWR_PLL1 (0x1 << 5)
+#define RT1016_PWR_PLL1_BIT 5
+#define RT1016_PWR_ANA_CTRL (0x1 << 4)
+#define RT1016_PWR_ANA_CTRL_BIT 4
+#define RT1016_PWR_CLK_SYS (0x1 << 3)
+#define RT1016_PWR_CLK_SYS_BIT 3
+
+/* 0x23 */
+#define RT1016_PWR_LRCK_DET (0x1 << 15)
+#define RT1016_PWR_LRCK_DET_BIT 15
+#define RT1016_PWR_BCLK_DET (0x1 << 11)
+#define RT1016_PWR_BCLK_DET_BIT 11
+
+/* 0x40 */
+#define RT1016_I2S_BCLK_MS_MASK (0x1 << 15)
+#define RT1016_I2S_BCLK_MS_SFT 15
+#define RT1016_I2S_BCLK_MS_32 (0x0 << 15)
+#define RT1016_I2S_BCLK_MS_64 (0x1 << 15)
+#define RT1016_I2S_BCLK_POL_MASK (0x1 << 13)
+#define RT1016_I2S_BCLK_POL_SFT 13
+#define RT1016_I2S_BCLK_POL_NOR (0x0 << 13)
+#define RT1016_I2S_BCLK_POL_INV (0x1 << 13)
+#define RT1016_I2S_DATA_SWAP_MASK (0x1 << 10)
+#define RT1016_I2S_DATA_SWAP_SFT 10
+#define RT1016_I2S_DL_MASK (0x7 << 4)
+#define RT1016_I2S_DL_SFT 4
+#define RT1016_I2S_DL_16 (0x1 << 4)
+#define RT1016_I2S_DL_20 (0x2 << 4)
+#define RT1016_I2S_DL_24 (0x3 << 4)
+#define RT1016_I2S_DL_32 (0x4 << 4)
+#define RT1016_I2S_MS_MASK (0x1 << 3)
+#define RT1016_I2S_MS_SFT 3
+#define RT1016_I2S_MS_M (0x0 << 3)
+#define RT1016_I2S_MS_S (0x1 << 3)
+#define RT1016_I2S_DF_MASK (0x7 << 0)
+#define RT1016_I2S_DF_SFT 0
+#define RT1016_I2S_DF_I2S (0x0)
+#define RT1016_I2S_DF_LEFT (0x1)
+#define RT1016_I2S_DF_PCM_A (0x2)
+#define RT1016_I2S_DF_PCM_B (0x3)
+
+/* 0xa0 */
+#define RT1016_SIL_DET_EN (0x1 << 15)
+#define RT1016_SIL_DET_EN_BIT 15
+
+/* 0xc2 */
+#define RT1016_CKGEN_DAC (0x1 << 13)
+#define RT1016_CKGEN_DAC_BIT 13
+
+/* 0xc4 */
+#define RT1016_VCM_SLOW (0x1 << 6)
+#define RT1016_VCM_SLOW_BIT 6
+
+/* 0xc5 */
+#define RT1016_PLL_M_MAX 0xf
+#define RT1016_PLL_M_MASK (RT1016_PLL_M_MAX << 12)
+#define RT1016_PLL_M_SFT 12
+#define RT1016_PLL_M_BP (0x1 << 11)
+#define RT1016_PLL_M_BP_SFT 11
+#define RT1016_PLL_N_MAX 0x1ff
+#define RT1016_PLL_N_MASK (RT1016_PLL_N_MAX << 0)
+#define RT1016_PLL_N_SFT 0
+
+/* 0xc6 */
+#define RT1016_PLL2_EN (0x1 << 15)
+#define RT1016_PLL2_EN_BIT 15
+#define RT1016_PLL_K_BP (0x1 << 5)
+#define RT1016_PLL_K_BP_SFT 5
+#define RT1016_PLL_K_MAX 0x1f
+#define RT1016_PLL_K_MASK (RT1016_PLL_K_MAX)
+#define RT1016_PLL_K_SFT 0
+
+/* 0xcf */
+#define RT1016_PWR_BG_1_2 (0x1 << 12)
+#define RT1016_PWR_BG_1_2_BIT 12
+#define RT1016_PWR_MBIAS_BG (0x1 << 11)
+#define RT1016_PWR_MBIAS_BG_BIT 11
+#define RT1016_PWR_PLL (0x1 << 9)
+#define RT1016_PWR_PLL_BIT 9
+#define RT1016_PWR_BASIC (0x1 << 8)
+#define RT1016_PWR_BASIC_BIT 8
+#define RT1016_PWR_CLSD (0x1 << 7)
+#define RT1016_PWR_CLSD_BIT 7
+#define RT1016_PWR_25M (0x1 << 6)
+#define RT1016_PWR_25M_BIT 6
+#define RT1016_PWR_DACL (0x1 << 4)
+#define RT1016_PWR_DACL_BIT 4
+#define RT1016_PWR_DACR (0x1 << 3)
+#define RT1016_PWR_DACR_BIT 3
+#define RT1016_PWR_LDO2 (0x1 << 2)
+#define RT1016_PWR_LDO2_BIT 2
+#define RT1016_PWR_VREF (0x1 << 1)
+#define RT1016_PWR_VREF_BIT 1
+#define RT1016_PWR_MBIAS (0x1 << 0)
+#define RT1016_PWR_MBIAS_BIT 0
+
+/* System Clock Source */
+enum {
+ RT1016_SCLK_S_MCLK,
+ RT1016_SCLK_S_PLL,
+};
+
+/* PLL1 Source */
+enum {
+ RT1016_PLL_S_MCLK,
+ RT1016_PLL_S_BCLK,
+};
+
+enum {
+ RT1016_AIF1,
+ RT1016_AIFS,
+};
+
+struct rt1016_priv {
+ struct snd_soc_component *component;
+ struct regmap *regmap;
+ int sysclk;
+ int sysclk_src;
+ int lrck;
+ int bclk;
+ int master;
+ int pll_src;
+ int pll_in;
+ int pll_out;
+};
+
+#endif /* __RT1016_H__ */
diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c
index a5a7e46de246..1502a22b0d4a 100644
--- a/sound/soc/codecs/rt1308-sdw.c
+++ b/sound/soc/codecs/rt1308-sdw.c
@@ -235,9 +235,9 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave)
efuse_c_btl_r = tmp;
regmap_read(rt1308->regmap, 0xc872, &tmp);
efuse_c_btl_r = efuse_c_btl_r | (tmp << 8);
- dev_info(&slave->dev, "%s m_btl_l=0x%x, m_btl_r=0x%x\n", __func__,
+ dev_dbg(&slave->dev, "%s m_btl_l=0x%x, m_btl_r=0x%x\n", __func__,
efuse_m_btl_l, efuse_m_btl_r);
- dev_info(&slave->dev, "%s c_btl_l=0x%x, c_btl_r=0x%x\n", __func__,
+ dev_dbg(&slave->dev, "%s c_btl_l=0x%x, c_btl_r=0x%x\n", __func__,
efuse_c_btl_l, efuse_c_btl_r);
/* initial settings */
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
index 3f40d2751833..7bfade8b3d6e 100644
--- a/sound/soc/codecs/rt5677-spi.c
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -605,20 +605,15 @@ static int rt5677_spi_probe(struct spi_device *spi)
g_spi = spi;
- ret = snd_soc_register_component(&spi->dev, &rt5677_spi_dai_component,
- &rt5677_spi_dai, 1);
+ ret = devm_snd_soc_register_component(&spi->dev,
+ &rt5677_spi_dai_component,
+ &rt5677_spi_dai, 1);
if (ret < 0)
dev_err(&spi->dev, "Failed to register component.\n");
return ret;
}
-static int rt5677_spi_remove(struct spi_device *spi)
-{
- snd_soc_unregister_component(&spi->dev);
- return 0;
-}
-
static const struct acpi_device_id rt5677_spi_acpi_id[] = {
{ "RT5677AA", 0 },
{ }
@@ -631,7 +626,6 @@ static struct spi_driver rt5677_spi_driver = {
.acpi_match_table = ACPI_PTR(rt5677_spi_acpi_id),
},
.probe = rt5677_spi_probe,
- .remove = rt5677_spi_remove,
};
module_spi_driver(rt5677_spi_driver);
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index d36f560ad7a8..5d3b11756a34 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -806,6 +806,7 @@ static void rt5682_reset(struct rt5682_priv *rt5682)
if (!rt5682->is_sdw)
regmap_write(rt5682->regmap, RT5682_I2C_MODE, 1);
}
+
/**
* rt5682_sel_asrc_clk_src - select ASRC clock source for a set of filters
* @component: SoC audio component device.
@@ -823,7 +824,6 @@ static void rt5682_reset(struct rt5682_priv *rt5682)
int rt5682_sel_asrc_clk_src(struct snd_soc_component *component,
unsigned int filter_mask, unsigned int clk_src)
{
-
switch (clk_src) {
case RT5682_CLK_SEL_SYS:
case RT5682_CLK_SEL_I2S1_ASRC:
@@ -857,7 +857,7 @@ static int rt5682_button_detect(struct snd_soc_component *component)
val = snd_soc_component_read32(component, RT5682_4BTN_IL_CMD_1);
btn_type = val & 0xfff0;
snd_soc_component_write(component, RT5682_4BTN_IL_CMD_1, val);
- pr_debug("%s btn_type=%x\n", __func__, btn_type);
+ dev_dbg(component->dev, "%s btn_type=%x\n", __func__, btn_type);
snd_soc_component_update_bits(component,
RT5682_SAR_IL_CMD_2, 0x10, 0x10);
@@ -918,7 +918,6 @@ static int rt5682_headset_detect(struct snd_soc_component *component,
unsigned int val, count;
if (jack_insert) {
-
snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1,
RT5682_PWR_VREF2 | RT5682_PWR_MB,
RT5682_PWR_VREF2 | RT5682_PWR_MB);
@@ -951,8 +950,8 @@ static int rt5682_headset_detect(struct snd_soc_component *component,
break;
default:
rt5682->jack_type = SND_JACK_HEADPHONE;
+ break;
}
-
} else {
rt5682_enable_push_button_irq(component, false);
snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
@@ -979,7 +978,7 @@ static irqreturn_t rt5682_irq(int irq, void *data)
struct rt5682_priv *rt5682 = data;
mod_delayed_work(system_power_efficient_wq,
- &rt5682->jack_detect_work, msecs_to_jiffies(250));
+ &rt5682->jack_detect_work, msecs_to_jiffies(250));
return IRQ_HANDLED;
}
@@ -995,16 +994,16 @@ static void rt5682_jd_check_handler(struct work_struct *work)
rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
- SND_JACK_HEADSET |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3);
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
} else {
schedule_delayed_work(&rt5682->jd_check_work, 500);
}
}
static int rt5682_set_jack_detect(struct snd_soc_component *component,
- struct snd_soc_jack *hs_jack, void *data)
+ struct snd_soc_jack *hs_jack, void *data)
{
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
@@ -1013,9 +1012,9 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component,
if (!rt5682->is_sdw) {
if (!hs_jack) {
regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
- RT5682_JD1_EN_MASK, RT5682_JD1_DIS);
+ RT5682_JD1_EN_MASK, RT5682_JD1_DIS);
regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL,
- RT5682_POW_JDH | RT5682_POW_JDL, 0);
+ RT5682_POW_JDH | RT5682_POW_JDL, 0);
cancel_delayed_work_sync(&rt5682->jack_detect_work);
return 0;
}
@@ -1058,15 +1057,15 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component,
0x7f7f, (rt5682->pdata.btndet_delay << 8 |
rt5682->pdata.btndet_delay));
mod_delayed_work(system_power_efficient_wq,
- &rt5682->jack_detect_work,
- msecs_to_jiffies(250));
+ &rt5682->jack_detect_work,
+ msecs_to_jiffies(250));
break;
case RT5682_JD_NULL:
regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
RT5682_JD1_EN_MASK, RT5682_JD1_DIS);
regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL,
- RT5682_POW_JDH | RT5682_POW_JDL, 0);
+ RT5682_POW_JDH | RT5682_POW_JDL, 0);
break;
default:
@@ -1135,7 +1134,6 @@ static void rt5682_jack_detect_handler(struct work_struct *work)
case 0x0000: /* unpressed */
break;
default:
- btn_type = 0;
dev_err(rt5682->component->dev,
"Unexpected button code 0x%04x\n",
btn_type);
@@ -1148,9 +1146,9 @@ static void rt5682_jack_detect_handler(struct work_struct *work)
}
snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
- SND_JACK_HEADSET |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3);
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
if (!rt5682->is_sdw) {
if (rt5682->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 |
@@ -1184,15 +1182,14 @@ static const struct snd_kcontrol_new rt5682_snd_controls[] = {
3, 0, adc_bst_tlv),
};
-
static int rt5682_div_sel(struct rt5682_priv *rt5682,
- int target, const int div[], int size)
+ int target, const int div[], int size)
{
int i;
if (rt5682->sysclk < target) {
- pr_err("sysclk rate %d is too low\n",
- rt5682->sysclk);
+ dev_err(rt5682->component->dev,
+ "sysclk rate %d is too low\n", rt5682->sysclk);
return 0;
}
@@ -1201,18 +1198,18 @@ static int rt5682_div_sel(struct rt5682_priv *rt5682,
if (target * div[i] == rt5682->sysclk)
return i;
if (target * div[i + 1] > rt5682->sysclk) {
- dev_dbg(rt5682->component->dev, "can't find div for sysclk %d\n",
+ dev_dbg(rt5682->component->dev,
+ "can't find div for sysclk %d\n",
rt5682->sysclk);
return i;
}
}
if (target * div[i] < rt5682->sysclk)
- pr_err("sysclk rate %d is too high\n",
- rt5682->sysclk);
+ dev_err(rt5682->component->dev,
+ "sysclk rate %d is too high\n", rt5682->sysclk);
return size - 1;
-
}
/**
@@ -1226,7 +1223,7 @@ static int rt5682_div_sel(struct rt5682_priv *rt5682,
* It is better for clock to approximate 3MHz.
*/
static int set_dmic_clk(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
@@ -1246,7 +1243,7 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
}
static int set_filter_clk(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
@@ -1290,7 +1287,7 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w,
}
static int is_sys_clk_from_pll1(struct snd_soc_dapm_widget *w,
- struct snd_soc_dapm_widget *sink)
+ struct snd_soc_dapm_widget *sink)
{
unsigned int val;
struct snd_soc_component *component =
@@ -1305,7 +1302,7 @@ static int is_sys_clk_from_pll1(struct snd_soc_dapm_widget *w,
}
static int is_sys_clk_from_pll2(struct snd_soc_dapm_widget *w,
- struct snd_soc_dapm_widget *sink)
+ struct snd_soc_dapm_widget *sink)
{
unsigned int val;
struct snd_soc_component *component =
@@ -1320,7 +1317,7 @@ static int is_sys_clk_from_pll2(struct snd_soc_dapm_widget *w,
}
static int is_using_asrc(struct snd_soc_dapm_widget *w,
- struct snd_soc_dapm_widget *sink)
+ struct snd_soc_dapm_widget *sink)
{
unsigned int reg, shift, val;
struct snd_soc_component *component =
@@ -1347,7 +1344,6 @@ static int is_using_asrc(struct snd_soc_dapm_widget *w,
default:
return 0;
}
-
}
/* Digital Mixer */
@@ -1501,13 +1497,13 @@ static const struct snd_kcontrol_new rt5682_alg_dac_r1_mux =
/* Out Switch */
static const struct snd_kcontrol_new hpol_switch =
SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1,
- RT5682_L_MUTE_SFT, 1, 1);
+ RT5682_L_MUTE_SFT, 1, 1);
static const struct snd_kcontrol_new hpor_switch =
SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1,
- RT5682_R_MUTE_SFT, 1, 1);
+ RT5682_R_MUTE_SFT, 1, 1);
static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
@@ -1532,17 +1528,13 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(component,
RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0000);
break;
-
- default:
- return 0;
}
return 0;
-
}
static int set_dmic_power(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
@@ -1557,16 +1549,13 @@ static int set_dmic_power(struct snd_soc_dapm_widget *w,
/*Add delay to avoid pop noise*/
msleep(delay);
break;
-
- default:
- return 0;
}
return 0;
}
static int rt5682_set_verf(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
@@ -1583,9 +1572,6 @@ static int rt5682_set_verf(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(component,
RT5682_PWR_ANLG_1, RT5682_PWR_FV2, 0);
break;
-
- default:
- break;
}
break;
@@ -1603,14 +1589,8 @@ static int rt5682_set_verf(struct snd_soc_dapm_widget *w,
RT5682_PWR_ANLG_1, RT5682_PWR_FV2,
RT5682_PWR_FV2);
break;
-
- default:
- break;
}
break;
-
- default:
- return 0;
}
return 0;
@@ -1743,23 +1723,23 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = {
/* Digital Interface Select */
SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
- &rt5682_if1_01_adc_swap_mux),
+ &rt5682_if1_01_adc_swap_mux),
SND_SOC_DAPM_MUX("IF1 23 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
- &rt5682_if1_23_adc_swap_mux),
+ &rt5682_if1_23_adc_swap_mux),
SND_SOC_DAPM_MUX("IF1 45 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
- &rt5682_if1_45_adc_swap_mux),
+ &rt5682_if1_45_adc_swap_mux),
SND_SOC_DAPM_MUX("IF1 67 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
- &rt5682_if1_67_adc_swap_mux),
+ &rt5682_if1_67_adc_swap_mux),
SND_SOC_DAPM_MUX("IF2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
- &rt5682_if2_adc_swap_mux),
+ &rt5682_if2_adc_swap_mux),
SND_SOC_DAPM_MUX("ADCDAT Mux", SND_SOC_NOPM, 0, 0,
- &rt5682_adcdat_pin_ctrl),
+ &rt5682_adcdat_pin_ctrl),
SND_SOC_DAPM_MUX("DAC L Mux", SND_SOC_NOPM, 0, 0,
- &rt5682_dac_l_mux),
+ &rt5682_dac_l_mux),
SND_SOC_DAPM_MUX("DAC R Mux", SND_SOC_NOPM, 0, 0,
- &rt5682_dac_r_mux),
+ &rt5682_dac_r_mux),
/* Audio Interface */
SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0,
@@ -1831,7 +1811,6 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = {
/* Output Lines */
SND_SOC_DAPM_OUTPUT("HPOL"),
SND_SOC_DAPM_OUTPUT("HPOR"),
-
};
static const struct snd_soc_dapm_route rt5682_dapm_routes[] = {
@@ -1997,7 +1976,7 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = {
};
static int rt5682_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
- unsigned int rx_mask, int slots, int slot_width)
+ unsigned int rx_mask, int slots, int slot_width)
{
struct snd_soc_component *component = dai->component;
unsigned int cl, val = 0;
@@ -2065,9 +2044,8 @@ static int rt5682_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
return 0;
}
-
static int rt5682_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
@@ -2085,7 +2063,7 @@ static int rt5682_hw_params(struct snd_pcm_substream *substream,
}
dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
- rt5682->lrck[dai->id], pre_div, dai->id);
+ rt5682->lrck[dai->id], pre_div, dai->id);
switch (params_width(params)) {
case 16:
@@ -2469,7 +2447,7 @@ static int rt5682_set_bclk2_ratio(struct snd_soc_dai *dai, unsigned int ratio)
}
static int rt5682_set_bias_level(struct snd_soc_component *component,
- enum snd_soc_bias_level level)
+ enum snd_soc_bias_level level)
{
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
@@ -2492,8 +2470,7 @@ static int rt5682_set_bias_level(struct snd_soc_component *component,
regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
RT5682_PWR_BG, 0);
break;
-
- default:
+ case SND_SOC_BIAS_ON:
break;
}
@@ -2667,7 +2644,7 @@ static unsigned long rt5682_bclk_recalc_rate(struct clk_hw *hw,
unsigned int bclks_per_wclk;
snd_soc_component_read(component, RT5682_TDM_TCON_CTRL,
- &bclks_per_wclk);
+ &bclks_per_wclk);
switch (bclks_per_wclk & RT5682_TDM_BCLK_MS1_MASK) {
case RT5682_TDM_BCLK_MS1_256:
@@ -2954,7 +2931,7 @@ struct sdw_stream_data {
};
static int rt5682_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
- int direction)
+ int direction)
{
struct sdw_stream_data *stream;
@@ -2997,8 +2974,8 @@ static int rt5682_sdw_hw_params(struct snd_pcm_substream *substream,
unsigned int val_p = 0, val_c = 0, osr_p = 0, osr_c = 0;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
- stream = snd_soc_dai_get_dma_data(dai, substream);
+ stream = snd_soc_dai_get_dma_data(dai, substream);
if (!stream)
return -ENOMEM;
@@ -3114,7 +3091,7 @@ static int rt5682_sdw_hw_params(struct snd_pcm_substream *substream,
}
static int rt5682_sdw_hw_free(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
@@ -3296,7 +3273,7 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682)
}
if (count >= 60)
- pr_err("HP Calibration Failure\n");
+ dev_err(rt5682->component->dev, "HP Calibration Failure\n");
/* restore settings */
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0x02af);
@@ -3308,7 +3285,6 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682)
regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4);
mutex_unlock(&rt5682->calibrate_mutex);
-
}
#if IS_ENABLED(CONFIG_SND_SOC_RT5682_SDW)
@@ -3363,7 +3339,7 @@ static const struct regmap_config rt5682_sdw_regmap = {
};
int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
- struct sdw_slave *slave)
+ struct sdw_slave *slave)
{
struct rt5682_priv *rt5682;
int ret;
@@ -3416,7 +3392,7 @@ int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
if (val != DEVICE_ID) {
- pr_err("Device with ID register %x is not rt5682\n", val);
+ dev_err(dev, "Device with ID register %x is not rt5682\n", val);
return -ENODEV;
}
@@ -3439,8 +3415,6 @@ int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
pm_runtime_get_noresume(&slave->dev);
- rt5682_reset(rt5682);
-
if (rt5682->first_hw_init) {
regcache_cache_only(rt5682->regmap, false);
regcache_cache_bypass(rt5682->regmap, true);
@@ -3461,23 +3435,23 @@ int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
}
ret = regmap_multi_reg_write(rt5682->regmap, patch_list,
- ARRAY_SIZE(patch_list));
- if (ret != 0)
+ ARRAY_SIZE(patch_list));
+ if (ret)
dev_warn(dev, "Failed to apply regmap patch: %d\n", ret);
regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0000);
regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
- RT5682_LDO1_DVO_MASK | RT5682_HP_DRIVER_MASK,
- RT5682_LDO1_DVO_12 | RT5682_HP_DRIVER_5X);
+ RT5682_LDO1_DVO_MASK | RT5682_HP_DRIVER_MASK,
+ RT5682_LDO1_DVO_12 | RT5682_HP_DRIVER_5X);
regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
regmap_update_bits(rt5682->regmap, RT5682_BIAS_CUR_CTRL_8,
- RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA);
+ RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA);
regmap_update_bits(rt5682->regmap, RT5682_CHARGE_PUMP_1,
- RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ);
+ RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ);
regmap_update_bits(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1,
- RT5682_PM_HP_MASK, RT5682_PM_HP_HV);
+ RT5682_PM_HP_MASK, RT5682_PM_HP_HV);
/* Soundwire */
regmap_write(rt5682->regmap, RT5682_PLL2_INTERNAL, 0xa266);
@@ -3499,9 +3473,9 @@ int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
regmap_update_bits(rt5682->regmap, RT5682_SAR_IL_CMD_1,
RT5682_SAR_POW_MASK, RT5682_SAR_POW_EN);
regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL,
- RT5682_POW_IRQ | RT5682_POW_JDH |
- RT5682_POW_ANA, RT5682_POW_IRQ |
- RT5682_POW_JDH | RT5682_POW_ANA);
+ RT5682_POW_IRQ | RT5682_POW_JDH |
+ RT5682_POW_ANA, RT5682_POW_IRQ |
+ RT5682_POW_JDH | RT5682_POW_ANA);
regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_2,
RT5682_PWR_JDH, RT5682_PWR_JDH);
regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
@@ -3510,7 +3484,7 @@ int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
reinit:
mod_delayed_work(system_power_efficient_wq,
- &rt5682->jack_detect_work, msecs_to_jiffies(250));
+ &rt5682->jack_detect_work, msecs_to_jiffies(250));
/* Mark Slave initialization complete */
rt5682->hw_init = true;
@@ -3527,7 +3501,7 @@ EXPORT_SYMBOL_GPL(rt5682_io_init);
#endif
static int rt5682_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
struct rt5682_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt5682_priv *rt5682;
@@ -3536,8 +3510,7 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
rt5682 = devm_kzalloc(&i2c->dev, sizeof(struct rt5682_priv),
GFP_KERNEL);
-
- if (rt5682 == NULL)
+ if (!rt5682)
return -ENOMEM;
i2c_set_clientdata(i2c, rt5682);
@@ -3562,14 +3535,14 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5682->supplies),
rt5682->supplies);
- if (ret != 0) {
+ if (ret) {
dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(rt5682->supplies),
rt5682->supplies);
- if (ret != 0) {
+ if (ret) {
dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
return ret;
}
@@ -3588,18 +3561,17 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
if (val != DEVICE_ID) {
- pr_err("Device with ID register %x is not rt5682\n", val);
+ dev_err(&i2c->dev,
+ "Device with ID register %x is not rt5682\n", val);
return -ENODEV;
}
- rt5682_reset(rt5682);
-
mutex_init(&rt5682->calibrate_mutex);
rt5682_calibrate(rt5682);
ret = regmap_multi_reg_write(rt5682->regmap, patch_list,
- ARRAY_SIZE(patch_list));
- if (ret != 0)
+ ARRAY_SIZE(patch_list));
+ if (ret)
dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0000);
@@ -3644,27 +3616,26 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
}
regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
- RT5682_LDO1_DVO_MASK | RT5682_HP_DRIVER_MASK,
- RT5682_LDO1_DVO_12 | RT5682_HP_DRIVER_5X);
+ RT5682_LDO1_DVO_MASK | RT5682_HP_DRIVER_MASK,
+ RT5682_LDO1_DVO_12 | RT5682_HP_DRIVER_5X);
regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
- RT5682_GP4_PIN_MASK | RT5682_GP5_PIN_MASK,
- RT5682_GP4_PIN_ADCDAT1 | RT5682_GP5_PIN_DACDAT1);
+ RT5682_GP4_PIN_MASK | RT5682_GP5_PIN_MASK,
+ RT5682_GP4_PIN_ADCDAT1 | RT5682_GP5_PIN_DACDAT1);
regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
regmap_update_bits(rt5682->regmap, RT5682_BIAS_CUR_CTRL_8,
- RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA);
+ RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA);
regmap_update_bits(rt5682->regmap, RT5682_CHARGE_PUMP_1,
- RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ);
+ RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ);
regmap_update_bits(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1,
- RT5682_PM_HP_MASK, RT5682_PM_HP_HV);
+ RT5682_PM_HP_MASK, RT5682_PM_HP_HV);
regmap_update_bits(rt5682->regmap, RT5682_DMIC_CTRL_1,
- RT5682_FIFO_CLK_DIV_MASK, RT5682_FIFO_CLK_DIV_2);
+ RT5682_FIFO_CLK_DIV_MASK, RT5682_FIFO_CLK_DIV_2);
INIT_DELAYED_WORK(&rt5682->jack_detect_work,
- rt5682_jack_detect_handler);
+ rt5682_jack_detect_handler);
INIT_DELAYED_WORK(&rt5682->jd_check_work,
- rt5682_jd_check_handler);
-
+ rt5682_jd_check_handler);
if (i2c->irq) {
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
@@ -3672,12 +3643,11 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
| IRQF_ONESHOT, "rt5682", rt5682);
if (ret)
dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
-
}
return devm_snd_soc_register_component(&i2c->dev,
- &soc_component_dev_rt5682,
- rt5682_dai, ARRAY_SIZE(rt5682_dai));
+ &soc_component_dev_rt5682,
+ rt5682_dai, ARRAY_SIZE(rt5682_dai));
}
static void rt5682_i2c_shutdown(struct i2c_client *client)
diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c
index 1d7d7b34a46e..472d759ba8a3 100644
--- a/sound/soc/codecs/tlv320adcx140.c
+++ b/sound/soc/codecs/tlv320adcx140.c
@@ -180,6 +180,17 @@ static const struct snd_kcontrol_new decimation_filter_controls[] = {
SOC_DAPM_ENUM("Decimation Filter", decimation_filter_enum),
};
+static const char * const pdmclk_text[] = {
+ "2.8224 MHz", "1.4112 MHz", "705.6 kHz", "5.6448 MHz"
+};
+
+static SOC_ENUM_SINGLE_DECL(pdmclk_select_enum, ADCX140_PDMCLK_CFG, 0,
+ pdmclk_text);
+
+static const struct snd_kcontrol_new pdmclk_div_controls[] = {
+ SOC_DAPM_ENUM("PDM Clk Divider Select", pdmclk_select_enum),
+};
+
static const char * const resistor_text[] = {
"2.5 kOhm", "10 kOhm", "20 kOhm"
};
@@ -416,6 +427,9 @@ static const struct snd_soc_dapm_widget adcx140_dapm_widgets[] = {
SND_SOC_DAPM_MUX("IN4 Analog Mic Resistor", SND_SOC_NOPM, 0, 0,
in4_resistor_controls),
+ SND_SOC_DAPM_MUX("PDM Clk Div Select", SND_SOC_NOPM, 0, 0,
+ pdmclk_div_controls),
+
SND_SOC_DAPM_MUX("Decimation Filter", SND_SOC_NOPM, 0, 0,
decimation_filter_controls),
};
@@ -493,6 +507,11 @@ static const struct snd_soc_dapm_route adcx140_audio_map[] = {
{"IN4 Analog Mic Resistor", "10 kOhm", "MIC4M Input Mux"},
{"IN4 Analog Mic Resistor", "20 kOhm", "MIC4M Input Mux"},
+ {"PDM Clk Div Select", "2.8224 MHz", "MIC1P Input Mux"},
+ {"PDM Clk Div Select", "1.4112 MHz", "MIC1P Input Mux"},
+ {"PDM Clk Div Select", "705.6 kHz", "MIC1P Input Mux"},
+ {"PDM Clk Div Select", "5.6448 MHz", "MIC1P Input Mux"},
+
{"MIC1 Analog Mux", "Line In", "MIC1P"},
{"MIC2 Analog Mux", "Line In", "MIC2P"},
{"MIC3 Analog Mux", "Line In", "MIC3P"},
@@ -742,6 +761,10 @@ static int adcx140_codec_probe(struct snd_soc_component *component)
u32 bias_source;
u32 vref_source;
u8 bias_cfg;
+ int pdm_count;
+ u32 pdm_edges[ADCX140_NUM_PDM_EDGES];
+ u32 pdm_edge_val = 0;
+ int i;
int ret;
ret = device_property_read_u32(adcx140->dev, "ti,mic-bias-source",
@@ -768,6 +791,24 @@ static int adcx140_codec_probe(struct snd_soc_component *component)
bias_cfg = bias_source << ADCX140_MIC_BIAS_SHIFT | vref_source;
+ pdm_count = device_property_count_u32(adcx140->dev,
+ "ti,pdm-edge-select");
+ if (pdm_count <= ADCX140_NUM_PDM_EDGES && pdm_count > 0) {
+ ret = device_property_read_u32_array(adcx140->dev,
+ "ti,pdm-edge-select",
+ pdm_edges, pdm_count);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < pdm_count; i++)
+ pdm_edge_val |= pdm_edges[i] << (ADCX140_PDM_EDGE_SHIFT - i);
+
+ ret = regmap_write(adcx140->regmap, ADCX140_PDM_CFG,
+ pdm_edge_val);
+ if (ret)
+ return ret;
+ }
+
ret = adcx140_reset(adcx140);
if (ret)
goto out;
diff --git a/sound/soc/codecs/tlv320adcx140.h b/sound/soc/codecs/tlv320adcx140.h
index 69de52d473f4..247827f315f1 100644
--- a/sound/soc/codecs/tlv320adcx140.h
+++ b/sound/soc/codecs/tlv320adcx140.h
@@ -129,4 +129,7 @@
#define ADCX140_TX_OFFSET_MASK GENMASK(4, 0)
+#define ADCX140_NUM_PDM_EDGES 4
+#define ADCX140_PDM_EDGE_SHIFT 7
+
#endif /* _TLV320ADCX140_ */
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 700cc1212770..fb073f4dc7ed 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -1919,7 +1919,7 @@ static int wcd9335_hw_params(struct snd_pcm_substream *substream,
__func__, params_rate(params));
return -EINVAL;
- };
+ }
ret = wcd9335_set_decimator_rate(dai, tx_fs_rate,
params_rate(params));
@@ -1935,13 +1935,13 @@ static int wcd9335_hw_params(struct snd_pcm_substream *substream,
dev_err(wcd->dev, "%s: Invalid format 0x%x\n",
__func__, params_width(params));
return -EINVAL;
- };
+ }
break;
default:
dev_err(wcd->dev, "Invalid stream type %d\n",
substream->stream);
return -EINVAL;
- };
+ }
wcd->dai[dai->id].sconfig.rate = params_rate(params);
wcd9335_slim_set_hw_params(wcd, &wcd->dai[dai->id], substream->stream);
@@ -2216,7 +2216,7 @@ static int wcd9335_set_compander(struct snd_kcontrol *kc,
break;
default:
break;
- };
+ }
return 0;
}
@@ -2565,7 +2565,7 @@ static int wcd9335_micbias_control(struct snd_soc_component *component,
0xC0, 0x00);
}
break;
- };
+ }
return 0;
}
@@ -2603,7 +2603,7 @@ static int __wcd9335_codec_enable_micbias(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMD:
wcd9335_micbias_control(comp, micb_num, MICB_DISABLE, true);
break;
- };
+ }
return 0;
}
@@ -2846,7 +2846,7 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMD:
snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x00);
break;
- };
+ }
out:
kfree(wname);
return ret;
@@ -2952,7 +2952,7 @@ static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w,
dev_err(comp->dev, "%s: Invalid DMIC Selection\n",
__func__);
return -EINVAL;
- };
+ }
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -2985,7 +2985,7 @@ static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w,
dmic_rate_val << dmic_rate_shift);
}
break;
- };
+ }
return 0;
}
@@ -3076,7 +3076,7 @@ static int wcd9335_codec_enable_mix_path(struct snd_soc_dapm_widget *w,
dev_err(comp->dev, "%s: No gain register avail for %s\n",
__func__, w->name);
return 0;
- };
+ }
switch (event) {
case SND_SOC_DAPM_POST_PMU:
@@ -3086,7 +3086,7 @@ static int wcd9335_codec_enable_mix_path(struct snd_soc_dapm_widget *w,
break;
case SND_SOC_DAPM_POST_PMD:
break;
- };
+ }
return 0;
}
@@ -3141,7 +3141,7 @@ static u16 wcd9335_interp_get_primary_reg(u16 reg, u16 *ind)
prim_int_reg = WCD9335_CDC_RX8_RX_PATH_CTL;
*ind = 8;
break;
- };
+ }
return prim_int_reg;
}
@@ -3229,7 +3229,7 @@ static int wcd9335_codec_enable_prim_interpolator(
wcd9335_codec_hd2_control(comp, prim_int_reg, event);
}
break;
- };
+ }
return 0;
}
@@ -3352,7 +3352,7 @@ static int wcd9335_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
wcd9335_config_compander(comp, w->shift, event);
wcd9335_codec_enable_prim_interpolator(comp, reg, event);
break;
- };
+ }
return 0;
}
@@ -3575,7 +3575,7 @@ static int wcd9335_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
((hph_mode == CLS_H_LOHIFI) ?
CLS_H_HIFI : hph_mode));
break;
- };
+ }
return 0;
}
@@ -3616,7 +3616,7 @@ static int wcd9335_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA,
WCD_CLSH_STATE_EAR, CLS_H_NORMAL);
break;
- };
+ }
return 0;
}
@@ -3725,7 +3725,7 @@ static int wcd9335_codec_hphr_dac_event(struct snd_soc_dapm_widget *w,
WCD_CLSH_STATE_HPHR, ((hph_mode == CLS_H_LOHIFI) ?
CLS_H_HIFI : hph_mode));
break;
- };
+ }
return 0;
}
@@ -3773,7 +3773,7 @@ static int wcd9335_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
*/
usleep_range(5000, 5500);
break;
- };
+ }
return 0;
}
@@ -3829,7 +3829,7 @@ static int wcd9335_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w,
*/
usleep_range(5000, 5500);
break;
- };
+ }
return 0;
}
@@ -3875,7 +3875,7 @@ static int wcd9335_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
WCD9335_ANA_RX_BIAS_ENABLE_MASK,
WCD9335_ANA_RX_BIAS_DISABLE);
break;
- };
+ }
return 0;
}
@@ -3921,7 +3921,7 @@ static int wcd9335_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
*/
usleep_range(5000, 5500);
break;
- };
+ }
return 0;
}
@@ -3957,7 +3957,7 @@ static int wcd9335_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
usleep_range(5000, 5500);
break;
- };
+ }
return 0;
}
diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c
index 5269857e2746..531b8b79e55f 100644
--- a/sound/soc/codecs/wcd934x.c
+++ b/sound/soc/codecs/wcd934x.c
@@ -1787,7 +1787,7 @@ static int wcd934x_hw_params(struct snd_pcm_substream *substream,
params_rate(params));
return -EINVAL;
- };
+ }
ret = wcd934x_set_decimator_rate(dai, tx_fs_rate,
params_rate(params));
@@ -1803,13 +1803,13 @@ static int wcd934x_hw_params(struct snd_pcm_substream *substream,
dev_err(wcd->dev, "Invalid format 0x%x\n",
params_width(params));
return -EINVAL;
- };
+ }
break;
default:
dev_err(wcd->dev, "Invalid stream type %d\n",
substream->stream);
return -EINVAL;
- };
+ }
wcd->dai[dai->id].sconfig.rate = params_rate(params);
wcd934x_slim_set_hw_params(wcd, &wcd->dai[dai->id], substream->stream);
@@ -2489,7 +2489,7 @@ static int wcd934x_compander_set(struct snd_kcontrol *kc,
break;
default:
break;
- };
+ }
return 0;
}
@@ -3539,7 +3539,7 @@ static int wcd934x_codec_enable_mix_path(struct snd_soc_dapm_widget *w,
val += offset_val;
snd_soc_component_write(comp, gain_reg, val);
break;
- };
+ }
return 0;
}
@@ -3593,7 +3593,7 @@ static int wcd934x_codec_enable_main_path(struct snd_soc_dapm_widget *w,
snd_soc_component_write(comp, gain_reg,
snd_soc_component_read32(comp, gain_reg));
break;
- };
+ }
return 0;
}
@@ -3618,7 +3618,7 @@ static int wcd934x_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA,
WCD_CLSH_STATE_EAR, CLS_H_NORMAL);
break;
- };
+ }
return 0;
}
@@ -3670,7 +3670,7 @@ static int wcd934x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
break;
default:
break;
- };
+ }
return 0;
}
@@ -3720,7 +3720,7 @@ static int wcd934x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w,
break;
default:
break;
- };
+ }
return 0;
}
@@ -3801,7 +3801,7 @@ static int wcd934x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
*/
usleep_range(20000, 20100);
break;
- };
+ }
return 0;
}
@@ -3863,7 +3863,7 @@ static int wcd934x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
*/
usleep_range(20000, 20100);
break;
- };
+ }
return 0;
}
@@ -3878,7 +3878,7 @@ static u32 wcd934x_get_dmic_sample_rate(struct snd_soc_component *comp,
u16 adc_mux_ctl_reg, tx_fs_reg;
u32 dmic_fs;
- while (dec_found == 0 && adc_mux_index < WCD934X_MAX_VALID_ADC_MUX) {
+ while (!dec_found && adc_mux_index < WCD934X_MAX_VALID_ADC_MUX) {
if (adc_mux_index < 4) {
adc_mux_ctl_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 +
(adc_mux_index * 2);
@@ -4015,7 +4015,7 @@ static int wcd934x_codec_enable_dmic(struct snd_soc_dapm_widget *w,
dev_err(comp->dev, "%s: Invalid DMIC Selection\n",
__func__);
return -EINVAL;
- };
+ }
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -4040,7 +4040,7 @@ static int wcd934x_codec_enable_dmic(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(comp, dmic_clk_reg,
dmic_clk_en, 0);
break;
- };
+ }
return 0;
}
@@ -4267,7 +4267,7 @@ static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w,
WCD934X_DEC_PWR_LVL_MASK,
WCD934X_DEC_PWR_LVL_DF);
break;
- };
+ }
out:
kfree(wname);
return ret;
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index d6d4b4121369..2ed3fa67027d 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -1909,10 +1909,9 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
},
};
-static int wm5102_open(struct snd_compr_stream *stream)
+static int wm5102_open(struct snd_soc_component *component,
+ struct snd_compr_stream *stream)
{
- struct snd_soc_pcm_runtime *rtd = stream->private_data;
- struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct wm5102_priv *priv = snd_soc_component_get_drvdata(component);
return wm_adsp_compr_open(&priv->core.adsp[0], stream);
@@ -1992,7 +1991,7 @@ static unsigned int wm5102_digital_vu[] = {
ARIZONA_DAC_DIGITAL_VOLUME_5R,
};
-static struct snd_compr_ops wm5102_compr_ops = {
+static struct snd_compress_ops wm5102_compress_ops = {
.open = wm5102_open,
.free = wm_adsp_compr_free,
.set_params = wm_adsp_compr_set_params,
@@ -2008,7 +2007,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm5102 = {
.set_sysclk = arizona_set_sysclk,
.set_pll = wm5102_set_fll,
.name = DRV_NAME,
- .compr_ops = &wm5102_compr_ops,
+ .compress_ops = &wm5102_compress_ops,
.controls = wm5102_snd_controls,
.num_controls = ARRAY_SIZE(wm5102_snd_controls),
.dapm_widgets = wm5102_dapm_widgets,
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 499e87d1dfcc..44de44bff423 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -2237,10 +2237,10 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
},
};
-static int wm5110_open(struct snd_compr_stream *stream)
+static int wm5110_open(struct snd_soc_component *component,
+ struct snd_compr_stream *stream)
{
struct snd_soc_pcm_runtime *rtd = stream->private_data;
- struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct wm5110_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->core.arizona;
int n_adsp;
@@ -2355,7 +2355,7 @@ static unsigned int wm5110_digital_vu[] = {
ARIZONA_DAC_DIGITAL_VOLUME_6R,
};
-static struct snd_compr_ops wm5110_compr_ops = {
+static struct snd_compress_ops wm5110_compress_ops = {
.open = wm5110_open,
.free = wm_adsp_compr_free,
.set_params = wm_adsp_compr_set_params,
@@ -2371,7 +2371,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm5110 = {
.set_sysclk = arizona_set_sysclk,
.set_pll = wm5110_set_fll,
.name = DRV_NAME,
- .compr_ops = &wm5110_compr_ops,
+ .compress_ops = &wm5110_compress_ops,
.controls = wm5110_snd_controls,
.num_controls = ARRAY_SIZE(wm5110_snd_controls),
.dapm_widgets = wm5110_dapm_widgets,
diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c
index 91e3d1570c45..4e9ab542f648 100644
--- a/sound/soc/codecs/wm8524.c
+++ b/sound/soc/codecs/wm8524.c
@@ -159,7 +159,9 @@ static int wm8524_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
#define WM8524_RATES SNDRV_PCM_RATE_8000_192000
-#define WM8524_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+#define WM8524_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops wm8524_dai_ops = {
.startup = wm8524_startup,
diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c
index aa5577e364d0..f89855c616eb 100644
--- a/sound/soc/codecs/wm8782.c
+++ b/sound/soc/codecs/wm8782.c
@@ -7,7 +7,7 @@
* Author: Johannes Stezenbach <[email protected]>
*
* based on ad73311.c
- * Copyright: Analog Device Inc.
+ * Copyright: Analog Devices Inc.
* Author: Cliff Cai <[email protected]>
*/
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 271235a69c01..3e239fa9bc8d 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -443,12 +443,6 @@ SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1,
};
-static const struct snd_kcontrol_new wm8900_dapm_loutput2_control =
-SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0);
-
-static const struct snd_kcontrol_new wm8900_dapm_routput2_control =
-SOC_DAPM_SINGLE("LINEOUT2R Switch", WM8900_REG_POWER3, 5, 1, 0);
-
static const struct snd_kcontrol_new wm8900_loutmix_controls[] = {
SOC_DAPM_SINGLE("LINPUT3 Bypass Switch", WM8900_REG_LOUTMIXCTL1, 7, 1, 0),
SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 7, 1, 0),
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index cfe7892696dd..499a29b47d5e 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -32,93 +32,14 @@ struct wm8990_priv {
unsigned int pcmclk;
};
-static bool wm8990_volatile_register(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case WM8990_RESET:
- return true;
- default:
- return false;
- }
-}
-
-static const struct reg_default wm8990_reg_defaults[] = {
- { 1, 0x0000 }, /* R1 - Power Management (1) */
- { 2, 0x6000 }, /* R2 - Power Management (2) */
- { 3, 0x0000 }, /* R3 - Power Management (3) */
- { 4, 0x4050 }, /* R4 - Audio Interface (1) */
- { 5, 0x4000 }, /* R5 - Audio Interface (2) */
- { 6, 0x01C8 }, /* R6 - Clocking (1) */
- { 7, 0x0000 }, /* R7 - Clocking (2) */
- { 8, 0x0040 }, /* R8 - Audio Interface (3) */
- { 9, 0x0040 }, /* R9 - Audio Interface (4) */
- { 10, 0x0004 }, /* R10 - DAC CTRL */
- { 11, 0x00C0 }, /* R11 - Left DAC Digital Volume */
- { 12, 0x00C0 }, /* R12 - Right DAC Digital Volume */
- { 13, 0x0000 }, /* R13 - Digital Side Tone */
- { 14, 0x0100 }, /* R14 - ADC CTRL */
- { 15, 0x00C0 }, /* R15 - Left ADC Digital Volume */
- { 16, 0x00C0 }, /* R16 - Right ADC Digital Volume */
-
- { 18, 0x0000 }, /* R18 - GPIO CTRL 1 */
- { 19, 0x1000 }, /* R19 - GPIO1 & GPIO2 */
- { 20, 0x1010 }, /* R20 - GPIO3 & GPIO4 */
- { 21, 0x1010 }, /* R21 - GPIO5 & GPIO6 */
- { 22, 0x8000 }, /* R22 - GPIOCTRL 2 */
- { 23, 0x0800 }, /* R23 - GPIO_POL */
- { 24, 0x008B }, /* R24 - Left Line Input 1&2 Volume */
- { 25, 0x008B }, /* R25 - Left Line Input 3&4 Volume */
- { 26, 0x008B }, /* R26 - Right Line Input 1&2 Volume */
- { 27, 0x008B }, /* R27 - Right Line Input 3&4 Volume */
- { 28, 0x0000 }, /* R28 - Left Output Volume */
- { 29, 0x0000 }, /* R29 - Right Output Volume */
- { 30, 0x0066 }, /* R30 - Line Outputs Volume */
- { 31, 0x0022 }, /* R31 - Out3/4 Volume */
- { 32, 0x0079 }, /* R32 - Left OPGA Volume */
- { 33, 0x0079 }, /* R33 - Right OPGA Volume */
- { 34, 0x0003 }, /* R34 - Speaker Volume */
- { 35, 0x0003 }, /* R35 - ClassD1 */
-
- { 37, 0x0100 }, /* R37 - ClassD3 */
- { 38, 0x0079 }, /* R38 - ClassD4 */
- { 39, 0x0000 }, /* R39 - Input Mixer1 */
- { 40, 0x0000 }, /* R40 - Input Mixer2 */
- { 41, 0x0000 }, /* R41 - Input Mixer3 */
- { 42, 0x0000 }, /* R42 - Input Mixer4 */
- { 43, 0x0000 }, /* R43 - Input Mixer5 */
- { 44, 0x0000 }, /* R44 - Input Mixer6 */
- { 45, 0x0000 }, /* R45 - Output Mixer1 */
- { 46, 0x0000 }, /* R46 - Output Mixer2 */
- { 47, 0x0000 }, /* R47 - Output Mixer3 */
- { 48, 0x0000 }, /* R48 - Output Mixer4 */
- { 49, 0x0000 }, /* R49 - Output Mixer5 */
- { 50, 0x0000 }, /* R50 - Output Mixer6 */
- { 51, 0x0180 }, /* R51 - Out3/4 Mixer */
- { 52, 0x0000 }, /* R52 - Line Mixer1 */
- { 53, 0x0000 }, /* R53 - Line Mixer2 */
- { 54, 0x0000 }, /* R54 - Speaker Mixer */
- { 55, 0x0000 }, /* R55 - Additional Control */
- { 56, 0x0000 }, /* R56 - AntiPOP1 */
- { 57, 0x0000 }, /* R57 - AntiPOP2 */
- { 58, 0x0000 }, /* R58 - MICBIAS */
-
- { 60, 0x0008 }, /* R60 - PLL1 */
- { 61, 0x0031 }, /* R61 - PLL2 */
- { 62, 0x0026 }, /* R62 - PLL3 */
-};
-
#define wm8990_reset(c) snd_soc_component_write(c, WM8990_RESET, 0)
-static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 600, 0);
-
static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1650, 3000, 0);
static const DECLARE_TLV_DB_SCALE(out_mix_tlv, 0, -2100, 0);
static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -7300, 600, 0);
-static const DECLARE_TLV_DB_SCALE(out_omix_tlv, -600, 0, 0);
-
static const DECLARE_TLV_DB_SCALE(out_dac_tlv, -7163, 0, 0);
static const DECLARE_TLV_DB_SCALE(in_adc_tlv, -7163, 1763, 0);
@@ -486,14 +407,6 @@ static SOC_ENUM_SINGLE_DECL(wm8990_ainrmux_enum,
static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls =
SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum);
-/* RXVOICE */
-static const struct snd_kcontrol_new wm8990_dapm_rxvoice_controls[] = {
-SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8990_INPUT_MIXER5, WM8990_LR4BVOL_SHIFT,
- WM8990_LR4BVOL_MASK, 0, in_mix_tlv),
-SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8990_INPUT_MIXER6, WM8990_RL4BVOL_SHIFT,
- WM8990_RL4BVOL_MASK, 0, in_mix_tlv),
-};
-
/* LOMIX */
static const struct snd_kcontrol_new wm8990_dapm_lomix_controls[] = {
SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER1,
@@ -1306,17 +1219,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8990 = {
.non_legacy_dai_naming = 1,
};
-static const struct regmap_config wm8990_regmap = {
- .reg_bits = 8,
- .val_bits = 16,
-
- .max_register = WM8990_PLL3,
- .volatile_reg = wm8990_volatile_register,
- .reg_defaults = wm8990_reg_defaults,
- .num_reg_defaults = ARRAY_SIZE(wm8990_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
-};
-
static int wm8990_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index 93c156782d59..f8375d67e901 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -476,14 +476,6 @@ static SOC_ENUM_SINGLE_DECL(wm8991_ainrmux_enum,
static const struct snd_kcontrol_new wm8991_dapm_ainrmux_controls =
SOC_DAPM_ENUM("Route", wm8991_ainrmux_enum);
-/* RXVOICE */
-static const struct snd_kcontrol_new wm8991_dapm_rxvoice_controls[] = {
- SOC_DAPM_SINGLE_TLV("LIN4RXN", WM8991_INPUT_MIXER5, WM8991_LR4BVOL_SHIFT,
- WM8991_LR4BVOL_MASK, 0, in_mix_tlv),
- SOC_DAPM_SINGLE_TLV("RIN4RXP", WM8991_INPUT_MIXER6, WM8991_RL4BVOL_SHIFT,
- WM8991_RL4BVOL_MASK, 0, in_mix_tlv),
-};
-
/* LOMIX */
static const struct snd_kcontrol_new wm8991_dapm_lomix_controls[] = {
SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8991_OUTPUT_MIXER1,
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 15ce64a48a87..55d0b9be6ff0 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -285,7 +285,6 @@ static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0);
static const DECLARE_TLV_DB_SCALE(wm8994_3d_tlv, -1600, 183, 0);
static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static const DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
-static const DECLARE_TLV_DB_SCALE(mixin_boost_tlv, 0, 900, 0);
#define WM8994_DRC_SWITCH(xname, reg, shift) \
SOC_SINGLE_EXT(xname, reg, shift, 1, 0, \
@@ -733,13 +732,6 @@ SOC_SINGLE_TLV("AIF2DAC Noise Gate Threshold Volume",
7, 1, ng_tlv),
};
-static const struct snd_kcontrol_new wm1811_snd_controls[] = {
-SOC_SINGLE_TLV("MIXINL IN1LP Boost Volume", WM8994_INPUT_MIXER_1, 7, 1, 0,
- mixin_boost_tlv),
-SOC_SINGLE_TLV("MIXINL IN1RP Boost Volume", WM8994_INPUT_MIXER_1, 8, 1, 0,
- mixin_boost_tlv),
-};
-
/* We run all mode setting through a function to enforce audio mode */
static void wm1811_jackdet_set_mode(struct snd_soc_component *component, u16 mode)
{
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 1ef69409ccd1..519ca2e69637 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -3509,7 +3509,8 @@ out:
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_open);
-int wm_adsp_compr_free(struct snd_compr_stream *stream)
+int wm_adsp_compr_free(struct snd_soc_component *component,
+ struct snd_compr_stream *stream)
{
struct wm_adsp_compr *compr = stream->runtime->private_data;
struct wm_adsp *dsp = compr->dsp;
@@ -3583,7 +3584,8 @@ static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr)
return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE;
}
-int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
+int wm_adsp_compr_set_params(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
struct snd_compr_params *params)
{
struct wm_adsp_compr *compr = stream->runtime->private_data;
@@ -3610,7 +3612,8 @@ int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
-int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
+int wm_adsp_compr_get_caps(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
struct snd_compr_caps *caps)
{
struct wm_adsp_compr *compr = stream->runtime->private_data;
@@ -3976,7 +3979,8 @@ static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf)
return 0;
}
-int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd)
+int wm_adsp_compr_trigger(struct snd_soc_component *component,
+ struct snd_compr_stream *stream, int cmd)
{
struct wm_adsp_compr *compr = stream->runtime->private_data;
struct wm_adsp *dsp = compr->dsp;
@@ -4139,7 +4143,8 @@ static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
buf->irq_count);
}
-int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
+int wm_adsp_compr_pointer(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
struct snd_compr_tstamp *tstamp)
{
struct wm_adsp_compr *compr = stream->runtime->private_data;
@@ -4297,7 +4302,8 @@ static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
return ntotal;
}
-int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf,
+int wm_adsp_compr_copy(struct snd_soc_component *component,
+ struct snd_compr_stream *stream, char __user *buf,
size_t count)
{
struct wm_adsp_compr *compr = stream->runtime->private_data;
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 4c481cf20275..1996350b817e 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -190,16 +190,22 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream);
-int wm_adsp_compr_free(struct snd_compr_stream *stream);
-int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
+int wm_adsp_compr_free(struct snd_soc_component *component,
+ struct snd_compr_stream *stream);
+int wm_adsp_compr_set_params(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
struct snd_compr_params *params);
-int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
+int wm_adsp_compr_get_caps(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
struct snd_compr_caps *caps);
-int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd);
+int wm_adsp_compr_trigger(struct snd_soc_component *component,
+ struct snd_compr_stream *stream, int cmd);
int wm_adsp_compr_handle_irq(struct wm_adsp *dsp);
-int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
+int wm_adsp_compr_pointer(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
struct snd_compr_tstamp *tstamp);
-int wm_adsp_compr_copy(struct snd_compr_stream *stream,
+int wm_adsp_compr_copy(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
char __user *buf, size_t count);
int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
unsigned int alg, void *buf, size_t len);
diff --git a/sound/soc/codecs/zl38060.c b/sound/soc/codecs/zl38060.c
new file mode 100644
index 000000000000..927ad849ad2d
--- /dev/null
+++ b/sound/soc/codecs/zl38060.c
@@ -0,0 +1,638 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Codec driver for Microsemi ZL38060 Connected Home Audio Processor.
+//
+// Copyright(c) 2020 Sven Van Asbroeck
+
+// The ZL38060 is very flexible and configurable. This driver implements only a
+// tiny subset of the chip's possible configurations:
+//
+// - DSP block bypassed: DAI routed straight to DACs
+// microphone routed straight to DAI
+// - chip's internal clock is driven by a 12 MHz external crystal
+// - chip's DAI connected to CPU is I2S, and bit + frame clock master
+// - chip must be strapped for "host boot": in this mode, firmware will be
+// provided by this driver.
+
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/property.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/ihex.h>
+
+#include <sound/pcm_params.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "zl38060"
+
+#define ZL38_RATES (SNDRV_PCM_RATE_8000 |\
+ SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_48000)
+#define ZL38_FORMATS SNDRV_PCM_FMTBIT_S16_LE
+
+#define HBI_FIRMWARE_PAGE 0xFF
+#define ZL38_MAX_RAW_XFER 0x100
+
+#define REG_TDMA_CFG_CLK 0x0262
+#define CFG_CLK_PCLK_SHIFT 4
+#define CFG_CLK_PCLK_MASK (0x7ff << CFG_CLK_PCLK_SHIFT)
+#define CFG_CLK_PCLK(bits) ((bits - 1) << CFG_CLK_PCLK_SHIFT)
+#define CFG_CLK_MASTER BIT(15)
+#define CFG_CLK_FSRATE_MASK 0x7
+#define CFG_CLK_FSRATE_8KHZ 0x1
+#define CFG_CLK_FSRATE_16KHZ 0x2
+#define CFG_CLK_FSRATE_48KHZ 0x6
+
+#define REG_CLK_CFG 0x0016
+#define CLK_CFG_SOURCE_XTAL BIT(15)
+
+#define REG_CLK_STATUS 0x0014
+#define CLK_STATUS_HWRST BIT(0)
+
+#define REG_PARAM_RESULT 0x0034
+#define PARAM_RESULT_READY 0xD3D3
+
+#define REG_PG255_BASE_HI 0x000C
+#define REG_PG255_OFFS(addr) ((HBI_FIRMWARE_PAGE << 8) | (addr & 0xFF))
+#define REG_FWR_EXEC 0x012C
+
+#define REG_CMD 0x0032
+#define REG_HW_REV 0x0020
+#define REG_FW_PROD 0x0022
+#define REG_FW_REV 0x0024
+
+#define REG_SEMA_FLAGS 0x0006
+#define SEMA_FLAGS_BOOT_CMD BIT(0)
+#define SEMA_FLAGS_APP_REBOOT BIT(1)
+
+#define REG_HW_REV 0x0020
+#define REG_FW_PROD 0x0022
+#define REG_FW_REV 0x0024
+#define REG_GPIO_DIR 0x02DC
+#define REG_GPIO_DAT 0x02DA
+
+#define BOOTCMD_LOAD_COMPLETE 0x000D
+#define BOOTCMD_FW_GO 0x0008
+
+#define FIRMWARE_MAJOR 2
+#define FIRMWARE_MINOR 2
+
+struct zl38_codec_priv {
+ struct device *dev;
+ struct regmap *regmap;
+ bool is_stream_in_use[2];
+ struct gpio_chip *gpio_chip;
+};
+
+static int zl38_fw_issue_command(struct regmap *regmap, u16 cmd)
+{
+ unsigned int val;
+ int err;
+
+ err = regmap_read_poll_timeout(regmap, REG_SEMA_FLAGS, val,
+ !(val & SEMA_FLAGS_BOOT_CMD), 10000,
+ 10000 * 100);
+ if (err)
+ return err;
+ err = regmap_write(regmap, REG_CMD, cmd);
+ if (err)
+ return err;
+ err = regmap_update_bits(regmap, REG_SEMA_FLAGS, SEMA_FLAGS_BOOT_CMD,
+ SEMA_FLAGS_BOOT_CMD);
+ if (err)
+ return err;
+
+ return regmap_read_poll_timeout(regmap, REG_CMD, val, !val, 10000,
+ 10000 * 100);
+}
+
+static int zl38_fw_go(struct regmap *regmap)
+{
+ int err;
+
+ err = zl38_fw_issue_command(regmap, BOOTCMD_LOAD_COMPLETE);
+ if (err)
+ return err;
+
+ return zl38_fw_issue_command(regmap, BOOTCMD_FW_GO);
+}
+
+static int zl38_fw_enter_boot_mode(struct regmap *regmap)
+{
+ unsigned int val;
+ int err;
+
+ err = regmap_update_bits(regmap, REG_CLK_STATUS, CLK_STATUS_HWRST,
+ CLK_STATUS_HWRST);
+ if (err)
+ return err;
+
+ return regmap_read_poll_timeout(regmap, REG_PARAM_RESULT, val,
+ val == PARAM_RESULT_READY, 1000, 50000);
+}
+
+static int
+zl38_fw_send_data(struct regmap *regmap, u32 addr, const void *data, u16 len)
+{
+ __be32 addr_base = cpu_to_be32(addr & ~0xFF);
+ int err;
+
+ err = regmap_raw_write(regmap, REG_PG255_BASE_HI, &addr_base,
+ sizeof(addr_base));
+ if (err)
+ return err;
+ return regmap_raw_write(regmap, REG_PG255_OFFS(addr), data, len);
+}
+
+static int zl38_fw_send_xaddr(struct regmap *regmap, const void *data)
+{
+ /* execution address from ihex: 32-bit little endian.
+ * device register expects 32-bit big endian.
+ */
+ u32 addr = le32_to_cpup(data);
+ __be32 baddr = cpu_to_be32(addr);
+
+ return regmap_raw_write(regmap, REG_FWR_EXEC, &baddr, sizeof(baddr));
+}
+
+static int zl38_load_firmware(struct device *dev, struct regmap *regmap)
+{
+ const struct ihex_binrec *rec;
+ const struct firmware *fw;
+ u32 addr;
+ u16 len;
+ int err;
+
+ /* how to get this firmware:
+ * 1. request and download chip firmware from Microsemi
+ * (provided by Microsemi in srec format)
+ * 2. convert downloaded firmware from srec to ihex. Simple tool:
+ * https://gitlab.com/TheSven73/s3-to-irec
+ * 3. convert ihex to binary (.fw) using ihex2fw tool which is included
+ * with the Linux kernel sources
+ */
+ err = request_ihex_firmware(&fw, "zl38060.fw", dev);
+ if (err)
+ return err;
+ err = zl38_fw_enter_boot_mode(regmap);
+ if (err)
+ goto out;
+ rec = (const struct ihex_binrec *)fw->data;
+ while (rec) {
+ addr = be32_to_cpu(rec->addr);
+ len = be16_to_cpu(rec->len);
+ if (addr) {
+ /* regular data ihex record */
+ err = zl38_fw_send_data(regmap, addr, rec->data, len);
+ } else if (len == 4) {
+ /* execution address ihex record */
+ err = zl38_fw_send_xaddr(regmap, rec->data);
+ } else {
+ err = -EINVAL;
+ }
+ if (err)
+ goto out;
+ /* next ! */
+ rec = ihex_next_binrec(rec);
+ }
+ err = zl38_fw_go(regmap);
+
+out:
+ release_firmware(fw);
+ return err;
+}
+
+
+static int zl38_software_reset(struct regmap *regmap)
+{
+ unsigned int val;
+ int err;
+
+ err = regmap_update_bits(regmap, REG_SEMA_FLAGS, SEMA_FLAGS_APP_REBOOT,
+ SEMA_FLAGS_APP_REBOOT);
+ if (err)
+ return err;
+
+ /* wait for host bus interface to settle.
+ * Not sure if this is required: Microsemi's vendor driver does this,
+ * but the firmware manual does not mention it. Leave it in, there's
+ * little downside, apart from a slower reset.
+ */
+ msleep(50);
+
+ return regmap_read_poll_timeout(regmap, REG_SEMA_FLAGS, val,
+ !(val & SEMA_FLAGS_APP_REBOOT), 10000,
+ 10000 * 100);
+}
+
+static int zl38_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct zl38_codec_priv *priv = snd_soc_dai_get_drvdata(dai);
+ int err;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /* firmware default is normal i2s */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ /* firmware default is normal bitclock and frame */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* always 32 bits per frame (= 16 bits/channel, 2 channels) */
+ err = regmap_update_bits(priv->regmap, REG_TDMA_CFG_CLK,
+ CFG_CLK_MASTER | CFG_CLK_PCLK_MASK,
+ CFG_CLK_MASTER | CFG_CLK_PCLK(32));
+ if (err)
+ return err;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int zl38_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct zl38_codec_priv *priv = snd_soc_dai_get_drvdata(dai);
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ unsigned int fsrate;
+ int err;
+
+ /* We cannot change hw_params while the dai is already in use - the
+ * software reset will corrupt the audio. However, this is not required,
+ * as the chip's TDM buses are fully symmetric, which mandates identical
+ * rates, channels, and samplebits for record and playback.
+ */
+ if (priv->is_stream_in_use[!tx])
+ goto skip_setup;
+
+ switch (params_rate(params)) {
+ case 8000:
+ fsrate = CFG_CLK_FSRATE_8KHZ;
+ break;
+ case 16000:
+ fsrate = CFG_CLK_FSRATE_16KHZ;
+ break;
+ case 48000:
+ fsrate = CFG_CLK_FSRATE_48KHZ;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ err = regmap_update_bits(priv->regmap, REG_TDMA_CFG_CLK,
+ CFG_CLK_FSRATE_MASK, fsrate);
+ if (err)
+ return err;
+
+ /* chip requires a software reset to apply audio register changes */
+ err = zl38_software_reset(priv->regmap);
+ if (err)
+ return err;
+
+skip_setup:
+ priv->is_stream_in_use[tx] = true;
+
+ return 0;
+}
+
+static int zl38_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct zl38_codec_priv *priv = snd_soc_dai_get_drvdata(dai);
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+
+ priv->is_stream_in_use[tx] = false;
+
+ return 0;
+}
+
+/* stereo bypass with no AEC */
+static const struct reg_sequence cp_config_stereo_bypass[] = {
+ /* interconnects must be programmed first */
+ { 0x0210, 0x0005 }, /* DAC1 in <= I2S1-L */
+ { 0x0212, 0x0006 }, /* DAC2 in <= I2S1-R */
+ { 0x0214, 0x0001 }, /* I2S1-L in <= MIC1 */
+ { 0x0216, 0x0001 }, /* I2S1-R in <= MIC1 */
+ { 0x0224, 0x0000 }, /* AEC-S in <= n/a */
+ { 0x0226, 0x0000 }, /* AEC-R in <= n/a */
+ /* output enables must be programmed next */
+ { 0x0202, 0x000F }, /* enable I2S1 + DAC */
+};
+
+static const struct snd_soc_dai_ops zl38_dai_ops = {
+ .set_fmt = zl38_set_fmt,
+ .hw_params = zl38_hw_params,
+ .hw_free = zl38_hw_free,
+};
+
+static struct snd_soc_dai_driver zl38_dai = {
+ .name = "zl38060-tdma",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = ZL38_RATES,
+ .formats = ZL38_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = ZL38_RATES,
+ .formats = ZL38_FORMATS,
+ },
+ .ops = &zl38_dai_ops,
+ .symmetric_rates = 1,
+ .symmetric_samplebits = 1,
+ .symmetric_channels = 1,
+};
+
+static const struct snd_soc_dapm_widget zl38_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("DAC1"),
+ SND_SOC_DAPM_OUTPUT("DAC2"),
+
+ SND_SOC_DAPM_INPUT("DMICL"),
+};
+
+static const struct snd_soc_dapm_route zl38_dapm_routes[] = {
+ { "DAC1", NULL, "Playback" },
+ { "DAC2", NULL, "Playback" },
+
+ { "Capture", NULL, "DMICL" },
+};
+
+static const struct snd_soc_component_driver zl38_component_dev = {
+ .dapm_widgets = zl38_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(zl38_dapm_widgets),
+ .dapm_routes = zl38_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(zl38_dapm_routes),
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
+};
+
+static void chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val)
+{
+ struct regmap *regmap = gpiochip_get_data(c);
+ unsigned int mask = BIT(offset);
+
+ regmap_update_bits(regmap, REG_GPIO_DAT, mask, val ? mask : 0);
+}
+
+static int chip_gpio_get(struct gpio_chip *c, unsigned int offset)
+{
+ struct regmap *regmap = gpiochip_get_data(c);
+ unsigned int mask = BIT(offset);
+ unsigned int val;
+ int err;
+
+ err = regmap_read(regmap, REG_GPIO_DAT, &val);
+ if (err)
+ return err;
+
+ return !!(val & mask);
+}
+
+static int chip_direction_input(struct gpio_chip *c, unsigned int offset)
+{
+ struct regmap *regmap = gpiochip_get_data(c);
+ unsigned int mask = BIT(offset);
+
+ return regmap_update_bits(regmap, REG_GPIO_DIR, mask, 0);
+}
+
+static int
+chip_direction_output(struct gpio_chip *c, unsigned int offset, int val)
+{
+ struct regmap *regmap = gpiochip_get_data(c);
+ unsigned int mask = BIT(offset);
+
+ chip_gpio_set(c, offset, val);
+ return regmap_update_bits(regmap, REG_GPIO_DIR, mask, mask);
+}
+
+static const struct gpio_chip template_chip = {
+ .owner = THIS_MODULE,
+ .label = DRV_NAME,
+
+ .base = -1,
+ .ngpio = 14,
+ .direction_input = chip_direction_input,
+ .direction_output = chip_direction_output,
+ .get = chip_gpio_get,
+ .set = chip_gpio_set,
+
+ .can_sleep = true,
+};
+
+static int zl38_check_revision(struct device *dev, struct regmap *regmap)
+{
+ unsigned int hwrev, fwprod, fwrev;
+ int fw_major, fw_minor, fw_micro;
+ int err;
+
+ err = regmap_read(regmap, REG_HW_REV, &hwrev);
+ if (err)
+ return err;
+ err = regmap_read(regmap, REG_FW_PROD, &fwprod);
+ if (err)
+ return err;
+ err = regmap_read(regmap, REG_FW_REV, &fwrev);
+ if (err)
+ return err;
+
+ fw_major = (fwrev >> 12) & 0xF;
+ fw_minor = (fwrev >> 8) & 0xF;
+ fw_micro = fwrev & 0xFF;
+ dev_info(dev, "hw rev 0x%x, fw product code %d, firmware rev %d.%d.%d",
+ hwrev & 0x1F, fwprod, fw_major, fw_minor, fw_micro);
+
+ if (fw_major != FIRMWARE_MAJOR || fw_minor < FIRMWARE_MINOR) {
+ dev_err(dev, "unsupported firmware. driver supports %d.%d",
+ FIRMWARE_MAJOR, FIRMWARE_MINOR);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int zl38_bus_read(void *context,
+ const void *reg_buf, size_t reg_size,
+ void *val_buf, size_t val_size)
+{
+ struct spi_device *spi = context;
+ const u8 *reg_buf8 = reg_buf;
+ size_t len = 0;
+ u8 offs, page;
+ u8 txbuf[4];
+
+ if (reg_size != 2 || val_size > ZL38_MAX_RAW_XFER)
+ return -EINVAL;
+
+ offs = reg_buf8[1] >> 1;
+ page = reg_buf8[0];
+
+ if (page) {
+ txbuf[len++] = 0xFE;
+ txbuf[len++] = page == HBI_FIRMWARE_PAGE ? 0xFF : page - 1;
+ txbuf[len++] = offs;
+ txbuf[len++] = val_size / 2 - 1;
+ } else {
+ txbuf[len++] = offs | 0x80;
+ txbuf[len++] = val_size / 2 - 1;
+ }
+
+ return spi_write_then_read(spi, txbuf, len, val_buf, val_size);
+}
+
+static int zl38_bus_write(void *context, const void *data, size_t count)
+{
+ struct spi_device *spi = context;
+ u8 buf[4 + ZL38_MAX_RAW_XFER];
+ size_t val_len, len = 0;
+ const u8 *data8 = data;
+ u8 offs, page;
+
+ if (count > (2 + ZL38_MAX_RAW_XFER) || count < 4)
+ return -EINVAL;
+ val_len = count - 2;
+ offs = data8[1] >> 1;
+ page = data8[0];
+
+ if (page) {
+ buf[len++] = 0xFE;
+ buf[len++] = page == HBI_FIRMWARE_PAGE ? 0xFF : page - 1;
+ buf[len++] = offs;
+ buf[len++] = (val_len / 2 - 1) | 0x80;
+ } else {
+ buf[len++] = offs | 0x80;
+ buf[len++] = (val_len / 2 - 1) | 0x80;
+ }
+ memcpy(buf + len, data8 + 2, val_len);
+ len += val_len;
+
+ return spi_write(spi, buf, len);
+}
+
+static const struct regmap_bus zl38_regmap_bus = {
+ .read = zl38_bus_read,
+ .write = zl38_bus_write,
+ .max_raw_write = ZL38_MAX_RAW_XFER,
+ .max_raw_read = ZL38_MAX_RAW_XFER,
+};
+
+static const struct regmap_config zl38_regmap_conf = {
+ .reg_bits = 16,
+ .val_bits = 16,
+ .reg_stride = 2,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int zl38_spi_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct zl38_codec_priv *priv;
+ struct gpio_desc *reset_gpio;
+ int err;
+
+ /* get the chip to a known state by putting it in reset */
+ reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(reset_gpio))
+ return PTR_ERR(reset_gpio);
+ if (reset_gpio) {
+ /* datasheet: need > 10us for a digital + analog reset */
+ usleep_range(15, 50);
+ /* take the chip out of reset */
+ gpiod_set_value_cansleep(reset_gpio, 0);
+ /* datasheet: need > 3ms for digital section to become stable */
+ usleep_range(3000, 10000);
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ dev_set_drvdata(dev, priv);
+ priv->regmap = devm_regmap_init(dev, &zl38_regmap_bus, spi,
+ &zl38_regmap_conf);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ err = zl38_load_firmware(dev, priv->regmap);
+ if (err)
+ return err;
+
+ err = zl38_check_revision(dev, priv->regmap);
+ if (err)
+ return err;
+
+ priv->gpio_chip = devm_kmemdup(dev, &template_chip,
+ sizeof(template_chip), GFP_KERNEL);
+ if (!priv->gpio_chip)
+ return -ENOMEM;
+#ifdef CONFIG_OF_GPIO
+ priv->gpio_chip->of_node = dev->of_node;
+#endif
+ err = devm_gpiochip_add_data(dev, priv->gpio_chip, priv->regmap);
+ if (err)
+ return err;
+
+ /* setup the cross-point switch for stereo bypass */
+ err = regmap_multi_reg_write(priv->regmap, cp_config_stereo_bypass,
+ ARRAY_SIZE(cp_config_stereo_bypass));
+ if (err)
+ return err;
+ /* setup for 12MHz crystal connected to the chip */
+ err = regmap_update_bits(priv->regmap, REG_CLK_CFG, CLK_CFG_SOURCE_XTAL,
+ CLK_CFG_SOURCE_XTAL);
+ if (err)
+ return err;
+
+ return devm_snd_soc_register_component(dev, &zl38_component_dev,
+ &zl38_dai, 1);
+}
+
+static const struct of_device_id zl38_dt_ids[] = {
+ { .compatible = "mscc,zl38060", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, zl38_dt_ids);
+
+static const struct spi_device_id zl38_spi_ids[] = {
+ { "zl38060", 0 },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, zl38_spi_ids);
+
+static struct spi_driver zl38060_spi_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = of_match_ptr(zl38_dt_ids),
+ },
+ .probe = zl38_spi_probe,
+ .id_table = zl38_spi_ids,
+};
+module_spi_driver(zl38060_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ZL38060 driver");
+MODULE_AUTHOR("Sven Van Asbroeck <[email protected]>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 65e8cd4be930..ea7b4787a8af 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -84,6 +84,17 @@ config SND_SOC_FSL_MICFIL
Say Y if you want to add Pulse Density Modulation microphone
interface (MICFIL) support for NXP.
+config SND_SOC_FSL_EASRC
+ tristate "Enhanced Asynchronous Sample Rate Converter (EASRC) module support"
+ depends on SND_SOC_FSL_ASRC
+ select REGMAP_MMIO
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ help
+ Say Y if you want to add Enhanced ASRC support for NXP. The ASRC is
+ a digital module that converts audio from a source sample rate to a
+ destination sample rate. It is a new design module compare with the
+ old ASRC.
+
config SND_SOC_FSL_UTILS
tristate
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 8cde88c72d93..b835eebf8825 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -24,6 +24,7 @@ snd-soc-fsl-micfil-objs := fsl_micfil.o
snd-soc-fsl-utils-objs := fsl_utils.o
snd-soc-fsl-dma-objs := fsl_dma.o
snd-soc-fsl-mqs-objs := fsl_mqs.o
+snd-soc-fsl-easrc-objs := fsl_easrc.o
obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o
obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
@@ -35,6 +36,7 @@ obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o
obj-$(CONFIG_SND_SOC_FSL_MICFIL) += snd-soc-fsl-micfil.o
obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
obj-$(CONFIG_SND_SOC_FSL_MQS) += snd-soc-fsl-mqs.o
+obj-$(CONFIG_SND_SOC_FSL_EASRC) += snd-soc-fsl-easrc.o
obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
# MPC5200 Platform Support
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index bb33601fab84..cf4feb835743 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -680,17 +680,23 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
goto asrc_fail;
}
- ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width);
+ ret = of_property_read_u32(asrc_np, "fsl,asrc-format",
+ &priv->asrc_format);
if (ret) {
- dev_err(&pdev->dev, "failed to get output rate\n");
- ret = -EINVAL;
- goto asrc_fail;
+ /* Fallback to old binding; translate to asrc_format */
+ ret = of_property_read_u32(asrc_np, "fsl,asrc-width",
+ &width);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to decide output format\n");
+ goto asrc_fail;
+ }
+
+ if (width == 24)
+ priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
+ else
+ priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE;
}
-
- if (width == 24)
- priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
- else
- priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE;
}
/* Finish card registering */
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 0dcebc24c312..432936039de4 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -21,10 +21,10 @@
#define IDEAL_RATIO_DECIMAL_DEPTH 26
#define pair_err(fmt, ...) \
- dev_err(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
+ dev_err(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
#define pair_dbg(fmt, ...) \
- dev_dbg(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
+ dev_dbg(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
/* Corresponding to process_option */
static unsigned int supported_asrc_rate[] = {
@@ -154,18 +154,18 @@ static void fsl_asrc_sel_proc(int inrate, int outrate,
* within range [ANCA, ANCA+ANCB-1], depends on the channels of pair A
* while pair A and pair C are comparatively independent.
*/
-int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
+static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
{
enum asrc_pair_index index = ASRC_INVALID_PAIR;
- struct fsl_asrc *asrc_priv = pair->asrc_priv;
- struct device *dev = &asrc_priv->pdev->dev;
+ struct fsl_asrc *asrc = pair->asrc;
+ struct device *dev = &asrc->pdev->dev;
unsigned long lock_flags;
int i, ret = 0;
- spin_lock_irqsave(&asrc_priv->lock, lock_flags);
+ spin_lock_irqsave(&asrc->lock, lock_flags);
for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) {
- if (asrc_priv->pair[i] != NULL)
+ if (asrc->pair[i] != NULL)
continue;
index = i;
@@ -177,17 +177,17 @@ int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
if (index == ASRC_INVALID_PAIR) {
dev_err(dev, "all pairs are busy now\n");
ret = -EBUSY;
- } else if (asrc_priv->channel_avail < channels) {
+ } else if (asrc->channel_avail < channels) {
dev_err(dev, "can't afford required channels: %d\n", channels);
ret = -EINVAL;
} else {
- asrc_priv->channel_avail -= channels;
- asrc_priv->pair[index] = pair;
+ asrc->channel_avail -= channels;
+ asrc->pair[index] = pair;
pair->channels = channels;
pair->index = index;
}
- spin_unlock_irqrestore(&asrc_priv->lock, lock_flags);
+ spin_unlock_irqrestore(&asrc->lock, lock_flags);
return ret;
}
@@ -195,25 +195,25 @@ int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
/**
* Release ASRC pair
*
- * It clears the resource from asrc_priv and releases the occupied channels.
+ * It clears the resource from asrc and releases the occupied channels.
*/
-void fsl_asrc_release_pair(struct fsl_asrc_pair *pair)
+static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair)
{
- struct fsl_asrc *asrc_priv = pair->asrc_priv;
+ struct fsl_asrc *asrc = pair->asrc;
enum asrc_pair_index index = pair->index;
unsigned long lock_flags;
/* Make sure the pair is disabled */
- regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+ regmap_update_bits(asrc->regmap, REG_ASRCTR,
ASRCTR_ASRCEi_MASK(index), 0);
- spin_lock_irqsave(&asrc_priv->lock, lock_flags);
+ spin_lock_irqsave(&asrc->lock, lock_flags);
- asrc_priv->channel_avail += pair->channels;
- asrc_priv->pair[index] = NULL;
+ asrc->channel_avail += pair->channels;
+ asrc->pair[index] = NULL;
pair->error = 0;
- spin_unlock_irqrestore(&asrc_priv->lock, lock_flags);
+ spin_unlock_irqrestore(&asrc->lock, lock_flags);
}
/**
@@ -221,10 +221,10 @@ void fsl_asrc_release_pair(struct fsl_asrc_pair *pair)
*/
static void fsl_asrc_set_watermarks(struct fsl_asrc_pair *pair, u32 in, u32 out)
{
- struct fsl_asrc *asrc_priv = pair->asrc_priv;
+ struct fsl_asrc *asrc = pair->asrc;
enum asrc_pair_index index = pair->index;
- regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index),
+ regmap_update_bits(asrc->regmap, REG_ASRMCR(index),
ASRMCRi_EXTTHRSHi_MASK |
ASRMCRi_INFIFO_THRESHOLD_MASK |
ASRMCRi_OUTFIFO_THRESHOLD_MASK,
@@ -257,7 +257,7 @@ static u32 fsl_asrc_cal_asrck_divisor(struct fsl_asrc_pair *pair, u32 div)
static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair,
int inrate, int outrate)
{
- struct fsl_asrc *asrc_priv = pair->asrc_priv;
+ struct fsl_asrc *asrc = pair->asrc;
enum asrc_pair_index index = pair->index;
unsigned long ratio;
int i;
@@ -286,8 +286,8 @@ static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair,
break;
}
- regmap_write(asrc_priv->regmap, REG_ASRIDRL(index), ratio);
- regmap_write(asrc_priv->regmap, REG_ASRIDRH(index), ratio >> 24);
+ regmap_write(asrc->regmap, REG_ASRIDRL(index), ratio);
+ regmap_write(asrc->regmap, REG_ASRIDRH(index), ratio >> 24);
return 0;
}
@@ -308,8 +308,10 @@ static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair,
*/
static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
{
- struct asrc_config *config = pair->config;
- struct fsl_asrc *asrc_priv = pair->asrc_priv;
+ struct fsl_asrc_pair_priv *pair_priv = pair->private;
+ struct asrc_config *config = pair_priv->config;
+ struct fsl_asrc *asrc = pair->asrc;
+ struct fsl_asrc_priv *asrc_priv = asrc->private;
enum asrc_pair_index index = pair->index;
enum asrc_word_width input_word_width;
enum asrc_word_width output_word_width;
@@ -441,18 +443,18 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
channels /= 2;
/* Update channels for current pair */
- regmap_update_bits(asrc_priv->regmap, REG_ASRCNCR,
+ regmap_update_bits(asrc->regmap, REG_ASRCNCR,
ASRCNCR_ANCi_MASK(index, asrc_priv->soc->channel_bits),
ASRCNCR_ANCi(index, channels, asrc_priv->soc->channel_bits));
/* Default setting: Automatic selection for processing mode */
- regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+ regmap_update_bits(asrc->regmap, REG_ASRCTR,
ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index));
- regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+ regmap_update_bits(asrc->regmap, REG_ASRCTR,
ASRCTR_USRi_MASK(index), 0);
/* Set the input and output clock sources */
- regmap_update_bits(asrc_priv->regmap, REG_ASRCSR,
+ regmap_update_bits(asrc->regmap, REG_ASRCSR,
ASRCSR_AICSi_MASK(index) | ASRCSR_AOCSi_MASK(index),
ASRCSR_AICS(index, clk_index[IN]) |
ASRCSR_AOCS(index, clk_index[OUT]));
@@ -462,19 +464,19 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
outdiv = fsl_asrc_cal_asrck_divisor(pair, div[OUT]);
/* Suppose indiv and outdiv includes prescaler, so add its MASK too */
- regmap_update_bits(asrc_priv->regmap, REG_ASRCDR(index),
+ regmap_update_bits(asrc->regmap, REG_ASRCDR(index),
ASRCDRi_AOCPi_MASK(index) | ASRCDRi_AICPi_MASK(index) |
ASRCDRi_AOCDi_MASK(index) | ASRCDRi_AICDi_MASK(index),
ASRCDRi_AOCP(index, outdiv) | ASRCDRi_AICP(index, indiv));
/* Implement word_width configurations */
- regmap_update_bits(asrc_priv->regmap, REG_ASRMCR1(index),
+ regmap_update_bits(asrc->regmap, REG_ASRMCR1(index),
ASRMCR1i_OW16_MASK | ASRMCR1i_IWD_MASK,
ASRMCR1i_OW16(output_word_width) |
ASRMCR1i_IWD(input_word_width));
/* Enable BUFFER STALL */
- regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index),
+ regmap_update_bits(asrc->regmap, REG_ASRMCR(index),
ASRMCRi_BUFSTALLi_MASK, ASRMCRi_BUFSTALLi);
/* Set default thresholds for input and output FIFO */
@@ -486,18 +488,18 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
return 0;
/* Clear ASTSx bit to use Ideal Ratio mode */
- regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+ regmap_update_bits(asrc->regmap, REG_ASRCTR,
ASRCTR_ATSi_MASK(index), 0);
/* Enable Ideal Ratio mode */
- regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+ regmap_update_bits(asrc->regmap, REG_ASRCTR,
ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index),
ASRCTR_IDR(index) | ASRCTR_USR(index));
fsl_asrc_sel_proc(inrate, outrate, &pre_proc, &post_proc);
/* Apply configurations for pre- and post-processing */
- regmap_update_bits(asrc_priv->regmap, REG_ASRCFG,
+ regmap_update_bits(asrc->regmap, REG_ASRCFG,
ASRCFG_PREMODi_MASK(index) | ASRCFG_POSTMODi_MASK(index),
ASRCFG_PREMOD(index, pre_proc) |
ASRCFG_POSTMOD(index, post_proc));
@@ -512,28 +514,28 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
*/
static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair)
{
- struct fsl_asrc *asrc_priv = pair->asrc_priv;
+ struct fsl_asrc *asrc = pair->asrc;
enum asrc_pair_index index = pair->index;
int reg, retry = 10, i;
/* Enable the current pair */
- regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+ regmap_update_bits(asrc->regmap, REG_ASRCTR,
ASRCTR_ASRCEi_MASK(index), ASRCTR_ASRCE(index));
/* Wait for status of initialization */
do {
udelay(5);
- regmap_read(asrc_priv->regmap, REG_ASRCFG, &reg);
+ regmap_read(asrc->regmap, REG_ASRCFG, &reg);
reg &= ASRCFG_INIRQi_MASK(index);
} while (!reg && --retry);
/* Make the input fifo to ASRC STALL level */
- regmap_read(asrc_priv->regmap, REG_ASRCNCR, &reg);
+ regmap_read(asrc->regmap, REG_ASRCNCR, &reg);
for (i = 0; i < pair->channels * 4; i++)
- regmap_write(asrc_priv->regmap, REG_ASRDI(index), 0);
+ regmap_write(asrc->regmap, REG_ASRDI(index), 0);
/* Enable overload interrupt */
- regmap_write(asrc_priv->regmap, REG_ASRIER, ASRIER_AOLIE);
+ regmap_write(asrc->regmap, REG_ASRIER, ASRIER_AOLIE);
}
/**
@@ -541,11 +543,11 @@ static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair)
*/
static void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair)
{
- struct fsl_asrc *asrc_priv = pair->asrc_priv;
+ struct fsl_asrc *asrc = pair->asrc;
enum asrc_pair_index index = pair->index;
/* Stop the current pair */
- regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+ regmap_update_bits(asrc->regmap, REG_ASRCTR,
ASRCTR_ASRCEi_MASK(index), 0);
}
@@ -554,20 +556,21 @@ static void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair)
*/
struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir)
{
- struct fsl_asrc *asrc_priv = pair->asrc_priv;
+ struct fsl_asrc *asrc = pair->asrc;
enum asrc_pair_index index = pair->index;
char name[4];
sprintf(name, "%cx%c", dir == IN ? 'r' : 't', index + 'a');
- return dma_request_slave_channel(&asrc_priv->pdev->dev, name);
+ return dma_request_slave_channel(&asrc->pdev->dev, name);
}
EXPORT_SYMBOL_GPL(fsl_asrc_get_dma_channel);
static int fsl_asrc_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai);
+ struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai);
+ struct fsl_asrc_priv *asrc_priv = asrc->private;
/* Odd channel number is not valid for older ASRC (channel_bits==3) */
if (asrc_priv->soc->channel_bits == 3)
@@ -583,13 +586,13 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai);
+ struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai);
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_asrc_pair *pair = runtime->private_data;
+ struct fsl_asrc_pair_priv *pair_priv = pair->private;
unsigned int channels = params_channels(params);
unsigned int rate = params_rate(params);
struct asrc_config config;
- snd_pcm_format_t format;
int ret;
ret = fsl_asrc_request_pair(channels, pair);
@@ -598,12 +601,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- pair->config = &config;
-
- if (asrc_priv->asrc_width == 16)
- format = SNDRV_PCM_FORMAT_S16_LE;
- else
- format = SNDRV_PCM_FORMAT_S24_LE;
+ pair_priv->config = &config;
config.pair = pair->index;
config.channel_num = channels;
@@ -612,13 +610,13 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
config.input_format = params_format(params);
- config.output_format = format;
+ config.output_format = asrc->asrc_format;
config.input_sample_rate = rate;
- config.output_sample_rate = asrc_priv->asrc_rate;
+ config.output_sample_rate = asrc->asrc_rate;
} else {
- config.input_format = format;
+ config.input_format = asrc->asrc_format;
config.output_format = params_format(params);
- config.input_sample_rate = asrc_priv->asrc_rate;
+ config.input_sample_rate = asrc->asrc_rate;
config.output_sample_rate = rate;
}
@@ -676,10 +674,10 @@ static const struct snd_soc_dai_ops fsl_asrc_dai_ops = {
static int fsl_asrc_dai_probe(struct snd_soc_dai *dai)
{
- struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai);
+ struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai);
- snd_soc_dai_init_dma_data(dai, &asrc_priv->dma_params_tx,
- &asrc_priv->dma_params_rx);
+ snd_soc_dai_init_dma_data(dai, &asrc->dma_params_tx,
+ &asrc->dma_params_rx);
return 0;
}
@@ -858,30 +856,30 @@ static const struct regmap_config fsl_asrc_regmap_config = {
/**
* Initialize ASRC registers with a default configurations
*/
-static int fsl_asrc_init(struct fsl_asrc *asrc_priv)
+static int fsl_asrc_init(struct fsl_asrc *asrc)
{
/* Halt ASRC internal FP when input FIFO needs data for pair A, B, C */
- regmap_write(asrc_priv->regmap, REG_ASRCTR, ASRCTR_ASRCEN);
+ regmap_write(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEN);
/* Disable interrupt by default */
- regmap_write(asrc_priv->regmap, REG_ASRIER, 0x0);
+ regmap_write(asrc->regmap, REG_ASRIER, 0x0);
/* Apply recommended settings for parameters from Reference Manual */
- regmap_write(asrc_priv->regmap, REG_ASRPM1, 0x7fffff);
- regmap_write(asrc_priv->regmap, REG_ASRPM2, 0x255555);
- regmap_write(asrc_priv->regmap, REG_ASRPM3, 0xff7280);
- regmap_write(asrc_priv->regmap, REG_ASRPM4, 0xff7280);
- regmap_write(asrc_priv->regmap, REG_ASRPM5, 0xff7280);
+ regmap_write(asrc->regmap, REG_ASRPM1, 0x7fffff);
+ regmap_write(asrc->regmap, REG_ASRPM2, 0x255555);
+ regmap_write(asrc->regmap, REG_ASRPM3, 0xff7280);
+ regmap_write(asrc->regmap, REG_ASRPM4, 0xff7280);
+ regmap_write(asrc->regmap, REG_ASRPM5, 0xff7280);
/* Base address for task queue FIFO. Set to 0x7C */
- regmap_update_bits(asrc_priv->regmap, REG_ASRTFR1,
+ regmap_update_bits(asrc->regmap, REG_ASRTFR1,
ASRTFR1_TF_BASE_MASK, ASRTFR1_TF_BASE(0xfc));
/* Set the processing clock for 76KHz to 133M */
- regmap_write(asrc_priv->regmap, REG_ASR76K, 0x06D6);
+ regmap_write(asrc->regmap, REG_ASR76K, 0x06D6);
/* Set the processing clock for 56KHz to 133M */
- return regmap_write(asrc_priv->regmap, REG_ASR56K, 0x0947);
+ return regmap_write(asrc->regmap, REG_ASR56K, 0x0947);
}
/**
@@ -889,15 +887,15 @@ static int fsl_asrc_init(struct fsl_asrc *asrc_priv)
*/
static irqreturn_t fsl_asrc_isr(int irq, void *dev_id)
{
- struct fsl_asrc *asrc_priv = (struct fsl_asrc *)dev_id;
- struct device *dev = &asrc_priv->pdev->dev;
+ struct fsl_asrc *asrc = (struct fsl_asrc *)dev_id;
+ struct device *dev = &asrc->pdev->dev;
enum asrc_pair_index index;
u32 status;
- regmap_read(asrc_priv->regmap, REG_ASRSTR, &status);
+ regmap_read(asrc->regmap, REG_ASRSTR, &status);
/* Clean overload error */
- regmap_write(asrc_priv->regmap, REG_ASRSTR, ASRSTR_AOLE);
+ regmap_write(asrc->regmap, REG_ASRSTR, ASRSTR_AOLE);
/*
* We here use dev_dbg() for all exceptions because ASRC itself does
@@ -905,31 +903,31 @@ static irqreturn_t fsl_asrc_isr(int irq, void *dev_id)
* interrupt would result a ridged conversion.
*/
for (index = ASRC_PAIR_A; index < ASRC_PAIR_MAX_NUM; index++) {
- if (!asrc_priv->pair[index])
+ if (!asrc->pair[index])
continue;
if (status & ASRSTR_ATQOL) {
- asrc_priv->pair[index]->error |= ASRC_TASK_Q_OVERLOAD;
+ asrc->pair[index]->error |= ASRC_TASK_Q_OVERLOAD;
dev_dbg(dev, "ASRC Task Queue FIFO overload\n");
}
if (status & ASRSTR_AOOL(index)) {
- asrc_priv->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD;
+ asrc->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD;
pair_dbg("Output Task Overload\n");
}
if (status & ASRSTR_AIOL(index)) {
- asrc_priv->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD;
+ asrc->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD;
pair_dbg("Input Task Overload\n");
}
if (status & ASRSTR_AODO(index)) {
- asrc_priv->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW;
+ asrc->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW;
pair_dbg("Output Data Buffer has overflowed\n");
}
if (status & ASRSTR_AIDU(index)) {
- asrc_priv->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN;
+ asrc->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN;
pair_dbg("Input Data Buffer has underflowed\n");
}
}
@@ -937,21 +935,33 @@ static irqreturn_t fsl_asrc_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static int fsl_asrc_get_fifo_addr(u8 dir, enum asrc_pair_index index)
+{
+ return REG_ASRDx(dir, index);
+}
+
static int fsl_asrc_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- struct fsl_asrc *asrc_priv;
+ struct fsl_asrc_priv *asrc_priv;
+ struct fsl_asrc *asrc;
struct resource *res;
void __iomem *regs;
int irq, ret, i;
u32 map_idx;
char tmp[16];
+ u32 width;
+
+ asrc = devm_kzalloc(&pdev->dev, sizeof(*asrc), GFP_KERNEL);
+ if (!asrc)
+ return -ENOMEM;
asrc_priv = devm_kzalloc(&pdev->dev, sizeof(*asrc_priv), GFP_KERNEL);
if (!asrc_priv)
return -ENOMEM;
- asrc_priv->pdev = pdev;
+ asrc->pdev = pdev;
+ asrc->private = asrc_priv;
/* Get the addresses and IRQ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -959,13 +969,13 @@ static int fsl_asrc_probe(struct platform_device *pdev)
if (IS_ERR(regs))
return PTR_ERR(regs);
- asrc_priv->paddr = res->start;
+ asrc->paddr = res->start;
- asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs,
- &fsl_asrc_regmap_config);
- if (IS_ERR(asrc_priv->regmap)) {
+ asrc->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs,
+ &fsl_asrc_regmap_config);
+ if (IS_ERR(asrc->regmap)) {
dev_err(&pdev->dev, "failed to init regmap\n");
- return PTR_ERR(asrc_priv->regmap);
+ return PTR_ERR(asrc->regmap);
}
irq = platform_get_irq(pdev, 0);
@@ -973,26 +983,26 @@ static int fsl_asrc_probe(struct platform_device *pdev)
return irq;
ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0,
- dev_name(&pdev->dev), asrc_priv);
+ dev_name(&pdev->dev), asrc);
if (ret) {
dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret);
return ret;
}
- asrc_priv->mem_clk = devm_clk_get(&pdev->dev, "mem");
- if (IS_ERR(asrc_priv->mem_clk)) {
+ asrc->mem_clk = devm_clk_get(&pdev->dev, "mem");
+ if (IS_ERR(asrc->mem_clk)) {
dev_err(&pdev->dev, "failed to get mem clock\n");
- return PTR_ERR(asrc_priv->mem_clk);
+ return PTR_ERR(asrc->mem_clk);
}
- asrc_priv->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
- if (IS_ERR(asrc_priv->ipg_clk)) {
+ asrc->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
+ if (IS_ERR(asrc->ipg_clk)) {
dev_err(&pdev->dev, "failed to get ipg clock\n");
- return PTR_ERR(asrc_priv->ipg_clk);
+ return PTR_ERR(asrc->ipg_clk);
}
- asrc_priv->spba_clk = devm_clk_get(&pdev->dev, "spba");
- if (IS_ERR(asrc_priv->spba_clk))
+ asrc->spba_clk = devm_clk_get(&pdev->dev, "spba");
+ if (IS_ERR(asrc->spba_clk))
dev_warn(&pdev->dev, "failed to get spba clock\n");
for (i = 0; i < ASRC_CLK_MAX_NUM; i++) {
@@ -1010,6 +1020,13 @@ static int fsl_asrc_probe(struct platform_device *pdev)
return -ENODEV;
}
+ asrc->use_edma = asrc_priv->soc->use_edma;
+ asrc->get_dma_channel = fsl_asrc_get_dma_channel;
+ asrc->request_pair = fsl_asrc_request_pair;
+ asrc->release_pair = fsl_asrc_release_pair;
+ asrc->get_fifo_addr = fsl_asrc_get_fifo_addr;
+ asrc->pair_priv_size = sizeof(struct fsl_asrc_pair_priv);
+
if (of_device_is_compatible(np, "fsl,imx35-asrc")) {
asrc_priv->clk_map[IN] = input_clk_map_imx35;
asrc_priv->clk_map[OUT] = output_clk_map_imx35;
@@ -1037,36 +1054,52 @@ static int fsl_asrc_probe(struct platform_device *pdev)
}
}
- ret = fsl_asrc_init(asrc_priv);
+ ret = fsl_asrc_init(asrc);
if (ret) {
dev_err(&pdev->dev, "failed to init asrc %d\n", ret);
return ret;
}
- asrc_priv->channel_avail = 10;
+ asrc->channel_avail = 10;
ret = of_property_read_u32(np, "fsl,asrc-rate",
- &asrc_priv->asrc_rate);
+ &asrc->asrc_rate);
if (ret) {
dev_err(&pdev->dev, "failed to get output rate\n");
return ret;
}
- ret = of_property_read_u32(np, "fsl,asrc-width",
- &asrc_priv->asrc_width);
+ ret = of_property_read_u32(np, "fsl,asrc-format", &asrc->asrc_format);
if (ret) {
- dev_err(&pdev->dev, "failed to get output width\n");
- return ret;
+ ret = of_property_read_u32(np, "fsl,asrc-width", &width);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to decide output format\n");
+ return ret;
+ }
+
+ switch (width) {
+ case 16:
+ asrc->asrc_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ case 24:
+ asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ default:
+ dev_warn(&pdev->dev,
+ "unsupported width, use default S24_LE\n");
+ asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ }
}
- if (asrc_priv->asrc_width != 16 && asrc_priv->asrc_width != 24) {
- dev_warn(&pdev->dev, "unsupported width, switching to 24bit\n");
- asrc_priv->asrc_width = 24;
+ if (!(FSL_ASRC_FORMATS & (1ULL << asrc->asrc_format))) {
+ dev_warn(&pdev->dev, "unsupported width, use default S24_LE\n");
+ asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
}
- platform_set_drvdata(pdev, asrc_priv);
+ platform_set_drvdata(pdev, asrc);
pm_runtime_enable(&pdev->dev);
- spin_lock_init(&asrc_priv->lock);
+ spin_lock_init(&asrc->lock);
ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component,
&fsl_asrc_dai, 1);
@@ -1081,17 +1114,18 @@ static int fsl_asrc_probe(struct platform_device *pdev)
#ifdef CONFIG_PM
static int fsl_asrc_runtime_resume(struct device *dev)
{
- struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
+ struct fsl_asrc *asrc = dev_get_drvdata(dev);
+ struct fsl_asrc_priv *asrc_priv = asrc->private;
int i, ret;
- ret = clk_prepare_enable(asrc_priv->mem_clk);
+ ret = clk_prepare_enable(asrc->mem_clk);
if (ret)
return ret;
- ret = clk_prepare_enable(asrc_priv->ipg_clk);
+ ret = clk_prepare_enable(asrc->ipg_clk);
if (ret)
goto disable_mem_clk;
- if (!IS_ERR(asrc_priv->spba_clk)) {
- ret = clk_prepare_enable(asrc_priv->spba_clk);
+ if (!IS_ERR(asrc->spba_clk)) {
+ ret = clk_prepare_enable(asrc->spba_clk);
if (ret)
goto disable_ipg_clk;
}
@@ -1106,26 +1140,27 @@ static int fsl_asrc_runtime_resume(struct device *dev)
disable_asrck_clk:
for (i--; i >= 0; i--)
clk_disable_unprepare(asrc_priv->asrck_clk[i]);
- if (!IS_ERR(asrc_priv->spba_clk))
- clk_disable_unprepare(asrc_priv->spba_clk);
+ if (!IS_ERR(asrc->spba_clk))
+ clk_disable_unprepare(asrc->spba_clk);
disable_ipg_clk:
- clk_disable_unprepare(asrc_priv->ipg_clk);
+ clk_disable_unprepare(asrc->ipg_clk);
disable_mem_clk:
- clk_disable_unprepare(asrc_priv->mem_clk);
+ clk_disable_unprepare(asrc->mem_clk);
return ret;
}
static int fsl_asrc_runtime_suspend(struct device *dev)
{
- struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
+ struct fsl_asrc *asrc = dev_get_drvdata(dev);
+ struct fsl_asrc_priv *asrc_priv = asrc->private;
int i;
for (i = 0; i < ASRC_CLK_MAX_NUM; i++)
clk_disable_unprepare(asrc_priv->asrck_clk[i]);
- if (!IS_ERR(asrc_priv->spba_clk))
- clk_disable_unprepare(asrc_priv->spba_clk);
- clk_disable_unprepare(asrc_priv->ipg_clk);
- clk_disable_unprepare(asrc_priv->mem_clk);
+ if (!IS_ERR(asrc->spba_clk))
+ clk_disable_unprepare(asrc->spba_clk);
+ clk_disable_unprepare(asrc->ipg_clk);
+ clk_disable_unprepare(asrc->mem_clk);
return 0;
}
@@ -1134,37 +1169,39 @@ static int fsl_asrc_runtime_suspend(struct device *dev)
#ifdef CONFIG_PM_SLEEP
static int fsl_asrc_suspend(struct device *dev)
{
- struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
+ struct fsl_asrc *asrc = dev_get_drvdata(dev);
+ struct fsl_asrc_priv *asrc_priv = asrc->private;
- regmap_read(asrc_priv->regmap, REG_ASRCFG,
+ regmap_read(asrc->regmap, REG_ASRCFG,
&asrc_priv->regcache_cfg);
- regcache_cache_only(asrc_priv->regmap, true);
- regcache_mark_dirty(asrc_priv->regmap);
+ regcache_cache_only(asrc->regmap, true);
+ regcache_mark_dirty(asrc->regmap);
return 0;
}
static int fsl_asrc_resume(struct device *dev)
{
- struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
+ struct fsl_asrc *asrc = dev_get_drvdata(dev);
+ struct fsl_asrc_priv *asrc_priv = asrc->private;
u32 asrctr;
/* Stop all pairs provisionally */
- regmap_read(asrc_priv->regmap, REG_ASRCTR, &asrctr);
- regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+ regmap_read(asrc->regmap, REG_ASRCTR, &asrctr);
+ regmap_update_bits(asrc->regmap, REG_ASRCTR,
ASRCTR_ASRCEi_ALL_MASK, 0);
/* Restore all registers */
- regcache_cache_only(asrc_priv->regmap, false);
- regcache_sync(asrc_priv->regmap);
+ regcache_cache_only(asrc->regmap, false);
+ regcache_sync(asrc->regmap);
- regmap_update_bits(asrc_priv->regmap, REG_ASRCFG,
+ regmap_update_bits(asrc->regmap, REG_ASRCFG,
ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK |
ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg);
/* Restart enabled pairs */
- regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+ regmap_update_bits(asrc->regmap, REG_ASRCTR,
ASRCTR_ASRCEi_ALL_MASK, asrctr);
return 0;
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index 8a821132d9d0..86d2422ad606 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -10,8 +10,7 @@
#ifndef _FSL_ASRC_H
#define _FSL_ASRC_H
-#define IN 0
-#define OUT 1
+#include "fsl_asrc_common.h"
#define ASRC_DMA_BUFFER_NUM 2
#define ASRC_INPUTFIFO_THRESHOLD 32
@@ -283,14 +282,6 @@
#define ASRMCR1i_OW16_MASK (1 << ASRMCR1i_OW16_SHIFT)
#define ASRMCR1i_OW16(v) ((v) << ASRMCR1i_OW16_SHIFT)
-
-enum asrc_pair_index {
- ASRC_INVALID_PAIR = -1,
- ASRC_PAIR_A = 0,
- ASRC_PAIR_B = 1,
- ASRC_PAIR_C = 2,
-};
-
#define ASRC_PAIR_MAX_NUM (ASRC_PAIR_C + 1)
enum asrc_inclk {
@@ -446,83 +437,28 @@ struct fsl_asrc_soc_data {
};
/**
- * fsl_asrc_pair: ASRC Pair private data
+ * fsl_asrc_pair_priv: ASRC Pair private data
*
- * @asrc_priv: pointer to its parent module
* @config: configuration profile
- * @error: error record
- * @index: pair index (ASRC_PAIR_A, ASRC_PAIR_B, ASRC_PAIR_C)
- * @channels: occupied channel number
- * @desc: input and output dma descriptors
- * @dma_chan: inputer and output DMA channels
- * @dma_data: private dma data
- * @pos: hardware pointer position
- * @private: pair private area
*/
-struct fsl_asrc_pair {
- struct fsl_asrc *asrc_priv;
+struct fsl_asrc_pair_priv {
struct asrc_config *config;
- unsigned int error;
-
- enum asrc_pair_index index;
- unsigned int channels;
-
- struct dma_async_tx_descriptor *desc[2];
- struct dma_chan *dma_chan[2];
- struct imx_dma_data dma_data;
- unsigned int pos;
-
- void *private;
};
/**
- * fsl_asrc_pair: ASRC private data
+ * fsl_asrc_priv: ASRC private data
*
- * @dma_params_rx: DMA parameters for receive channel
- * @dma_params_tx: DMA parameters for transmit channel
- * @pdev: platform device pointer
- * @regmap: regmap handler
- * @paddr: physical address to the base address of registers
- * @mem_clk: clock source to access register
- * @ipg_clk: clock source to drive peripheral
- * @spba_clk: SPBA clock (optional, depending on SoC design)
* @asrck_clk: clock sources to driver ASRC internal logic
- * @lock: spin lock for resource protection
- * @pair: pair pointers
* @soc: soc specific data
- * @channel_avail: non-occupied channel numbers
* @clk_map: clock map for input/output clock
- * @asrc_rate: default sample rate for ASoC Back-Ends
- * @asrc_width: default sample width for ASoC Back-Ends
* @regcache_cfg: store register value of REG_ASRCFG
*/
-struct fsl_asrc {
- struct snd_dmaengine_dai_dma_data dma_params_rx;
- struct snd_dmaengine_dai_dma_data dma_params_tx;
- struct platform_device *pdev;
- struct regmap *regmap;
- unsigned long paddr;
- struct clk *mem_clk;
- struct clk *ipg_clk;
- struct clk *spba_clk;
+struct fsl_asrc_priv {
struct clk *asrck_clk[ASRC_CLK_MAX_NUM];
- spinlock_t lock;
-
- struct fsl_asrc_pair *pair[ASRC_PAIR_MAX_NUM];
const struct fsl_asrc_soc_data *soc;
- unsigned int channel_avail;
unsigned char *clk_map[2];
- int asrc_rate;
- int asrc_width;
-
u32 regcache_cfg;
};
-#define DRV_NAME "fsl-asrc-dai"
-extern struct snd_soc_component_driver fsl_asrc_component;
-struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir);
-int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair);
-void fsl_asrc_release_pair(struct fsl_asrc_pair *pair);
-
#endif /* _FSL_ASRC_H */
diff --git a/sound/soc/fsl/fsl_asrc_common.h b/sound/soc/fsl/fsl_asrc_common.h
new file mode 100644
index 000000000000..77665b15c8db
--- /dev/null
+++ b/sound/soc/fsl/fsl_asrc_common.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 NXP
+ *
+ */
+
+#ifndef _FSL_ASRC_COMMON_H
+#define _FSL_ASRC_COMMON_H
+
+/* directions */
+#define IN 0
+#define OUT 1
+
+enum asrc_pair_index {
+ ASRC_INVALID_PAIR = -1,
+ ASRC_PAIR_A = 0,
+ ASRC_PAIR_B = 1,
+ ASRC_PAIR_C = 2,
+ ASRC_PAIR_D = 3,
+};
+
+#define PAIR_CTX_NUM 0x4
+
+/**
+ * fsl_asrc_pair: ASRC Pair common data
+ *
+ * @asrc: pointer to its parent module
+ * @error: error record
+ * @index: pair index (ASRC_PAIR_A, ASRC_PAIR_B, ASRC_PAIR_C)
+ * @channels: occupied channel number
+ * @desc: input and output dma descriptors
+ * @dma_chan: inputer and output DMA channels
+ * @dma_data: private dma data
+ * @pos: hardware pointer position
+ * @private: pair private area
+ */
+struct fsl_asrc_pair {
+ struct fsl_asrc *asrc;
+ unsigned int error;
+
+ enum asrc_pair_index index;
+ unsigned int channels;
+
+ struct dma_async_tx_descriptor *desc[2];
+ struct dma_chan *dma_chan[2];
+ struct imx_dma_data dma_data;
+ unsigned int pos;
+
+ void *private;
+};
+
+/**
+ * fsl_asrc: ASRC common data
+ *
+ * @dma_params_rx: DMA parameters for receive channel
+ * @dma_params_tx: DMA parameters for transmit channel
+ * @pdev: platform device pointer
+ * @regmap: regmap handler
+ * @paddr: physical address to the base address of registers
+ * @mem_clk: clock source to access register
+ * @ipg_clk: clock source to drive peripheral
+ * @spba_clk: SPBA clock (optional, depending on SoC design)
+ * @lock: spin lock for resource protection
+ * @pair: pair pointers
+ * @channel_avail: non-occupied channel numbers
+ * @asrc_rate: default sample rate for ASoC Back-Ends
+ * @asrc_format: default sample format for ASoC Back-Ends
+ * @use_edma: edma is used
+ * @get_dma_channel: function pointer
+ * @request_pair: function pointer
+ * @release_pair: function pointer
+ * @get_fifo_addr: function pointer
+ * @pair_priv_size: size of pair private struct.
+ * @private: private data structure
+ */
+struct fsl_asrc {
+ struct snd_dmaengine_dai_dma_data dma_params_rx;
+ struct snd_dmaengine_dai_dma_data dma_params_tx;
+ struct platform_device *pdev;
+ struct regmap *regmap;
+ unsigned long paddr;
+ struct clk *mem_clk;
+ struct clk *ipg_clk;
+ struct clk *spba_clk;
+ spinlock_t lock; /* spin lock for resource protection */
+
+ struct fsl_asrc_pair *pair[PAIR_CTX_NUM];
+ unsigned int channel_avail;
+
+ int asrc_rate;
+ snd_pcm_format_t asrc_format;
+ bool use_edma;
+
+ struct dma_chan *(*get_dma_channel)(struct fsl_asrc_pair *pair, bool dir);
+ int (*request_pair)(int channels, struct fsl_asrc_pair *pair);
+ void (*release_pair)(struct fsl_asrc_pair *pair);
+ int (*get_fifo_addr)(u8 dir, enum asrc_pair_index index);
+ size_t pair_priv_size;
+
+ void *private;
+};
+
+#define DRV_NAME "fsl-asrc-dai"
+extern struct snd_soc_component_driver fsl_asrc_component;
+
+#endif /* _FSL_ASRC_COMMON_H */
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index e7178817d7a7..e5d1b218acf8 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -12,7 +12,7 @@
#include <sound/dmaengine_pcm.h>
#include <sound/pcm_params.h>
-#include "fsl_asrc.h"
+#include "fsl_asrc_common.h"
#define FSL_ASRC_DMABUF_SIZE (256 * 1024)
@@ -135,7 +135,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
struct snd_dmaengine_dai_dma_data *dma_params_be = NULL;
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_asrc_pair *pair = runtime->private_data;
- struct fsl_asrc *asrc_priv = pair->asrc_priv;
+ struct fsl_asrc *asrc = pair->asrc;
struct dma_slave_config config_fe, config_be;
enum asrc_pair_index index = pair->index;
struct device *dev = component->dev;
@@ -146,7 +146,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
struct device *dev_be;
u8 dir = tx ? OUT : IN;
dma_cap_mask_t mask;
- int ret;
+ int ret, width;
/* Fetch the Back-End dma_data from DPCM */
for_each_dpcm_be(rtd, stream, dpcm) {
@@ -170,10 +170,10 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
/* Override dma_data of the Front-End and config its dmaengine */
dma_params_fe = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
- dma_params_fe->addr = asrc_priv->paddr + REG_ASRDx(!dir, index);
+ dma_params_fe->addr = asrc->paddr + asrc->get_fifo_addr(!dir, index);
dma_params_fe->maxburst = dma_params_be->maxburst;
- pair->dma_chan[!dir] = fsl_asrc_get_dma_channel(pair, !dir);
+ pair->dma_chan[!dir] = asrc->get_dma_channel(pair, !dir);
if (!pair->dma_chan[!dir]) {
dev_err(dev, "failed to request DMA channel\n");
return -EINVAL;
@@ -203,7 +203,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
* need to configure dma_request and dma_request2, but get dma_chan via
* dma_request_slave_channel directly with dma name of Front-End device
*/
- if (!asrc_priv->soc->use_edma) {
+ if (!asrc->use_edma) {
/* Get DMA request of Back-End */
tmp_chan = dma_request_slave_channel(dev_be, tx ? "tx" : "rx");
tmp_data = tmp_chan->private;
@@ -211,7 +211,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
dma_release_channel(tmp_chan);
/* Get DMA request of Front-End */
- tmp_chan = fsl_asrc_get_dma_channel(pair, dir);
+ tmp_chan = asrc->get_dma_channel(pair, dir);
tmp_data = tmp_chan->private;
pair->dma_data.dma_request2 = tmp_data->dma_request;
pair->dma_data.peripheral_type = tmp_data->peripheral_type;
@@ -222,7 +222,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
dma_request_channel(mask, filter, &pair->dma_data);
} else {
pair->dma_chan[dir] =
- fsl_asrc_get_dma_channel(pair, dir);
+ asrc->get_dma_channel(pair, dir);
}
if (!pair->dma_chan[dir]) {
@@ -230,10 +230,19 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
return -EINVAL;
}
- if (asrc_priv->asrc_width == 16)
+ width = snd_pcm_format_physical_width(asrc->asrc_format);
+ if (width < 8 || width > 64)
+ return -EINVAL;
+ else if (width == 8)
+ buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ else if (width == 16)
buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
- else
+ else if (width == 24)
+ buswidth = DMA_SLAVE_BUSWIDTH_3_BYTES;
+ else if (width <= 32)
buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ else
+ buswidth = DMA_SLAVE_BUSWIDTH_8_BYTES;
config_be.direction = DMA_DEV_TO_DEV;
config_be.src_addr_width = buswidth;
@@ -242,10 +251,10 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
config_be.dst_maxburst = dma_params_be->maxburst;
if (tx) {
- config_be.src_addr = asrc_priv->paddr + REG_ASRDO(index);
+ config_be.src_addr = asrc->paddr + asrc->get_fifo_addr(OUT, index);
config_be.dst_addr = dma_params_be->addr;
} else {
- config_be.dst_addr = asrc_priv->paddr + REG_ASRDI(index);
+ config_be.dst_addr = asrc->paddr + asrc->get_fifo_addr(IN, index);
config_be.src_addr = dma_params_be->addr;
}
@@ -288,7 +297,7 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component,
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dmaengine_dai_dma_data *dma_data;
struct device *dev = component->dev;
- struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
+ struct fsl_asrc *asrc = dev_get_drvdata(dev);
struct fsl_asrc_pair *pair;
struct dma_chan *tmp_chan = NULL;
u8 dir = tx ? OUT : IN;
@@ -302,11 +311,12 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component,
return ret;
}
- pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL);
+ pair = kzalloc(sizeof(*pair) + asrc->pair_priv_size, GFP_KERNEL);
if (!pair)
return -ENOMEM;
- pair->asrc_priv = asrc_priv;
+ pair->asrc = asrc;
+ pair->private = (void *)pair + sizeof(struct fsl_asrc_pair);
runtime->private_data = pair;
@@ -314,14 +324,14 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component,
* Request pair function needs channel num as input, for this
* dummy pair, we just request "1" channel temporarily.
*/
- ret = fsl_asrc_request_pair(1, pair);
+ ret = asrc->request_pair(1, pair);
if (ret < 0) {
dev_err(dev, "failed to request asrc pair\n");
goto req_pair_err;
}
/* Request a dummy dma channel, which will be released later. */
- tmp_chan = fsl_asrc_get_dma_channel(pair, dir);
+ tmp_chan = asrc->get_dma_channel(pair, dir);
if (!tmp_chan) {
dev_err(dev, "failed to get dma channel\n");
ret = -EINVAL;
@@ -347,7 +357,7 @@ out:
dma_release_channel(tmp_chan);
dma_chan_err:
- fsl_asrc_release_pair(pair);
+ asrc->release_pair(pair);
req_pair_err:
if (release_pair)
@@ -361,15 +371,15 @@ static int fsl_asrc_dma_shutdown(struct snd_soc_component *component,
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_asrc_pair *pair = runtime->private_data;
- struct fsl_asrc *asrc_priv;
+ struct fsl_asrc *asrc;
if (!pair)
return 0;
- asrc_priv = pair->asrc_priv;
+ asrc = pair->asrc;
- if (asrc_priv->pair[pair->index] == pair)
- asrc_priv->pair[pair->index] = NULL;
+ if (asrc->pair[pair->index] == pair)
+ asrc->pair[pair->index] = NULL;
kfree(pair);
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
new file mode 100644
index 000000000000..c6b5eb2d2af7
--- /dev/null
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -0,0 +1,2117 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2019 NXP
+
+#include <linux/atomic.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/kobject.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/sched/signal.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/gcd.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/core.h>
+
+#include "fsl_easrc.h"
+#include "imx-pcm.h"
+
+#define FSL_EASRC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | \
+ SNDRV_PCM_FMTBIT_U24_LE | \
+ SNDRV_PCM_FMTBIT_U24_3LE | \
+ SNDRV_PCM_FMTBIT_S32_LE | \
+ SNDRV_PCM_FMTBIT_U32_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_U20_3LE | \
+ SNDRV_PCM_FMTBIT_FLOAT_LE)
+
+static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct fsl_asrc *easrc = snd_soc_component_get_drvdata(comp);
+ struct fsl_easrc_priv *easrc_priv = easrc->private;
+ struct soc_mreg_control *mc =
+ (struct soc_mreg_control *)kcontrol->private_value;
+ unsigned int regval = ucontrol->value.integer.value[0];
+
+ easrc_priv->bps_iec958[mc->regbase] = regval;
+
+ return 0;
+}
+
+static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct fsl_asrc *easrc = snd_soc_component_get_drvdata(comp);
+ struct fsl_easrc_priv *easrc_priv = easrc->private;
+ struct soc_mreg_control *mc =
+ (struct soc_mreg_control *)kcontrol->private_value;
+
+ ucontrol->value.enumerated.item[0] = easrc_priv->bps_iec958[mc->regbase];
+
+ return 0;
+}
+
+static int fsl_easrc_get_reg(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_mreg_control *mc =
+ (struct soc_mreg_control *)kcontrol->private_value;
+ unsigned int regval;
+ int ret;
+
+ ret = snd_soc_component_read(component, mc->regbase, &regval);
+ if (ret < 0)
+ return ret;
+
+ ucontrol->value.integer.value[0] = regval;
+
+ return 0;
+}
+
+static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_mreg_control *mc =
+ (struct soc_mreg_control *)kcontrol->private_value;
+ unsigned int regval = ucontrol->value.integer.value[0];
+ int ret;
+
+ ret = snd_soc_component_write(component, mc->regbase, regval);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+#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, \
+ .put = fsl_easrc_set_reg, \
+ .private_value = (unsigned long)&(struct soc_mreg_control) \
+ { .regbase = xreg, .regcount = 1, .nbits = 32, \
+ .invert = 0, .min = 0, .max = 0xffffffff, } }
+
+#define SOC_SINGLE_VAL_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_iec958_get_bits, \
+ .put = fsl_easrc_iec958_put_bits, \
+ .private_value = (unsigned long)&(struct soc_mreg_control) \
+ { .regbase = xreg, .regcount = 1, .nbits = 32, \
+ .invert = 0, .min = 0, .max = 2, } }
+
+static const struct snd_kcontrol_new fsl_easrc_snd_controls[] = {
+ SOC_SINGLE("Context 0 Dither Switch", REG_EASRC_COC(0), 0, 1, 0),
+ SOC_SINGLE("Context 1 Dither Switch", REG_EASRC_COC(1), 0, 1, 0),
+ SOC_SINGLE("Context 2 Dither Switch", REG_EASRC_COC(2), 0, 1, 0),
+ SOC_SINGLE("Context 3 Dither Switch", REG_EASRC_COC(3), 0, 1, 0),
+
+ SOC_SINGLE("Context 0 IEC958 Validity", REG_EASRC_COC(0), 2, 1, 0),
+ SOC_SINGLE("Context 1 IEC958 Validity", REG_EASRC_COC(1), 2, 1, 0),
+ SOC_SINGLE("Context 2 IEC958 Validity", REG_EASRC_COC(2), 2, 1, 0),
+ SOC_SINGLE("Context 3 IEC958 Validity", REG_EASRC_COC(3), 2, 1, 0),
+
+ SOC_SINGLE_VAL_RW("Context 0 IEC958 Bits Per Sample", 0),
+ SOC_SINGLE_VAL_RW("Context 1 IEC958 Bits Per Sample", 1),
+ 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)),
+};
+
+/*
+ * fsl_easrc_set_rs_ratio
+ *
+ * According to the resample taps, calculate the resample ratio
+ * ratio = in_rate / out_rate
+ */
+static int fsl_easrc_set_rs_ratio(struct fsl_asrc_pair *ctx)
+{
+ struct fsl_asrc *easrc = ctx->asrc;
+ struct fsl_easrc_priv *easrc_priv = easrc->private;
+ struct fsl_easrc_ctx_priv *ctx_priv = ctx->private;
+ unsigned int in_rate = ctx_priv->in_params.norm_rate;
+ unsigned int out_rate = ctx_priv->out_params.norm_rate;
+ unsigned int int_bits;
+ unsigned int frac_bits;
+ u64 val;
+ u32 *r;
+
+ switch (easrc_priv->rs_num_taps) {
+ case EASRC_RS_32_TAPS:
+ int_bits = 5;
+ frac_bits = 39;
+ break;
+ case EASRC_RS_64_TAPS:
+ int_bits = 6;
+ frac_bits = 38;
+ break;
+ case EASRC_RS_128_TAPS:
+ int_bits = 7;
+ frac_bits = 37;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val = (u64)in_rate << frac_bits;
+ do_div(val, out_rate);
+ r = (uint32_t *)&val;
+
+ if (r[1] & 0xFFFFF000) {
+ dev_err(&easrc->pdev->dev, "ratio exceed range\n");
+ return -EINVAL;
+ }
+
+ regmap_write(easrc->regmap, REG_EASRC_RRL(ctx->index),
+ EASRC_RRL_RS_RL(r[0]));
+ regmap_write(easrc->regmap, REG_EASRC_RRH(ctx->index),
+ EASRC_RRH_RS_RH(r[1]));
+
+ return 0;
+}
+
+/* Normalize input and output sample rates */
+static void fsl_easrc_normalize_rates(struct fsl_asrc_pair *ctx)
+{
+ struct fsl_easrc_ctx_priv *ctx_priv;
+ int a, b;
+
+ if (!ctx)
+ return;
+
+ ctx_priv = ctx->private;
+
+ a = ctx_priv->in_params.sample_rate;
+ b = ctx_priv->out_params.sample_rate;
+
+ a = gcd(a, b);
+
+ /* Divide by gcd to normalize the rate */
+ ctx_priv->in_params.norm_rate = ctx_priv->in_params.sample_rate / a;
+ ctx_priv->out_params.norm_rate = ctx_priv->out_params.sample_rate / a;
+}
+
+/* Resets the pointer of the coeff memory pointers */
+static int fsl_easrc_coeff_mem_ptr_reset(struct fsl_asrc *easrc,
+ unsigned int ctx_id, int mem_type)
+{
+ struct device *dev;
+ u32 reg, mask, val;
+
+ if (!easrc)
+ return -ENODEV;
+
+ dev = &easrc->pdev->dev;
+
+ switch (mem_type) {
+ case EASRC_PF_COEFF_MEM:
+ /* This resets the prefilter memory pointer addr */
+ if (ctx_id >= EASRC_CTX_MAX_NUM) {
+ dev_err(dev, "Invalid context id[%d]\n", ctx_id);
+ return -EINVAL;
+ }
+
+ reg = REG_EASRC_CCE1(ctx_id);
+ mask = EASRC_CCE1_COEF_MEM_RST_MASK;
+ val = EASRC_CCE1_COEF_MEM_RST;
+ break;
+ case EASRC_RS_COEFF_MEM:
+ /* This resets the resampling memory pointer addr */
+ reg = REG_EASRC_CRCC;
+ mask = EASRC_CRCC_RS_CPR_MASK;
+ val = EASRC_CRCC_RS_CPR;
+ break;
+ default:
+ dev_err(dev, "Unknown memory type\n");
+ return -EINVAL;
+ }
+
+ /*
+ * To reset the write pointer back to zero, the register field
+ * ASRC_CTX_CTRL_EXT1x[PF_COEFF_MEM_RST] can be toggled from
+ * 0x0 to 0x1 to 0x0.
+ */
+ regmap_update_bits(easrc->regmap, reg, mask, 0);
+ regmap_update_bits(easrc->regmap, reg, mask, val);
+ regmap_update_bits(easrc->regmap, reg, mask, 0);
+
+ return 0;
+}
+
+static inline uint32_t bits_taps_to_val(unsigned int t)
+{
+ switch (t) {
+ case EASRC_RS_32_TAPS:
+ return 32;
+ case EASRC_RS_64_TAPS:
+ return 64;
+ case EASRC_RS_128_TAPS:
+ return 128;
+ }
+
+ return 0;
+}
+
+static int fsl_easrc_resampler_config(struct fsl_asrc *easrc)
+{
+ struct device *dev = &easrc->pdev->dev;
+ struct fsl_easrc_priv *easrc_priv = easrc->private;
+ struct asrc_firmware_hdr *hdr = easrc_priv->firmware_hdr;
+ struct interp_params *interp = easrc_priv->interp;
+ struct interp_params *selected_interp = NULL;
+ unsigned int num_coeff;
+ unsigned int i;
+ u64 *coef;
+ u32 *r;
+ int ret;
+
+ if (!hdr) {
+ dev_err(dev, "firmware not loaded!\n");
+ return -ENODEV;
+ }
+
+ for (i = 0; i < hdr->interp_scen; i++) {
+ if ((interp[i].num_taps - 1) !=
+ bits_taps_to_val(easrc_priv->rs_num_taps))
+ continue;
+
+ coef = interp[i].coeff;
+ selected_interp = &interp[i];
+ dev_dbg(dev, "Selected interp_filter: %u taps - %u phases\n",
+ selected_interp->num_taps,
+ selected_interp->num_phases);
+ break;
+ }
+
+ if (!selected_interp) {
+ dev_err(dev, "failed to get interpreter configuration\n");
+ return -EINVAL;
+ }
+
+ /*
+ * RS_LOW - first half of center tap of the sinc function
+ * RS_HIGH - second half of center tap of the sinc function
+ * This is due to the fact the resampling function must be
+ * symetrical - i.e. odd number of taps
+ */
+ r = (uint32_t *)&selected_interp->center_tap;
+ regmap_write(easrc->regmap, REG_EASRC_RCTCL, EASRC_RCTCL_RS_CL(r[0]));
+ regmap_write(easrc->regmap, REG_EASRC_RCTCH, EASRC_RCTCH_RS_CH(r[1]));
+
+ /*
+ * Write Number of Resampling Coefficient Taps
+ * 00b - 32-Tap Resampling Filter
+ * 01b - 64-Tap Resampling Filter
+ * 10b - 128-Tap Resampling Filter
+ * 11b - N/A
+ */
+ regmap_update_bits(easrc->regmap, REG_EASRC_CRCC,
+ EASRC_CRCC_RS_TAPS_MASK,
+ EASRC_CRCC_RS_TAPS(easrc_priv->rs_num_taps));
+
+ /* Reset prefilter coefficient pointer back to 0 */
+ ret = fsl_easrc_coeff_mem_ptr_reset(easrc, 0, EASRC_RS_COEFF_MEM);
+ if (ret)
+ return ret;
+
+ /*
+ * When the filter is programmed to run in:
+ * 32-tap mode, 16-taps, 128-phases 4-coefficients per phase
+ * 64-tap mode, 32-taps, 64-phases 4-coefficients per phase
+ * 128-tap mode, 64-taps, 32-phases 4-coefficients per phase
+ * This means the number of writes is constant no matter
+ * the mode we are using
+ */
+ num_coeff = 16 * 128 * 4;
+
+ for (i = 0; i < num_coeff; i++) {
+ r = (uint32_t *)&coef[i];
+ regmap_write(easrc->regmap, REG_EASRC_CRCM,
+ EASRC_CRCM_RS_CWD(r[0]));
+ regmap_write(easrc->regmap, REG_EASRC_CRCM,
+ EASRC_CRCM_RS_CWD(r[1]));
+ }
+
+ return 0;
+}
+
+/**
+ * Scale filter coefficients (64 bits float)
+ * For input float32 normalized range (1.0,-1.0) -> output int[16,24,32]:
+ * scale it by multiplying filter coefficients by 2^31
+ * For input int[16, 24, 32] -> output float32
+ * scale it by multiplying filter coefficients by 2^-15, 2^-23, 2^-31
+ * input:
+ * asrc: Structure pointer of fsl_asrc
+ * infilter : Pointer to non-scaled input filter
+ * shift: The multiply factor
+ * output:
+ * outfilter: scaled filter
+ */
+static int fsl_easrc_normalize_filter(struct fsl_asrc *easrc,
+ u64 *infilter,
+ u64 *outfilter,
+ int shift)
+{
+ struct device *dev = &easrc->pdev->dev;
+ u64 coef = *infilter;
+ s64 exp = (coef & 0x7ff0000000000000ll) >> 52;
+ u64 outcoef;
+
+ /*
+ * If exponent is zero (value == 0), or 7ff (value == NaNs)
+ * dont touch the content
+ */
+ if (exp == 0 || exp == 0x7ff) {
+ *outfilter = coef;
+ return 0;
+ }
+
+ /* coef * 2^shift ==> exp + shift */
+ exp += shift;
+
+ if ((shift > 0 && exp >= 0x7ff) || (shift < 0 && exp <= 0)) {
+ dev_err(dev, "coef out of range\n");
+ return -EINVAL;
+ }
+
+ outcoef = (u64)(coef & 0x800FFFFFFFFFFFFFll) + ((u64)exp << 52);
+ *outfilter = outcoef;
+
+ return 0;
+}
+
+static int fsl_easrc_write_pf_coeff_mem(struct fsl_asrc *easrc, int ctx_id,
+ u64 *coef, int n_taps, int shift)
+{
+ struct device *dev = &easrc->pdev->dev;
+ int ret = 0;
+ int i;
+ u32 *r;
+ u64 tmp;
+
+ /* If STx_NUM_TAPS is set to 0x0 then return */
+ if (!n_taps)
+ return 0;
+
+ if (!coef) {
+ dev_err(dev, "coef table is NULL\n");
+ return -EINVAL;
+ }
+
+ /*
+ * When switching between stages, the address pointer
+ * should be reset back to 0x0 before performing a write
+ */
+ ret = fsl_easrc_coeff_mem_ptr_reset(easrc, ctx_id, EASRC_PF_COEFF_MEM);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < (n_taps + 1) / 2; i++) {
+ ret = fsl_easrc_normalize_filter(easrc, &coef[i], &tmp, shift);
+ if (ret)
+ return ret;
+
+ r = (uint32_t *)&tmp;
+ regmap_write(easrc->regmap, REG_EASRC_PCF(ctx_id),
+ EASRC_PCF_CD(r[0]));
+ regmap_write(easrc->regmap, REG_EASRC_PCF(ctx_id),
+ EASRC_PCF_CD(r[1]));
+ }
+
+ return 0;
+}
+
+static int fsl_easrc_prefilter_config(struct fsl_asrc *easrc,
+ unsigned int ctx_id)
+{
+ struct prefil_params *prefil, *selected_prefil = NULL;
+ struct fsl_easrc_ctx_priv *ctx_priv;
+ struct fsl_easrc_priv *easrc_priv;
+ struct asrc_firmware_hdr *hdr;
+ struct fsl_asrc_pair *ctx;
+ struct device *dev;
+ u32 inrate, outrate, offset = 0;
+ u32 in_s_rate, out_s_rate, in_s_fmt, out_s_fmt;
+ int ret, i;
+
+ if (!easrc)
+ return -ENODEV;
+
+ dev = &easrc->pdev->dev;
+
+ if (ctx_id >= EASRC_CTX_MAX_NUM) {
+ dev_err(dev, "Invalid context id[%d]\n", ctx_id);
+ return -EINVAL;
+ }
+
+ easrc_priv = easrc->private;
+
+ ctx = easrc->pair[ctx_id];
+ ctx_priv = ctx->private;
+
+ in_s_rate = ctx_priv->in_params.sample_rate;
+ out_s_rate = ctx_priv->out_params.sample_rate;
+ in_s_fmt = ctx_priv->in_params.sample_format;
+ out_s_fmt = ctx_priv->out_params.sample_format;
+
+ ctx_priv->in_filled_sample = bits_taps_to_val(easrc_priv->rs_num_taps) / 2;
+ ctx_priv->out_missed_sample = ctx_priv->in_filled_sample * out_s_rate / in_s_rate;
+
+ ctx_priv->st1_num_taps = 0;
+ ctx_priv->st2_num_taps = 0;
+
+ regmap_write(easrc->regmap, REG_EASRC_CCE1(ctx_id), 0);
+ regmap_write(easrc->regmap, REG_EASRC_CCE2(ctx_id), 0);
+
+ /*
+ * The audio float point data range is (-1, 1), the asrc would output
+ * all zero for float point input and integer output case, that is to
+ * drop the fractional part of the data directly.
+ *
+ * In order to support float to int conversion or int to float
+ * conversion we need to do special operation on the coefficient to
+ * enlarge/reduce the data to the expected range.
+ *
+ * For float to int case:
+ * Up sampling:
+ * 1. Create a 1 tap filter with center tap (only tap) of 2^31
+ * in 64 bits floating point.
+ * double value = (double)(((uint64_t)1) << 31)
+ * 2. Program 1 tap prefilter with center tap above.
+ *
+ * Down sampling,
+ * 1. If the filter is single stage filter, add "shift" to the exponent
+ * of stage 1 coefficients.
+ * 2. If the filter is two stage filter , add "shift" to the exponent
+ * of stage 2 coefficients.
+ *
+ * The "shift" is 31, same for int16, int24, int32 case.
+ *
+ * For int to float case:
+ * Up sampling:
+ * 1. Create a 1 tap filter with center tap (only tap) of 2^-31
+ * in 64 bits floating point.
+ * 2. Program 1 tap prefilter with center tap above.
+ *
+ * Down sampling,
+ * 1. If the filter is single stage filter, subtract "shift" to the
+ * exponent of stage 1 coefficients.
+ * 2. If the filter is two stage filter , subtract "shift" to the
+ * exponent of stage 2 coefficients.
+ *
+ * The "shift" is 15,23,31, different for int16, int24, int32 case.
+ *
+ */
+ if (out_s_rate >= in_s_rate) {
+ if (out_s_rate == in_s_rate)
+ regmap_update_bits(easrc->regmap,
+ REG_EASRC_CCE1(ctx_id),
+ EASRC_CCE1_RS_BYPASS_MASK,
+ EASRC_CCE1_RS_BYPASS);
+
+ ctx_priv->st1_num_taps = 1;
+ ctx_priv->st1_coeff = &easrc_priv->const_coeff;
+ ctx_priv->st1_num_exp = 1;
+ ctx_priv->st2_num_taps = 0;
+
+ if (in_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE &&
+ out_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE)
+ ctx_priv->st1_addexp = 31;
+ else if (in_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE &&
+ out_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE)
+ ctx_priv->st1_addexp -= ctx_priv->in_params.fmt.addexp;
+ } else {
+ inrate = ctx_priv->in_params.norm_rate;
+ outrate = ctx_priv->out_params.norm_rate;
+
+ hdr = easrc_priv->firmware_hdr;
+ prefil = easrc_priv->prefil;
+
+ for (i = 0; i < hdr->prefil_scen; i++) {
+ if (inrate == prefil[i].insr &&
+ outrate == prefil[i].outsr) {
+ selected_prefil = &prefil[i];
+ dev_dbg(dev, "Selected prefilter: %u insr, %u outsr, %u st1_taps, %u st2_taps\n",
+ selected_prefil->insr,
+ selected_prefil->outsr,
+ selected_prefil->st1_taps,
+ selected_prefil->st2_taps);
+ break;
+ }
+ }
+
+ if (!selected_prefil) {
+ dev_err(dev, "Conversion from in ratio %u(%u) to out ratio %u(%u) is not supported\n",
+ in_s_rate, inrate,
+ out_s_rate, outrate);
+ return -EINVAL;
+ }
+
+ /*
+ * In prefilter coeff array, first st1_num_taps represent the
+ * stage1 prefilter coefficients followed by next st2_num_taps
+ * representing stage 2 coefficients
+ */
+ ctx_priv->st1_num_taps = selected_prefil->st1_taps;
+ ctx_priv->st1_coeff = selected_prefil->coeff;
+ ctx_priv->st1_num_exp = selected_prefil->st1_exp;
+
+ offset = ((selected_prefil->st1_taps + 1) / 2);
+ ctx_priv->st2_num_taps = selected_prefil->st2_taps;
+ ctx_priv->st2_coeff = selected_prefil->coeff + offset;
+
+ if (in_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE &&
+ out_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE) {
+ /* only change stage2 coefficient for 2 stage case */
+ if (ctx_priv->st2_num_taps > 0)
+ ctx_priv->st2_addexp = 31;
+ else
+ ctx_priv->st1_addexp = 31;
+ } else if (in_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE &&
+ out_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE) {
+ if (ctx_priv->st2_num_taps > 0)
+ ctx_priv->st2_addexp -= ctx_priv->in_params.fmt.addexp;
+ else
+ ctx_priv->st1_addexp -= ctx_priv->in_params.fmt.addexp;
+ }
+ }
+
+ ctx_priv->in_filled_sample += (ctx_priv->st1_num_taps / 2) * ctx_priv->st1_num_exp +
+ ctx_priv->st2_num_taps / 2;
+ ctx_priv->out_missed_sample = ctx_priv->in_filled_sample * out_s_rate / in_s_rate;
+
+ if (ctx_priv->in_filled_sample * out_s_rate % in_s_rate != 0)
+ ctx_priv->out_missed_sample += 1;
+ /*
+ * To modify the value of a prefilter coefficient, the user must
+ * perform a write to the register ASRC_PRE_COEFF_FIFOn[COEFF_DATA]
+ * while the respective context RUN_EN bit is set to 0b0
+ */
+ regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx_id),
+ EASRC_CC_EN_MASK, 0);
+
+ if (ctx_priv->st1_num_taps > EASRC_MAX_PF_TAPS) {
+ dev_err(dev, "ST1 taps [%d] mus be lower than %d\n",
+ ctx_priv->st1_num_taps, EASRC_MAX_PF_TAPS);
+ ret = -EINVAL;
+ goto ctx_error;
+ }
+
+ /* Update ctx ST1_NUM_TAPS in Context Control Extended 2 register */
+ regmap_update_bits(easrc->regmap, REG_EASRC_CCE2(ctx_id),
+ EASRC_CCE2_ST1_TAPS_MASK,
+ EASRC_CCE2_ST1_TAPS(ctx_priv->st1_num_taps - 1));
+
+ /* Prefilter Coefficient Write Select to write in ST1 coeff */
+ regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id),
+ EASRC_CCE1_COEF_WS_MASK,
+ EASRC_PF_ST1_COEFF_WR << EASRC_CCE1_COEF_WS_SHIFT);
+
+ ret = fsl_easrc_write_pf_coeff_mem(easrc, ctx_id,
+ ctx_priv->st1_coeff,
+ ctx_priv->st1_num_taps,
+ ctx_priv->st1_addexp);
+ if (ret)
+ goto ctx_error;
+
+ if (ctx_priv->st2_num_taps > 0) {
+ if (ctx_priv->st2_num_taps + ctx_priv->st1_num_taps > EASRC_MAX_PF_TAPS) {
+ dev_err(dev, "ST2 taps [%d] mus be lower than %d\n",
+ ctx_priv->st2_num_taps, EASRC_MAX_PF_TAPS);
+ ret = -EINVAL;
+ goto ctx_error;
+ }
+
+ regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id),
+ EASRC_CCE1_PF_TSEN_MASK,
+ EASRC_CCE1_PF_TSEN);
+ /*
+ * Enable prefilter stage1 writeback floating point
+ * which is used for FLOAT_LE case
+ */
+ regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id),
+ EASRC_CCE1_PF_ST1_WBFP_MASK,
+ EASRC_CCE1_PF_ST1_WBFP);
+
+ regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id),
+ EASRC_CCE1_PF_EXP_MASK,
+ EASRC_CCE1_PF_EXP(ctx_priv->st1_num_exp - 1));
+
+ /* Update ctx ST2_NUM_TAPS in Context Control Extended 2 reg */
+ regmap_update_bits(easrc->regmap, REG_EASRC_CCE2(ctx_id),
+ EASRC_CCE2_ST2_TAPS_MASK,
+ EASRC_CCE2_ST2_TAPS(ctx_priv->st2_num_taps - 1));
+
+ /* Prefilter Coefficient Write Select to write in ST2 coeff */
+ regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id),
+ EASRC_CCE1_COEF_WS_MASK,
+ EASRC_PF_ST2_COEFF_WR << EASRC_CCE1_COEF_WS_SHIFT);
+
+ ret = fsl_easrc_write_pf_coeff_mem(easrc, ctx_id,
+ ctx_priv->st2_coeff,
+ ctx_priv->st2_num_taps,
+ ctx_priv->st2_addexp);
+ if (ret)
+ goto ctx_error;
+ }
+
+ return 0;
+
+ctx_error:
+ return ret;
+}
+
+static int fsl_easrc_max_ch_for_slot(struct fsl_asrc_pair *ctx,
+ struct fsl_easrc_slot *slot)
+{
+ struct fsl_easrc_ctx_priv *ctx_priv = ctx->private;
+ int st1_mem_alloc = 0, st2_mem_alloc = 0;
+ int pf_mem_alloc = 0;
+ int max_channels = 8 - slot->num_channel;
+ int channels = 0;
+
+ if (ctx_priv->st1_num_taps > 0) {
+ if (ctx_priv->st2_num_taps > 0)
+ st1_mem_alloc =
+ (ctx_priv->st1_num_taps - 1) * ctx_priv->st1_num_exp + 1;
+ else
+ st1_mem_alloc = ctx_priv->st1_num_taps;
+ }
+
+ if (ctx_priv->st2_num_taps > 0)
+ st2_mem_alloc = ctx_priv->st2_num_taps;
+
+ pf_mem_alloc = st1_mem_alloc + st2_mem_alloc;
+
+ if (pf_mem_alloc != 0)
+ channels = (6144 - slot->pf_mem_used) / pf_mem_alloc;
+ else
+ channels = 8;
+
+ if (channels < max_channels)
+ max_channels = channels;
+
+ return max_channels;
+}
+
+static int fsl_easrc_config_one_slot(struct fsl_asrc_pair *ctx,
+ struct fsl_easrc_slot *slot,
+ unsigned int slot_ctx_idx,
+ unsigned int *req_channels,
+ unsigned int *start_channel,
+ unsigned int *avail_channel)
+{
+ struct fsl_asrc *easrc = ctx->asrc;
+ struct fsl_easrc_ctx_priv *ctx_priv = ctx->private;
+ int st1_chanxexp, st1_mem_alloc = 0, st2_mem_alloc = 0;
+ unsigned int reg0, reg1, reg2, reg3;
+ unsigned int addr;
+
+ if (slot->slot_index == 0) {
+ reg0 = REG_EASRC_DPCS0R0(slot_ctx_idx);
+ reg1 = REG_EASRC_DPCS0R1(slot_ctx_idx);
+ reg2 = REG_EASRC_DPCS0R2(slot_ctx_idx);
+ reg3 = REG_EASRC_DPCS0R3(slot_ctx_idx);
+ } else {
+ reg0 = REG_EASRC_DPCS1R0(slot_ctx_idx);
+ reg1 = REG_EASRC_DPCS1R1(slot_ctx_idx);
+ reg2 = REG_EASRC_DPCS1R2(slot_ctx_idx);
+ reg3 = REG_EASRC_DPCS1R3(slot_ctx_idx);
+ }
+
+ if (*req_channels <= *avail_channel) {
+ slot->num_channel = *req_channels;
+ *req_channels = 0;
+ } else {
+ slot->num_channel = *avail_channel;
+ *req_channels -= *avail_channel;
+ }
+
+ slot->min_channel = *start_channel;
+ slot->max_channel = *start_channel + slot->num_channel - 1;
+ slot->ctx_index = ctx->index;
+ slot->busy = true;
+ *start_channel += slot->num_channel;
+
+ regmap_update_bits(easrc->regmap, reg0,
+ EASRC_DPCS0R0_MAXCH_MASK,
+ EASRC_DPCS0R0_MAXCH(slot->max_channel));
+
+ regmap_update_bits(easrc->regmap, reg0,
+ EASRC_DPCS0R0_MINCH_MASK,
+ EASRC_DPCS0R0_MINCH(slot->min_channel));
+
+ regmap_update_bits(easrc->regmap, reg0,
+ EASRC_DPCS0R0_NUMCH_MASK,
+ EASRC_DPCS0R0_NUMCH(slot->num_channel - 1));
+
+ regmap_update_bits(easrc->regmap, reg0,
+ EASRC_DPCS0R0_CTXNUM_MASK,
+ EASRC_DPCS0R0_CTXNUM(slot->ctx_index));
+
+ if (ctx_priv->st1_num_taps > 0) {
+ if (ctx_priv->st2_num_taps > 0)
+ st1_mem_alloc =
+ (ctx_priv->st1_num_taps - 1) * slot->num_channel *
+ ctx_priv->st1_num_exp + slot->num_channel;
+ else
+ st1_mem_alloc = ctx_priv->st1_num_taps * slot->num_channel;
+
+ slot->pf_mem_used = st1_mem_alloc;
+ regmap_update_bits(easrc->regmap, reg2,
+ EASRC_DPCS0R2_ST1_MA_MASK,
+ EASRC_DPCS0R2_ST1_MA(st1_mem_alloc));
+
+ if (slot->slot_index == 1)
+ addr = PREFILTER_MEM_LEN - st1_mem_alloc;
+ else
+ addr = 0;
+
+ regmap_update_bits(easrc->regmap, reg2,
+ EASRC_DPCS0R2_ST1_SA_MASK,
+ EASRC_DPCS0R2_ST1_SA(addr));
+ }
+
+ if (ctx_priv->st2_num_taps > 0) {
+ st1_chanxexp = slot->num_channel * (ctx_priv->st1_num_exp - 1);
+
+ regmap_update_bits(easrc->regmap, reg1,
+ EASRC_DPCS0R1_ST1_EXP_MASK,
+ EASRC_DPCS0R1_ST1_EXP(st1_chanxexp));
+
+ st2_mem_alloc = slot->num_channel * ctx_priv->st2_num_taps;
+ slot->pf_mem_used += st2_mem_alloc;
+ regmap_update_bits(easrc->regmap, reg3,
+ EASRC_DPCS0R3_ST2_MA_MASK,
+ EASRC_DPCS0R3_ST2_MA(st2_mem_alloc));
+
+ if (slot->slot_index == 1)
+ addr = PREFILTER_MEM_LEN - st1_mem_alloc - st2_mem_alloc;
+ else
+ addr = st1_mem_alloc;
+
+ regmap_update_bits(easrc->regmap, reg3,
+ EASRC_DPCS0R3_ST2_SA_MASK,
+ EASRC_DPCS0R3_ST2_SA(addr));
+ }
+
+ regmap_update_bits(easrc->regmap, reg0,
+ EASRC_DPCS0R0_EN_MASK, EASRC_DPCS0R0_EN);
+
+ return 0;
+}
+
+/*
+ * fsl_easrc_config_slot
+ *
+ * A single context can be split amongst any of the 4 context processing pipes
+ * in the design.
+ * The total number of channels consumed within the context processor must be
+ * less than or equal to 8. if a single context is configured to contain more
+ * than 8 channels then it must be distributed across multiple context
+ * processing pipe slots.
+ *
+ */
+static int fsl_easrc_config_slot(struct fsl_asrc *easrc, unsigned int ctx_id)
+{
+ struct fsl_easrc_priv *easrc_priv = easrc->private;
+ struct fsl_asrc_pair *ctx = easrc->pair[ctx_id];
+ int req_channels = ctx->channels;
+ int start_channel = 0, avail_channel;
+ struct fsl_easrc_slot *slot0, *slot1;
+ struct fsl_easrc_slot *slota, *slotb;
+ int i, ret;
+
+ if (req_channels <= 0)
+ return -EINVAL;
+
+ for (i = 0; i < EASRC_CTX_MAX_NUM; i++) {
+ slot0 = &easrc_priv->slot[i][0];
+ slot1 = &easrc_priv->slot[i][1];
+
+ if (slot0->busy && slot1->busy) {
+ continue;
+ } else if ((slot0->busy && slot0->ctx_index == ctx->index) ||
+ (slot1->busy && slot1->ctx_index == ctx->index)) {
+ continue;
+ } else if (!slot0->busy) {
+ slota = slot0;
+ slotb = slot1;
+ slota->slot_index = 0;
+ } else if (!slot1->busy) {
+ slota = slot1;
+ slotb = slot0;
+ slota->slot_index = 1;
+ }
+
+ if (!slota || !slotb)
+ continue;
+
+ avail_channel = fsl_easrc_max_ch_for_slot(ctx, slotb);
+ if (avail_channel <= 0)
+ continue;
+
+ ret = fsl_easrc_config_one_slot(ctx, slota, i, &req_channels,
+ &start_channel, &avail_channel);
+ if (ret)
+ return ret;
+
+ if (req_channels > 0)
+ continue;
+ else
+ break;
+ }
+
+ if (req_channels > 0) {
+ dev_err(&easrc->pdev->dev, "no avail slot.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * fsl_easrc_release_slot
+ *
+ * Clear the slot configuration
+ */
+static int fsl_easrc_release_slot(struct fsl_asrc *easrc, unsigned int ctx_id)
+{
+ struct fsl_easrc_priv *easrc_priv = easrc->private;
+ struct fsl_asrc_pair *ctx = easrc->pair[ctx_id];
+ int i;
+
+ for (i = 0; i < EASRC_CTX_MAX_NUM; i++) {
+ if (easrc_priv->slot[i][0].busy &&
+ easrc_priv->slot[i][0].ctx_index == ctx->index) {
+ easrc_priv->slot[i][0].busy = false;
+ easrc_priv->slot[i][0].num_channel = 0;
+ easrc_priv->slot[i][0].pf_mem_used = 0;
+ /* set registers */
+ regmap_write(easrc->regmap, REG_EASRC_DPCS0R0(i), 0);
+ regmap_write(easrc->regmap, REG_EASRC_DPCS0R1(i), 0);
+ regmap_write(easrc->regmap, REG_EASRC_DPCS0R2(i), 0);
+ regmap_write(easrc->regmap, REG_EASRC_DPCS0R3(i), 0);
+ }
+
+ if (easrc_priv->slot[i][1].busy &&
+ easrc_priv->slot[i][1].ctx_index == ctx->index) {
+ easrc_priv->slot[i][1].busy = false;
+ easrc_priv->slot[i][1].num_channel = 0;
+ easrc_priv->slot[i][1].pf_mem_used = 0;
+ /* set registers */
+ regmap_write(easrc->regmap, REG_EASRC_DPCS1R0(i), 0);
+ regmap_write(easrc->regmap, REG_EASRC_DPCS1R1(i), 0);
+ regmap_write(easrc->regmap, REG_EASRC_DPCS1R2(i), 0);
+ regmap_write(easrc->regmap, REG_EASRC_DPCS1R3(i), 0);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * fsl_easrc_config_context
+ *
+ * Configure the register relate with context.
+ */
+int fsl_easrc_config_context(struct fsl_asrc *easrc, unsigned int ctx_id)
+{
+ struct fsl_easrc_ctx_priv *ctx_priv;
+ struct fsl_asrc_pair *ctx;
+ struct device *dev;
+ unsigned long lock_flags;
+ int ret;
+
+ if (!easrc)
+ return -ENODEV;
+
+ dev = &easrc->pdev->dev;
+
+ if (ctx_id >= EASRC_CTX_MAX_NUM) {
+ dev_err(dev, "Invalid context id[%d]\n", ctx_id);
+ return -EINVAL;
+ }
+
+ ctx = easrc->pair[ctx_id];
+
+ ctx_priv = ctx->private;
+
+ fsl_easrc_normalize_rates(ctx);
+
+ ret = fsl_easrc_set_rs_ratio(ctx);
+ if (ret)
+ return ret;
+
+ /* Initialize the context coeficients */
+ ret = fsl_easrc_prefilter_config(easrc, ctx->index);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&easrc->lock, lock_flags);
+ ret = fsl_easrc_config_slot(easrc, ctx->index);
+ spin_unlock_irqrestore(&easrc->lock, lock_flags);
+ if (ret)
+ return ret;
+
+ /*
+ * Both prefilter and resampling filters can use following
+ * initialization modes:
+ * 2 - zero-fil mode
+ * 1 - replication mode
+ * 0 - software control
+ */
+ regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id),
+ EASRC_CCE1_RS_INIT_MASK,
+ EASRC_CCE1_RS_INIT(ctx_priv->rs_init_mode));
+
+ regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id),
+ EASRC_CCE1_PF_INIT_MASK,
+ EASRC_CCE1_PF_INIT(ctx_priv->pf_init_mode));
+
+ /*
+ * Context Input FIFO Watermark
+ * DMA request is generated when input FIFO < FIFO_WTMK
+ */
+ regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx_id),
+ EASRC_CC_FIFO_WTMK_MASK,
+ EASRC_CC_FIFO_WTMK(ctx_priv->in_params.fifo_wtmk));
+
+ /*
+ * Context Output FIFO Watermark
+ * DMA request is generated when output FIFO > FIFO_WTMK
+ * So we set fifo_wtmk -1 to register.
+ */
+ regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx_id),
+ EASRC_COC_FIFO_WTMK_MASK,
+ EASRC_COC_FIFO_WTMK(ctx_priv->out_params.fifo_wtmk - 1));
+
+ /* Number of channels */
+ regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx_id),
+ EASRC_CC_CHEN_MASK,
+ EASRC_CC_CHEN(ctx->channels - 1));
+ return 0;
+}
+
+static int fsl_easrc_process_format(struct fsl_asrc_pair *ctx,
+ struct fsl_easrc_data_fmt *fmt,
+ snd_pcm_format_t raw_fmt)
+{
+ struct fsl_asrc *easrc = ctx->asrc;
+ struct fsl_easrc_priv *easrc_priv = easrc->private;
+ int ret;
+
+ if (!fmt)
+ return -EINVAL;
+
+ /*
+ * Context Input Floating Point Format
+ * 0 - Integer Format
+ * 1 - Single Precision FP Format
+ */
+ fmt->floating_point = !snd_pcm_format_linear(raw_fmt);
+ fmt->sample_pos = 0;
+ fmt->iec958 = 0;
+
+ /* Get the data width */
+ switch (snd_pcm_format_width(raw_fmt)) {
+ case 16:
+ fmt->width = EASRC_WIDTH_16_BIT;
+ fmt->addexp = 15;
+ break;
+ case 20:
+ fmt->width = EASRC_WIDTH_20_BIT;
+ fmt->addexp = 19;
+ break;
+ case 24:
+ fmt->width = EASRC_WIDTH_24_BIT;
+ fmt->addexp = 23;
+ break;
+ case 32:
+ fmt->width = EASRC_WIDTH_32_BIT;
+ fmt->addexp = 31;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (raw_fmt) {
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+ fmt->width = easrc_priv->bps_iec958[ctx->index];
+ fmt->iec958 = 1;
+ fmt->floating_point = 0;
+ if (fmt->width == EASRC_WIDTH_16_BIT) {
+ fmt->sample_pos = 12;
+ fmt->addexp = 15;
+ } else if (fmt->width == EASRC_WIDTH_20_BIT) {
+ fmt->sample_pos = 8;
+ fmt->addexp = 19;
+ } else if (fmt->width == EASRC_WIDTH_24_BIT) {
+ fmt->sample_pos = 4;
+ fmt->addexp = 23;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Data Endianness
+ * 0 - Little-Endian
+ * 1 - Big-Endian
+ */
+ ret = snd_pcm_format_big_endian(raw_fmt);
+ if (ret < 0)
+ return ret;
+
+ fmt->endianness = ret;
+
+ /*
+ * Input Data sign
+ * 0b - Signed Format
+ * 1b - Unsigned Format
+ */
+ fmt->unsign = snd_pcm_format_unsigned(raw_fmt) > 0 ? 1 : 0;
+
+ return 0;
+}
+
+int fsl_easrc_set_ctx_format(struct fsl_asrc_pair *ctx,
+ snd_pcm_format_t *in_raw_format,
+ snd_pcm_format_t *out_raw_format)
+{
+ struct fsl_asrc *easrc = ctx->asrc;
+ struct fsl_easrc_ctx_priv *ctx_priv = ctx->private;
+ struct fsl_easrc_data_fmt *in_fmt = &ctx_priv->in_params.fmt;
+ struct fsl_easrc_data_fmt *out_fmt = &ctx_priv->out_params.fmt;
+ int ret;
+
+ /* Get the bitfield values for input data format */
+ if (in_raw_format && out_raw_format) {
+ ret = fsl_easrc_process_format(ctx, in_fmt, *in_raw_format);
+ if (ret)
+ return ret;
+ }
+
+ regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+ EASRC_CC_BPS_MASK,
+ EASRC_CC_BPS(in_fmt->width));
+ regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+ EASRC_CC_ENDIANNESS_MASK,
+ in_fmt->endianness << EASRC_CC_ENDIANNESS_SHIFT);
+ regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+ EASRC_CC_FMT_MASK,
+ in_fmt->floating_point << EASRC_CC_FMT_SHIFT);
+ regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+ EASRC_CC_INSIGN_MASK,
+ in_fmt->unsign << EASRC_CC_INSIGN_SHIFT);
+
+ /* In Sample Position */
+ regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+ EASRC_CC_SAMPLE_POS_MASK,
+ EASRC_CC_SAMPLE_POS(in_fmt->sample_pos));
+
+ /* Get the bitfield values for input data format */
+ if (in_raw_format && out_raw_format) {
+ ret = fsl_easrc_process_format(ctx, out_fmt, *out_raw_format);
+ if (ret)
+ return ret;
+ }
+
+ regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+ EASRC_COC_BPS_MASK,
+ EASRC_COC_BPS(out_fmt->width));
+ regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+ EASRC_COC_ENDIANNESS_MASK,
+ out_fmt->endianness << EASRC_COC_ENDIANNESS_SHIFT);
+ regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+ EASRC_COC_FMT_MASK,
+ out_fmt->floating_point << EASRC_COC_FMT_SHIFT);
+ regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+ EASRC_COC_OUTSIGN_MASK,
+ out_fmt->unsign << EASRC_COC_OUTSIGN_SHIFT);
+
+ /* Out Sample Position */
+ regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+ EASRC_COC_SAMPLE_POS_MASK,
+ EASRC_COC_SAMPLE_POS(out_fmt->sample_pos));
+
+ regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+ EASRC_COC_IEC_EN_MASK,
+ out_fmt->iec958 << EASRC_COC_IEC_EN_SHIFT);
+
+ return ret;
+}
+
+/*
+ * The ASRC provides interleaving support in hardware to ensure that a
+ * variety of sample sources can be internally combined
+ * to conform with this format. Interleaving parameters are accessed
+ * through the ASRC_CTRL_IN_ACCESSa and ASRC_CTRL_OUT_ACCESSa registers
+ */
+int fsl_easrc_set_ctx_organziation(struct fsl_asrc_pair *ctx)
+{
+ struct fsl_easrc_ctx_priv *ctx_priv;
+ struct device *dev;
+ struct fsl_asrc *easrc;
+
+ if (!ctx)
+ return -ENODEV;
+
+ easrc = ctx->asrc;
+ ctx_priv = ctx->private;
+ dev = &easrc->pdev->dev;
+
+ /* input interleaving parameters */
+ regmap_update_bits(easrc->regmap, REG_EASRC_CIA(ctx->index),
+ EASRC_CIA_ITER_MASK,
+ EASRC_CIA_ITER(ctx_priv->in_params.iterations));
+ regmap_update_bits(easrc->regmap, REG_EASRC_CIA(ctx->index),
+ EASRC_CIA_GRLEN_MASK,
+ EASRC_CIA_GRLEN(ctx_priv->in_params.group_len));
+ regmap_update_bits(easrc->regmap, REG_EASRC_CIA(ctx->index),
+ EASRC_CIA_ACCLEN_MASK,
+ EASRC_CIA_ACCLEN(ctx_priv->in_params.access_len));
+
+ /* output interleaving parameters */
+ regmap_update_bits(easrc->regmap, REG_EASRC_COA(ctx->index),
+ EASRC_COA_ITER_MASK,
+ EASRC_COA_ITER(ctx_priv->out_params.iterations));
+ regmap_update_bits(easrc->regmap, REG_EASRC_COA(ctx->index),
+ EASRC_COA_GRLEN_MASK,
+ EASRC_COA_GRLEN(ctx_priv->out_params.group_len));
+ regmap_update_bits(easrc->regmap, REG_EASRC_COA(ctx->index),
+ EASRC_COA_ACCLEN_MASK,
+ EASRC_COA_ACCLEN(ctx_priv->out_params.access_len));
+
+ return 0;
+}
+
+/*
+ * Request one of the available contexts
+ *
+ * Returns a negative number on error and >=0 as context id
+ * on success
+ */
+int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx)
+{
+ enum asrc_pair_index index = ASRC_INVALID_PAIR;
+ struct fsl_asrc *easrc = ctx->asrc;
+ struct device *dev;
+ unsigned long lock_flags;
+ int ret = 0;
+ int i;
+
+ dev = &easrc->pdev->dev;
+
+ spin_lock_irqsave(&easrc->lock, lock_flags);
+
+ for (i = ASRC_PAIR_A; i < EASRC_CTX_MAX_NUM; i++) {
+ if (easrc->pair[i])
+ continue;
+
+ index = i;
+ break;
+ }
+
+ if (index == ASRC_INVALID_PAIR) {
+ dev_err(dev, "all contexts are busy\n");
+ ret = -EBUSY;
+ } else if (channels > easrc->channel_avail) {
+ dev_err(dev, "can't give the required channels: %d\n",
+ channels);
+ ret = -EINVAL;
+ } else {
+ ctx->index = index;
+ ctx->channels = channels;
+ easrc->pair[index] = ctx;
+ easrc->channel_avail -= channels;
+ }
+
+ spin_unlock_irqrestore(&easrc->lock, lock_flags);
+
+ return ret;
+}
+
+/*
+ * Release the context
+ *
+ * This funciton is mainly doing the revert thing in request context
+ */
+void fsl_easrc_release_context(struct fsl_asrc_pair *ctx)
+{
+ unsigned long lock_flags;
+ struct fsl_asrc *easrc;
+ struct device *dev;
+
+ if (!ctx)
+ return;
+
+ easrc = ctx->asrc;
+ dev = &easrc->pdev->dev;
+
+ spin_lock_irqsave(&easrc->lock, lock_flags);
+
+ fsl_easrc_release_slot(easrc, ctx->index);
+
+ easrc->channel_avail += ctx->channels;
+ easrc->pair[ctx->index] = NULL;
+
+ spin_unlock_irqrestore(&easrc->lock, lock_flags);
+}
+
+/*
+ * Start the context
+ *
+ * Enable the DMA request and context
+ */
+int fsl_easrc_start_context(struct fsl_asrc_pair *ctx)
+{
+ struct fsl_asrc *easrc = ctx->asrc;
+
+ regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+ EASRC_CC_FWMDE_MASK, EASRC_CC_FWMDE);
+ regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+ EASRC_COC_FWMDE_MASK, EASRC_COC_FWMDE);
+ regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+ EASRC_CC_EN_MASK, EASRC_CC_EN);
+ return 0;
+}
+
+/*
+ * Stop the context
+ *
+ * Disable the DMA request and context
+ */
+int fsl_easrc_stop_context(struct fsl_asrc_pair *ctx)
+{
+ struct fsl_asrc *easrc = ctx->asrc;
+ int val, i;
+ int size = 0;
+ int retry = 200;
+
+ regmap_read(easrc->regmap, REG_EASRC_CC(ctx->index), &val);
+
+ if (val & EASRC_CC_EN_MASK) {
+ regmap_update_bits(easrc->regmap,
+ REG_EASRC_CC(ctx->index),
+ EASRC_CC_STOP_MASK, EASRC_CC_STOP);
+ do {
+ regmap_read(easrc->regmap, REG_EASRC_SFS(ctx->index), &val);
+ val &= EASRC_SFS_NSGO_MASK;
+ size = val >> EASRC_SFS_NSGO_SHIFT;
+
+ /* Read FIFO, drop the data */
+ for (i = 0; i < size * ctx->channels; i++)
+ regmap_read(easrc->regmap, REG_EASRC_RDFIFO(ctx->index), &val);
+ /* Check RUN_STOP_DONE */
+ regmap_read(easrc->regmap, REG_EASRC_IRQF, &val);
+ if (val & EASRC_IRQF_RSD(1 << ctx->index)) {
+ /*Clear RUN_STOP_DONE*/
+ regmap_write_bits(easrc->regmap,
+ REG_EASRC_IRQF,
+ EASRC_IRQF_RSD(1 << ctx->index),
+ EASRC_IRQF_RSD(1 << ctx->index));
+ break;
+ }
+ udelay(100);
+ } while (--retry);
+
+ if (retry == 0)
+ dev_warn(&easrc->pdev->dev, "RUN STOP fail\n");
+ }
+
+ regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+ EASRC_CC_EN_MASK | EASRC_CC_STOP_MASK, 0);
+ regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+ EASRC_CC_FWMDE_MASK, 0);
+ regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+ EASRC_COC_FWMDE_MASK, 0);
+ return 0;
+}
+
+struct dma_chan *fsl_easrc_get_dma_channel(struct fsl_asrc_pair *ctx,
+ bool dir)
+{
+ struct fsl_asrc *easrc = ctx->asrc;
+ enum asrc_pair_index index = ctx->index;
+ char name[8];
+
+ /* Example of dma name: ctx0_rx */
+ sprintf(name, "ctx%c_%cx", index + '0', dir == IN ? 'r' : 't');
+
+ return dma_request_slave_channel(&easrc->pdev->dev, name);
+};
+EXPORT_SYMBOL_GPL(fsl_easrc_get_dma_channel);
+
+static const unsigned int easrc_rates[] = {
+ 8000, 11025, 12000, 16000,
+ 22050, 24000, 32000, 44100,
+ 48000, 64000, 88200, 96000,
+ 128000, 176400, 192000, 256000,
+ 352800, 384000, 705600, 768000,
+};
+
+static const struct snd_pcm_hw_constraint_list easrc_rate_constraints = {
+ .count = ARRAY_SIZE(easrc_rates),
+ .list = easrc_rates,
+};
+
+static int fsl_easrc_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &easrc_rate_constraints);
+}
+
+static int fsl_easrc_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct fsl_asrc_pair *ctx = runtime->private_data;
+ int ret;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ret = fsl_easrc_start_context(ctx);
+ if (ret)
+ return ret;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ ret = fsl_easrc_stop_context(ctx);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fsl_easrc_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct fsl_asrc *easrc = snd_soc_dai_get_drvdata(dai);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct device *dev = &easrc->pdev->dev;
+ struct fsl_asrc_pair *ctx = runtime->private_data;
+ struct fsl_easrc_ctx_priv *ctx_priv = ctx->private;
+ unsigned int channels = params_channels(params);
+ unsigned int rate = params_rate(params);
+ snd_pcm_format_t format = params_format(params);
+ int ret;
+
+ ret = fsl_easrc_request_context(channels, ctx);
+ if (ret) {
+ dev_err(dev, "failed to request context\n");
+ return ret;
+ }
+
+ ctx_priv->ctx_streams |= BIT(substream->stream);
+
+ /*
+ * Set the input and output ratio so we can compute
+ * the resampling ratio in RS_LOW/HIGH
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ctx_priv->in_params.sample_rate = rate;
+ ctx_priv->in_params.sample_format = format;
+ ctx_priv->out_params.sample_rate = easrc->asrc_rate;
+ ctx_priv->out_params.sample_format = easrc->asrc_format;
+ } else {
+ ctx_priv->out_params.sample_rate = rate;
+ ctx_priv->out_params.sample_format = format;
+ ctx_priv->in_params.sample_rate = easrc->asrc_rate;
+ ctx_priv->in_params.sample_format = easrc->asrc_format;
+ }
+
+ ctx->channels = channels;
+ ctx_priv->in_params.fifo_wtmk = 0x20;
+ ctx_priv->out_params.fifo_wtmk = 0x20;
+
+ /*
+ * Do only rate conversion and keep the same format for input
+ * and output data
+ */
+ ret = fsl_easrc_set_ctx_format(ctx,
+ &ctx_priv->in_params.sample_format,
+ &ctx_priv->out_params.sample_format);
+ if (ret) {
+ dev_err(dev, "failed to set format %d", ret);
+ return ret;
+ }
+
+ ret = fsl_easrc_config_context(easrc, ctx->index);
+ if (ret) {
+ dev_err(dev, "failed to config context\n");
+ return ret;
+ }
+
+ ctx_priv->in_params.iterations = 1;
+ ctx_priv->in_params.group_len = ctx->channels;
+ ctx_priv->in_params.access_len = ctx->channels;
+ ctx_priv->out_params.iterations = 1;
+ ctx_priv->out_params.group_len = ctx->channels;
+ ctx_priv->out_params.access_len = ctx->channels;
+
+ ret = fsl_easrc_set_ctx_organziation(ctx);
+ if (ret) {
+ dev_err(dev, "failed to set fifo organization\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fsl_easrc_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct fsl_asrc_pair *ctx = runtime->private_data;
+ struct fsl_easrc_ctx_priv *ctx_priv;
+
+ if (!ctx)
+ return -EINVAL;
+
+ ctx_priv = ctx->private;
+
+ if (ctx_priv->ctx_streams & BIT(substream->stream)) {
+ ctx_priv->ctx_streams &= ~BIT(substream->stream);
+ fsl_easrc_release_context(ctx);
+ }
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops fsl_easrc_dai_ops = {
+ .startup = fsl_easrc_startup,
+ .trigger = fsl_easrc_trigger,
+ .hw_params = fsl_easrc_hw_params,
+ .hw_free = fsl_easrc_hw_free,
+};
+
+static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_asrc *easrc = dev_get_drvdata(cpu_dai->dev);
+
+ snd_soc_dai_init_dma_data(cpu_dai,
+ &easrc->dma_params_tx,
+ &easrc->dma_params_rx);
+ return 0;
+}
+
+static struct snd_soc_dai_driver fsl_easrc_dai = {
+ .probe = fsl_easrc_dai_probe,
+ .playback = {
+ .stream_name = "ASRC-Playback",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 768000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_EASRC_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ASRC-Capture",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 768000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_EASRC_FORMATS |
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+ },
+ .ops = &fsl_easrc_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_easrc_component = {
+ .name = "fsl-easrc-dai",
+ .controls = fsl_easrc_snd_controls,
+ .num_controls = ARRAY_SIZE(fsl_easrc_snd_controls),
+};
+
+static const struct reg_default fsl_easrc_reg_defaults[] = {
+ {REG_EASRC_WRFIFO(0), 0x00000000},
+ {REG_EASRC_WRFIFO(1), 0x00000000},
+ {REG_EASRC_WRFIFO(2), 0x00000000},
+ {REG_EASRC_WRFIFO(3), 0x00000000},
+ {REG_EASRC_RDFIFO(0), 0x00000000},
+ {REG_EASRC_RDFIFO(1), 0x00000000},
+ {REG_EASRC_RDFIFO(2), 0x00000000},
+ {REG_EASRC_RDFIFO(3), 0x00000000},
+ {REG_EASRC_CC(0), 0x00000000},
+ {REG_EASRC_CC(1), 0x00000000},
+ {REG_EASRC_CC(2), 0x00000000},
+ {REG_EASRC_CC(3), 0x00000000},
+ {REG_EASRC_CCE1(0), 0x00000000},
+ {REG_EASRC_CCE1(1), 0x00000000},
+ {REG_EASRC_CCE1(2), 0x00000000},
+ {REG_EASRC_CCE1(3), 0x00000000},
+ {REG_EASRC_CCE2(0), 0x00000000},
+ {REG_EASRC_CCE2(1), 0x00000000},
+ {REG_EASRC_CCE2(2), 0x00000000},
+ {REG_EASRC_CCE2(3), 0x00000000},
+ {REG_EASRC_CIA(0), 0x00000000},
+ {REG_EASRC_CIA(1), 0x00000000},
+ {REG_EASRC_CIA(2), 0x00000000},
+ {REG_EASRC_CIA(3), 0x00000000},
+ {REG_EASRC_DPCS0R0(0), 0x00000000},
+ {REG_EASRC_DPCS0R0(1), 0x00000000},
+ {REG_EASRC_DPCS0R0(2), 0x00000000},
+ {REG_EASRC_DPCS0R0(3), 0x00000000},
+ {REG_EASRC_DPCS0R1(0), 0x00000000},
+ {REG_EASRC_DPCS0R1(1), 0x00000000},
+ {REG_EASRC_DPCS0R1(2), 0x00000000},
+ {REG_EASRC_DPCS0R1(3), 0x00000000},
+ {REG_EASRC_DPCS0R2(0), 0x00000000},
+ {REG_EASRC_DPCS0R2(1), 0x00000000},
+ {REG_EASRC_DPCS0R2(2), 0x00000000},
+ {REG_EASRC_DPCS0R2(3), 0x00000000},
+ {REG_EASRC_DPCS0R3(0), 0x00000000},
+ {REG_EASRC_DPCS0R3(1), 0x00000000},
+ {REG_EASRC_DPCS0R3(2), 0x00000000},
+ {REG_EASRC_DPCS0R3(3), 0x00000000},
+ {REG_EASRC_DPCS1R0(0), 0x00000000},
+ {REG_EASRC_DPCS1R0(1), 0x00000000},
+ {REG_EASRC_DPCS1R0(2), 0x00000000},
+ {REG_EASRC_DPCS1R0(3), 0x00000000},
+ {REG_EASRC_DPCS1R1(0), 0x00000000},
+ {REG_EASRC_DPCS1R1(1), 0x00000000},
+ {REG_EASRC_DPCS1R1(2), 0x00000000},
+ {REG_EASRC_DPCS1R1(3), 0x00000000},
+ {REG_EASRC_DPCS1R2(0), 0x00000000},
+ {REG_EASRC_DPCS1R2(1), 0x00000000},
+ {REG_EASRC_DPCS1R2(2), 0x00000000},
+ {REG_EASRC_DPCS1R2(3), 0x00000000},
+ {REG_EASRC_DPCS1R3(0), 0x00000000},
+ {REG_EASRC_DPCS1R3(1), 0x00000000},
+ {REG_EASRC_DPCS1R3(2), 0x00000000},
+ {REG_EASRC_DPCS1R3(3), 0x00000000},
+ {REG_EASRC_COC(0), 0x00000000},
+ {REG_EASRC_COC(1), 0x00000000},
+ {REG_EASRC_COC(2), 0x00000000},
+ {REG_EASRC_COC(3), 0x00000000},
+ {REG_EASRC_COA(0), 0x00000000},
+ {REG_EASRC_COA(1), 0x00000000},
+ {REG_EASRC_COA(2), 0x00000000},
+ {REG_EASRC_COA(3), 0x00000000},
+ {REG_EASRC_SFS(0), 0x00000000},
+ {REG_EASRC_SFS(1), 0x00000000},
+ {REG_EASRC_SFS(2), 0x00000000},
+ {REG_EASRC_SFS(3), 0x00000000},
+ {REG_EASRC_RRL(0), 0x00000000},
+ {REG_EASRC_RRL(1), 0x00000000},
+ {REG_EASRC_RRL(2), 0x00000000},
+ {REG_EASRC_RRL(3), 0x00000000},
+ {REG_EASRC_RRH(0), 0x00000000},
+ {REG_EASRC_RRH(1), 0x00000000},
+ {REG_EASRC_RRH(2), 0x00000000},
+ {REG_EASRC_RRH(3), 0x00000000},
+ {REG_EASRC_RUC(0), 0x00000000},
+ {REG_EASRC_RUC(1), 0x00000000},
+ {REG_EASRC_RUC(2), 0x00000000},
+ {REG_EASRC_RUC(3), 0x00000000},
+ {REG_EASRC_RUR(0), 0x7FFFFFFF},
+ {REG_EASRC_RUR(1), 0x7FFFFFFF},
+ {REG_EASRC_RUR(2), 0x7FFFFFFF},
+ {REG_EASRC_RUR(3), 0x7FFFFFFF},
+ {REG_EASRC_RCTCL, 0x00000000},
+ {REG_EASRC_RCTCH, 0x00000000},
+ {REG_EASRC_PCF(0), 0x00000000},
+ {REG_EASRC_PCF(1), 0x00000000},
+ {REG_EASRC_PCF(2), 0x00000000},
+ {REG_EASRC_PCF(3), 0x00000000},
+ {REG_EASRC_CRCM, 0x00000000},
+ {REG_EASRC_CRCC, 0x00000000},
+ {REG_EASRC_IRQC, 0x00000FFF},
+ {REG_EASRC_IRQF, 0x00000000},
+ {REG_EASRC_CS0(0), 0x00000000},
+ {REG_EASRC_CS0(1), 0x00000000},
+ {REG_EASRC_CS0(2), 0x00000000},
+ {REG_EASRC_CS0(3), 0x00000000},
+ {REG_EASRC_CS1(0), 0x00000000},
+ {REG_EASRC_CS1(1), 0x00000000},
+ {REG_EASRC_CS1(2), 0x00000000},
+ {REG_EASRC_CS1(3), 0x00000000},
+ {REG_EASRC_CS2(0), 0x00000000},
+ {REG_EASRC_CS2(1), 0x00000000},
+ {REG_EASRC_CS2(2), 0x00000000},
+ {REG_EASRC_CS2(3), 0x00000000},
+ {REG_EASRC_CS3(0), 0x00000000},
+ {REG_EASRC_CS3(1), 0x00000000},
+ {REG_EASRC_CS3(2), 0x00000000},
+ {REG_EASRC_CS3(3), 0x00000000},
+ {REG_EASRC_CS4(0), 0x00000000},
+ {REG_EASRC_CS4(1), 0x00000000},
+ {REG_EASRC_CS4(2), 0x00000000},
+ {REG_EASRC_CS4(3), 0x00000000},
+ {REG_EASRC_CS5(0), 0x00000000},
+ {REG_EASRC_CS5(1), 0x00000000},
+ {REG_EASRC_CS5(2), 0x00000000},
+ {REG_EASRC_CS5(3), 0x00000000},
+ {REG_EASRC_DBGC, 0x00000000},
+ {REG_EASRC_DBGS, 0x00000000},
+};
+
+static const struct regmap_range fsl_easrc_readable_ranges[] = {
+ regmap_reg_range(REG_EASRC_RDFIFO(0), REG_EASRC_RCTCH),
+ regmap_reg_range(REG_EASRC_PCF(0), REG_EASRC_PCF(3)),
+ regmap_reg_range(REG_EASRC_CRCC, REG_EASRC_DBGS),
+};
+
+static const struct regmap_access_table fsl_easrc_readable_table = {
+ .yes_ranges = fsl_easrc_readable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(fsl_easrc_readable_ranges),
+};
+
+static const struct regmap_range fsl_easrc_writeable_ranges[] = {
+ regmap_reg_range(REG_EASRC_WRFIFO(0), REG_EASRC_WRFIFO(3)),
+ regmap_reg_range(REG_EASRC_CC(0), REG_EASRC_COA(3)),
+ regmap_reg_range(REG_EASRC_RRL(0), REG_EASRC_RCTCH),
+ regmap_reg_range(REG_EASRC_PCF(0), REG_EASRC_DBGC),
+};
+
+static const struct regmap_access_table fsl_easrc_writeable_table = {
+ .yes_ranges = fsl_easrc_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(fsl_easrc_writeable_ranges),
+};
+
+static const struct regmap_range fsl_easrc_volatileable_ranges[] = {
+ regmap_reg_range(REG_EASRC_RDFIFO(0), REG_EASRC_RDFIFO(3)),
+ regmap_reg_range(REG_EASRC_SFS(0), REG_EASRC_SFS(3)),
+ regmap_reg_range(REG_EASRC_IRQF, REG_EASRC_IRQF),
+ regmap_reg_range(REG_EASRC_DBGS, REG_EASRC_DBGS),
+};
+
+static const struct regmap_access_table fsl_easrc_volatileable_table = {
+ .yes_ranges = fsl_easrc_volatileable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(fsl_easrc_volatileable_ranges),
+};
+
+static const struct regmap_config fsl_easrc_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+
+ .max_register = REG_EASRC_DBGS,
+ .reg_defaults = fsl_easrc_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(fsl_easrc_reg_defaults),
+ .rd_table = &fsl_easrc_readable_table,
+ .wr_table = &fsl_easrc_writeable_table,
+ .volatile_table = &fsl_easrc_volatileable_table,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+#ifdef DEBUG
+static void fsl_easrc_dump_firmware(struct fsl_asrc *easrc)
+{
+ struct fsl_easrc_priv *easrc_priv = easrc->private;
+ struct asrc_firmware_hdr *firm = easrc_priv->firmware_hdr;
+ struct interp_params *interp = easrc_priv->interp;
+ struct prefil_params *prefil = easrc_priv->prefil;
+ struct device *dev = &easrc->pdev->dev;
+ int i;
+
+ if (firm->magic != FIRMWARE_MAGIC) {
+ dev_err(dev, "Wrong magic. Something went wrong!");
+ return;
+ }
+
+ dev_dbg(dev, "Firmware v%u dump:\n", firm->firmware_version);
+ dev_dbg(dev, "Num prefilter scenarios: %u\n", firm->prefil_scen);
+ dev_dbg(dev, "Num interpolation scenarios: %u\n", firm->interp_scen);
+ dev_dbg(dev, "\nInterpolation scenarios:\n");
+
+ for (i = 0; i < firm->interp_scen; i++) {
+ if (interp[i].magic != FIRMWARE_MAGIC) {
+ dev_dbg(dev, "%d. wrong interp magic: %x\n",
+ i, interp[i].magic);
+ continue;
+ }
+ dev_dbg(dev, "%d. taps: %u, phases: %u, center: %llu\n", i,
+ interp[i].num_taps, interp[i].num_phases,
+ interp[i].center_tap);
+ }
+
+ for (i = 0; i < firm->prefil_scen; i++) {
+ if (prefil[i].magic != FIRMWARE_MAGIC) {
+ dev_dbg(dev, "%d. wrong prefil magic: %x\n",
+ i, prefil[i].magic);
+ continue;
+ }
+ dev_dbg(dev, "%d. insr: %u, outsr: %u, st1: %u, st2: %u\n", i,
+ prefil[i].insr, prefil[i].outsr,
+ prefil[i].st1_taps, prefil[i].st2_taps);
+ }
+
+ dev_dbg(dev, "end of firmware dump\n");
+}
+#endif
+
+static int fsl_easrc_get_firmware(struct fsl_asrc *easrc)
+{
+ struct fsl_easrc_priv *easrc_priv;
+ const struct firmware **fw_p;
+ u32 pnum, inum, offset;
+ const u8 *data;
+ int ret;
+
+ if (!easrc)
+ return -EINVAL;
+
+ easrc_priv = easrc->private;
+ fw_p = &easrc_priv->fw;
+
+ ret = request_firmware(fw_p, easrc_priv->fw_name, &easrc->pdev->dev);
+ if (ret)
+ return ret;
+
+ data = easrc_priv->fw->data;
+
+ easrc_priv->firmware_hdr = (struct asrc_firmware_hdr *)data;
+ pnum = easrc_priv->firmware_hdr->prefil_scen;
+ inum = easrc_priv->firmware_hdr->interp_scen;
+
+ if (inum) {
+ offset = sizeof(struct asrc_firmware_hdr);
+ easrc_priv->interp = (struct interp_params *)(data + offset);
+ }
+
+ if (pnum) {
+ offset = sizeof(struct asrc_firmware_hdr) +
+ inum * sizeof(struct interp_params);
+ easrc_priv->prefil = (struct prefil_params *)(data + offset);
+ }
+
+#ifdef DEBUG
+ fsl_easrc_dump_firmware(easrc);
+#endif
+
+ return 0;
+}
+
+static irqreturn_t fsl_easrc_isr(int irq, void *dev_id)
+{
+ struct fsl_asrc *easrc = (struct fsl_asrc *)dev_id;
+ struct device *dev = &easrc->pdev->dev;
+ int val;
+
+ regmap_read(easrc->regmap, REG_EASRC_IRQF, &val);
+
+ if (val & EASRC_IRQF_OER_MASK)
+ dev_dbg(dev, "output FIFO underflow\n");
+
+ if (val & EASRC_IRQF_IFO_MASK)
+ dev_dbg(dev, "input FIFO overflow\n");
+
+ return IRQ_HANDLED;
+}
+
+static int fsl_easrc_get_fifo_addr(u8 dir, enum asrc_pair_index index)
+{
+ return REG_EASRC_FIFO(dir, index);
+}
+
+static const struct of_device_id fsl_easrc_dt_ids[] = {
+ { .compatible = "fsl,imx8mn-easrc",},
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_easrc_dt_ids);
+
+static int fsl_easrc_probe(struct platform_device *pdev)
+{
+ struct fsl_easrc_priv *easrc_priv;
+ struct device *dev = &pdev->dev;
+ struct fsl_asrc *easrc;
+ struct resource *res;
+ struct device_node *np;
+ void __iomem *regs;
+ int ret, irq;
+
+ easrc = devm_kzalloc(dev, sizeof(*easrc), GFP_KERNEL);
+ if (!easrc)
+ return -ENOMEM;
+
+ easrc_priv = devm_kzalloc(dev, sizeof(*easrc_priv), GFP_KERNEL);
+ if (!easrc_priv)
+ return -ENOMEM;
+
+ easrc->pdev = pdev;
+ easrc->private = easrc_priv;
+ np = dev->of_node;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs)) {
+ dev_err(&pdev->dev, "failed ioremap\n");
+ return PTR_ERR(regs);
+ }
+
+ easrc->paddr = res->start;
+
+ easrc->regmap = devm_regmap_init_mmio_clk(dev, "mem", regs,
+ &fsl_easrc_regmap_config);
+ if (IS_ERR(easrc->regmap)) {
+ dev_err(dev, "failed to init regmap");
+ return PTR_ERR(easrc->regmap);
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "no irq for node %pOF\n", np);
+ return irq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, fsl_easrc_isr, 0,
+ dev_name(dev), easrc);
+ if (ret) {
+ dev_err(dev, "failed to claim irq %u: %d\n", irq, ret);
+ return ret;
+ }
+
+ easrc->mem_clk = devm_clk_get(dev, "mem");
+ if (IS_ERR(easrc->mem_clk)) {
+ dev_err(dev, "failed to get mem clock\n");
+ return PTR_ERR(easrc->mem_clk);
+ }
+
+ /* Set default value */
+ easrc->channel_avail = 32;
+ easrc->get_dma_channel = fsl_easrc_get_dma_channel;
+ easrc->request_pair = fsl_easrc_request_context;
+ easrc->release_pair = fsl_easrc_release_context;
+ easrc->get_fifo_addr = fsl_easrc_get_fifo_addr;
+ easrc->pair_priv_size = sizeof(struct fsl_easrc_ctx_priv);
+
+ easrc_priv->rs_num_taps = EASRC_RS_32_TAPS;
+ easrc_priv->const_coeff = 0x3FF0000000000000;
+
+ ret = of_property_read_u32(np, "fsl,asrc-rate", &easrc->asrc_rate);
+ if (ret) {
+ dev_err(dev, "failed to asrc rate\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "fsl,asrc-format", &easrc->asrc_format);
+ if (ret) {
+ dev_err(dev, "failed to asrc format\n");
+ return ret;
+ }
+
+ if (!(FSL_EASRC_FORMATS & (1ULL << easrc->asrc_format))) {
+ dev_warn(dev, "unsupported format, switching to S24_LE\n");
+ easrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
+ }
+
+ ret = of_property_read_string(np, "firmware-name",
+ &easrc_priv->fw_name);
+ if (ret) {
+ dev_err(dev, "failed to get firmware name\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, easrc);
+ pm_runtime_enable(dev);
+
+ spin_lock_init(&easrc->lock);
+
+ regcache_cache_only(easrc->regmap, true);
+
+ ret = devm_snd_soc_register_component(dev, &fsl_easrc_component,
+ &fsl_easrc_dai, 1);
+ if (ret) {
+ dev_err(dev, "failed to register ASoC DAI\n");
+ return ret;
+ }
+
+ ret = devm_snd_soc_register_component(dev, &fsl_asrc_component,
+ NULL, 0);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register ASoC platform\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fsl_easrc_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static __maybe_unused int fsl_easrc_runtime_suspend(struct device *dev)
+{
+ struct fsl_asrc *easrc = dev_get_drvdata(dev);
+ struct fsl_easrc_priv *easrc_priv = easrc->private;
+ unsigned long lock_flags;
+
+ regcache_cache_only(easrc->regmap, true);
+
+ clk_disable_unprepare(easrc->mem_clk);
+
+ spin_lock_irqsave(&easrc->lock, lock_flags);
+ easrc_priv->firmware_loaded = 0;
+ spin_unlock_irqrestore(&easrc->lock, lock_flags);
+
+ return 0;
+}
+
+static __maybe_unused int fsl_easrc_runtime_resume(struct device *dev)
+{
+ struct fsl_asrc *easrc = dev_get_drvdata(dev);
+ struct fsl_easrc_priv *easrc_priv = easrc->private;
+ struct fsl_easrc_ctx_priv *ctx_priv;
+ struct fsl_asrc_pair *ctx;
+ unsigned long lock_flags;
+ int ret;
+ int i;
+
+ ret = clk_prepare_enable(easrc->mem_clk);
+ if (ret)
+ return ret;
+
+ regcache_cache_only(easrc->regmap, false);
+ regcache_mark_dirty(easrc->regmap);
+ regcache_sync(easrc->regmap);
+
+ spin_lock_irqsave(&easrc->lock, lock_flags);
+ if (easrc_priv->firmware_loaded) {
+ spin_unlock_irqrestore(&easrc->lock, lock_flags);
+ goto skip_load;
+ }
+ easrc_priv->firmware_loaded = 1;
+ spin_unlock_irqrestore(&easrc->lock, lock_flags);
+
+ ret = fsl_easrc_get_firmware(easrc);
+ if (ret) {
+ dev_err(dev, "failed to get firmware\n");
+ goto disable_mem_clk;
+ }
+
+ /*
+ * Write Resampling Coefficients
+ * The coefficient RAM must be configured prior to beginning of
+ * any context processing within the ASRC
+ */
+ ret = fsl_easrc_resampler_config(easrc);
+ if (ret) {
+ dev_err(dev, "resampler config failed\n");
+ goto disable_mem_clk;
+ }
+
+ for (i = ASRC_PAIR_A; i < EASRC_CTX_MAX_NUM; i++) {
+ ctx = easrc->pair[i];
+ if (!ctx)
+ continue;
+
+ ctx_priv = ctx->private;
+ fsl_easrc_set_rs_ratio(ctx);
+ ctx_priv->out_missed_sample = ctx_priv->in_filled_sample *
+ ctx_priv->out_params.sample_rate /
+ ctx_priv->in_params.sample_rate;
+ if (ctx_priv->in_filled_sample * ctx_priv->out_params.sample_rate
+ % ctx_priv->in_params.sample_rate != 0)
+ ctx_priv->out_missed_sample += 1;
+
+ ret = fsl_easrc_write_pf_coeff_mem(easrc, i,
+ ctx_priv->st1_coeff,
+ ctx_priv->st1_num_taps,
+ ctx_priv->st1_addexp);
+ if (ret)
+ goto disable_mem_clk;
+
+ ret = fsl_easrc_write_pf_coeff_mem(easrc, i,
+ ctx_priv->st2_coeff,
+ ctx_priv->st2_num_taps,
+ ctx_priv->st2_addexp);
+ if (ret)
+ goto disable_mem_clk;
+ }
+
+skip_load:
+ return 0;
+
+disable_mem_clk:
+ clk_disable_unprepare(easrc->mem_clk);
+ return ret;
+}
+
+static const struct dev_pm_ops fsl_easrc_pm_ops = {
+ SET_RUNTIME_PM_OPS(fsl_easrc_runtime_suspend,
+ fsl_easrc_runtime_resume,
+ NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_easrc_driver = {
+ .probe = fsl_easrc_probe,
+ .remove = fsl_easrc_remove,
+ .driver = {
+ .name = "fsl-easrc",
+ .pm = &fsl_easrc_pm_ops,
+ .of_match_table = fsl_easrc_dt_ids,
+ },
+};
+module_platform_driver(fsl_easrc_driver);
+
+MODULE_DESCRIPTION("NXP Enhanced Asynchronous Sample Rate (eASRC) driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_easrc.h b/sound/soc/fsl/fsl_easrc.h
new file mode 100644
index 000000000000..30620d56252c
--- /dev/null
+++ b/sound/soc/fsl/fsl_easrc.h
@@ -0,0 +1,651 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 NXP
+ */
+
+#ifndef _FSL_EASRC_H
+#define _FSL_EASRC_H
+
+#include <sound/asound.h>
+#include <linux/platform_data/dma-imx.h>
+
+#include "fsl_asrc_common.h"
+
+/* EASRC Register Map */
+
+/* ASRC Input Write FIFO */
+#define REG_EASRC_WRFIFO(ctx) (0x000 + 4 * (ctx))
+/* ASRC Output Read FIFO */
+#define REG_EASRC_RDFIFO(ctx) (0x010 + 4 * (ctx))
+/* ASRC Context Control */
+#define REG_EASRC_CC(ctx) (0x020 + 4 * (ctx))
+/* ASRC Context Control Extended 1 */
+#define REG_EASRC_CCE1(ctx) (0x030 + 4 * (ctx))
+/* ASRC Context Control Extended 2 */
+#define REG_EASRC_CCE2(ctx) (0x040 + 4 * (ctx))
+/* ASRC Control Input Access */
+#define REG_EASRC_CIA(ctx) (0x050 + 4 * (ctx))
+/* ASRC Datapath Processor Control Slot0 */
+#define REG_EASRC_DPCS0R0(ctx) (0x060 + 4 * (ctx))
+#define REG_EASRC_DPCS0R1(ctx) (0x070 + 4 * (ctx))
+#define REG_EASRC_DPCS0R2(ctx) (0x080 + 4 * (ctx))
+#define REG_EASRC_DPCS0R3(ctx) (0x090 + 4 * (ctx))
+/* ASRC Datapath Processor Control Slot1 */
+#define REG_EASRC_DPCS1R0(ctx) (0x0A0 + 4 * (ctx))
+#define REG_EASRC_DPCS1R1(ctx) (0x0B0 + 4 * (ctx))
+#define REG_EASRC_DPCS1R2(ctx) (0x0C0 + 4 * (ctx))
+#define REG_EASRC_DPCS1R3(ctx) (0x0D0 + 4 * (ctx))
+/* ASRC Context Output Control */
+#define REG_EASRC_COC(ctx) (0x0E0 + 4 * (ctx))
+/* ASRC Control Output Access */
+#define REG_EASRC_COA(ctx) (0x0F0 + 4 * (ctx))
+/* ASRC Sample FIFO Status */
+#define REG_EASRC_SFS(ctx) (0x100 + 4 * (ctx))
+/* ASRC Resampling Ratio Low */
+#define REG_EASRC_RRL(ctx) (0x110 + 8 * (ctx))
+/* ASRC Resampling Ratio High */
+#define REG_EASRC_RRH(ctx) (0x114 + 8 * (ctx))
+/* ASRC Resampling Ratio Update Control */
+#define REG_EASRC_RUC(ctx) (0x130 + 4 * (ctx))
+/* ASRC Resampling Ratio Update Rate */
+#define REG_EASRC_RUR(ctx) (0x140 + 4 * (ctx))
+/* ASRC Resampling Center Tap Coefficient Low */
+#define REG_EASRC_RCTCL (0x150)
+/* ASRC Resampling Center Tap Coefficient High */
+#define REG_EASRC_RCTCH (0x154)
+/* ASRC Prefilter Coefficient FIFO */
+#define REG_EASRC_PCF(ctx) (0x160 + 4 * (ctx))
+/* ASRC Context Resampling Coefficient Memory */
+#define REG_EASRC_CRCM 0x170
+/* ASRC Context Resampling Coefficient Control*/
+#define REG_EASRC_CRCC 0x174
+/* ASRC Interrupt Control */
+#define REG_EASRC_IRQC 0x178
+/* ASRC Interrupt Status Flags */
+#define REG_EASRC_IRQF 0x17C
+/* ASRC Channel Status 0 */
+#define REG_EASRC_CS0(ctx) (0x180 + 4 * (ctx))
+/* ASRC Channel Status 1 */
+#define REG_EASRC_CS1(ctx) (0x190 + 4 * (ctx))
+/* ASRC Channel Status 2 */
+#define REG_EASRC_CS2(ctx) (0x1A0 + 4 * (ctx))
+/* ASRC Channel Status 3 */
+#define REG_EASRC_CS3(ctx) (0x1B0 + 4 * (ctx))
+/* ASRC Channel Status 4 */
+#define REG_EASRC_CS4(ctx) (0x1C0 + 4 * (ctx))
+/* ASRC Channel Status 5 */
+#define REG_EASRC_CS5(ctx) (0x1D0 + 4 * (ctx))
+/* ASRC Debug Control Register */
+#define REG_EASRC_DBGC 0x1E0
+/* ASRC Debug Status Register */
+#define REG_EASRC_DBGS 0x1E4
+
+#define REG_EASRC_FIFO(x, ctx) (x == IN ? REG_EASRC_WRFIFO(ctx) \
+ : REG_EASRC_RDFIFO(ctx))
+
+/* ASRC Context Control (CC) */
+#define EASRC_CC_EN_SHIFT 31
+#define EASRC_CC_EN_MASK BIT(EASRC_CC_EN_SHIFT)
+#define EASRC_CC_EN BIT(EASRC_CC_EN_SHIFT)
+#define EASRC_CC_STOP_SHIFT 29
+#define EASRC_CC_STOP_MASK BIT(EASRC_CC_STOP_SHIFT)
+#define EASRC_CC_STOP BIT(EASRC_CC_STOP_SHIFT)
+#define EASRC_CC_FWMDE_SHIFT 28
+#define EASRC_CC_FWMDE_MASK BIT(EASRC_CC_FWMDE_SHIFT)
+#define EASRC_CC_FWMDE BIT(EASRC_CC_FWMDE_SHIFT)
+#define EASRC_CC_FIFO_WTMK_SHIFT 16
+#define EASRC_CC_FIFO_WTMK_WIDTH 7
+#define EASRC_CC_FIFO_WTMK_MASK ((BIT(EASRC_CC_FIFO_WTMK_WIDTH) - 1) \
+ << EASRC_CC_FIFO_WTMK_SHIFT)
+#define EASRC_CC_FIFO_WTMK(v) (((v) << EASRC_CC_FIFO_WTMK_SHIFT) \
+ & EASRC_CC_FIFO_WTMK_MASK)
+#define EASRC_CC_SAMPLE_POS_SHIFT 11
+#define EASRC_CC_SAMPLE_POS_WIDTH 5
+#define EASRC_CC_SAMPLE_POS_MASK ((BIT(EASRC_CC_SAMPLE_POS_WIDTH) - 1) \
+ << EASRC_CC_SAMPLE_POS_SHIFT)
+#define EASRC_CC_SAMPLE_POS(v) (((v) << EASRC_CC_SAMPLE_POS_SHIFT) \
+ & EASRC_CC_SAMPLE_POS_MASK)
+#define EASRC_CC_ENDIANNESS_SHIFT 10
+#define EASRC_CC_ENDIANNESS_MASK BIT(EASRC_CC_ENDIANNESS_SHIFT)
+#define EASRC_CC_ENDIANNESS BIT(EASRC_CC_ENDIANNESS_SHIFT)
+#define EASRC_CC_BPS_SHIFT 8
+#define EASRC_CC_BPS_WIDTH 2
+#define EASRC_CC_BPS_MASK ((BIT(EASRC_CC_BPS_WIDTH) - 1) \
+ << EASRC_CC_BPS_SHIFT)
+#define EASRC_CC_BPS(v) (((v) << EASRC_CC_BPS_SHIFT) \
+ & EASRC_CC_BPS_MASK)
+#define EASRC_CC_FMT_SHIFT 7
+#define EASRC_CC_FMT_MASK BIT(EASRC_CC_FMT_SHIFT)
+#define EASRC_CC_FMT BIT(EASRC_CC_FMT_SHIFT)
+#define EASRC_CC_INSIGN_SHIFT 6
+#define EASRC_CC_INSIGN_MASK BIT(EASRC_CC_INSIGN_SHIFT)
+#define EASRC_CC_INSIGN BIT(EASRC_CC_INSIGN_SHIFT)
+#define EASRC_CC_CHEN_SHIFT 0
+#define EASRC_CC_CHEN_WIDTH 5
+#define EASRC_CC_CHEN_MASK ((BIT(EASRC_CC_CHEN_WIDTH) - 1) \
+ << EASRC_CC_CHEN_SHIFT)
+#define EASRC_CC_CHEN(v) (((v) << EASRC_CC_CHEN_SHIFT) \
+ & EASRC_CC_CHEN_MASK)
+
+/* ASRC Context Control Extended 1 (CCE1) */
+#define EASRC_CCE1_COEF_WS_SHIFT 25
+#define EASRC_CCE1_COEF_WS_MASK BIT(EASRC_CCE1_COEF_WS_SHIFT)
+#define EASRC_CCE1_COEF_WS BIT(EASRC_CCE1_COEF_WS_SHIFT)
+#define EASRC_CCE1_COEF_MEM_RST_SHIFT 24
+#define EASRC_CCE1_COEF_MEM_RST_MASK BIT(EASRC_CCE1_COEF_MEM_RST_SHIFT)
+#define EASRC_CCE1_COEF_MEM_RST BIT(EASRC_CCE1_COEF_MEM_RST_SHIFT)
+#define EASRC_CCE1_PF_EXP_SHIFT 16
+#define EASRC_CCE1_PF_EXP_WIDTH 8
+#define EASRC_CCE1_PF_EXP_MASK ((BIT(EASRC_CCE1_PF_EXP_WIDTH) - 1) \
+ << EASRC_CCE1_PF_EXP_SHIFT)
+#define EASRC_CCE1_PF_EXP(v) (((v) << EASRC_CCE1_PF_EXP_SHIFT) \
+ & EASRC_CCE1_PF_EXP_MASK)
+#define EASRC_CCE1_PF_ST1_WBFP_SHIFT 9
+#define EASRC_CCE1_PF_ST1_WBFP_MASK BIT(EASRC_CCE1_PF_ST1_WBFP_SHIFT)
+#define EASRC_CCE1_PF_ST1_WBFP BIT(EASRC_CCE1_PF_ST1_WBFP_SHIFT)
+#define EASRC_CCE1_PF_TSEN_SHIFT 8
+#define EASRC_CCE1_PF_TSEN_MASK BIT(EASRC_CCE1_PF_TSEN_SHIFT)
+#define EASRC_CCE1_PF_TSEN BIT(EASRC_CCE1_PF_TSEN_SHIFT)
+#define EASRC_CCE1_RS_BYPASS_SHIFT 7
+#define EASRC_CCE1_RS_BYPASS_MASK BIT(EASRC_CCE1_RS_BYPASS_SHIFT)
+#define EASRC_CCE1_RS_BYPASS BIT(EASRC_CCE1_RS_BYPASS_SHIFT)
+#define EASRC_CCE1_PF_BYPASS_SHIFT 6
+#define EASRC_CCE1_PF_BYPASS_MASK BIT(EASRC_CCE1_PF_BYPASS_SHIFT)
+#define EASRC_CCE1_PF_BYPASS BIT(EASRC_CCE1_PF_BYPASS_SHIFT)
+#define EASRC_CCE1_RS_STOP_SHIFT 5
+#define EASRC_CCE1_RS_STOP_MASK BIT(EASRC_CCE1_RS_STOP_SHIFT)
+#define EASRC_CCE1_RS_STOP BIT(EASRC_CCE1_RS_STOP_SHIFT)
+#define EASRC_CCE1_PF_STOP_SHIFT 4
+#define EASRC_CCE1_PF_STOP_MASK BIT(EASRC_CCE1_PF_STOP_SHIFT)
+#define EASRC_CCE1_PF_STOP BIT(EASRC_CCE1_PF_STOP_SHIFT)
+#define EASRC_CCE1_RS_INIT_SHIFT 2
+#define EASRC_CCE1_RS_INIT_WIDTH 2
+#define EASRC_CCE1_RS_INIT_MASK ((BIT(EASRC_CCE1_RS_INIT_WIDTH) - 1) \
+ << EASRC_CCE1_RS_INIT_SHIFT)
+#define EASRC_CCE1_RS_INIT(v) (((v) << EASRC_CCE1_RS_INIT_SHIFT) \
+ & EASRC_CCE1_RS_INIT_MASK)
+#define EASRC_CCE1_PF_INIT_SHIFT 0
+#define EASRC_CCE1_PF_INIT_WIDTH 2
+#define EASRC_CCE1_PF_INIT_MASK ((BIT(EASRC_CCE1_PF_INIT_WIDTH) - 1) \
+ << EASRC_CCE1_PF_INIT_SHIFT)
+#define EASRC_CCE1_PF_INIT(v) (((v) << EASRC_CCE1_PF_INIT_SHIFT) \
+ & EASRC_CCE1_PF_INIT_MASK)
+
+/* ASRC Context Control Extended 2 (CCE2) */
+#define EASRC_CCE2_ST2_TAPS_SHIFT 16
+#define EASRC_CCE2_ST2_TAPS_WIDTH 9
+#define EASRC_CCE2_ST2_TAPS_MASK ((BIT(EASRC_CCE2_ST2_TAPS_WIDTH) - 1) \
+ << EASRC_CCE2_ST2_TAPS_SHIFT)
+#define EASRC_CCE2_ST2_TAPS(v) (((v) << EASRC_CCE2_ST2_TAPS_SHIFT) \
+ & EASRC_CCE2_ST2_TAPS_MASK)
+#define EASRC_CCE2_ST1_TAPS_SHIFT 0
+#define EASRC_CCE2_ST1_TAPS_WIDTH 9
+#define EASRC_CCE2_ST1_TAPS_MASK ((BIT(EASRC_CCE2_ST1_TAPS_WIDTH) - 1) \
+ << EASRC_CCE2_ST1_TAPS_SHIFT)
+#define EASRC_CCE2_ST1_TAPS(v) (((v) << EASRC_CCE2_ST1_TAPS_SHIFT) \
+ & EASRC_CCE2_ST1_TAPS_MASK)
+
+/* ASRC Control Input Access (CIA) */
+#define EASRC_CIA_ITER_SHIFT 16
+#define EASRC_CIA_ITER_WIDTH 6
+#define EASRC_CIA_ITER_MASK ((BIT(EASRC_CIA_ITER_WIDTH) - 1) \
+ << EASRC_CIA_ITER_SHIFT)
+#define EASRC_CIA_ITER(v) (((v) << EASRC_CIA_ITER_SHIFT) \
+ & EASRC_CIA_ITER_MASK)
+#define EASRC_CIA_GRLEN_SHIFT 8
+#define EASRC_CIA_GRLEN_WIDTH 6
+#define EASRC_CIA_GRLEN_MASK ((BIT(EASRC_CIA_GRLEN_WIDTH) - 1) \
+ << EASRC_CIA_GRLEN_SHIFT)
+#define EASRC_CIA_GRLEN(v) (((v) << EASRC_CIA_GRLEN_SHIFT) \
+ & EASRC_CIA_GRLEN_MASK)
+#define EASRC_CIA_ACCLEN_SHIFT 0
+#define EASRC_CIA_ACCLEN_WIDTH 6
+#define EASRC_CIA_ACCLEN_MASK ((BIT(EASRC_CIA_ACCLEN_WIDTH) - 1) \
+ << EASRC_CIA_ACCLEN_SHIFT)
+#define EASRC_CIA_ACCLEN(v) (((v) << EASRC_CIA_ACCLEN_SHIFT) \
+ & EASRC_CIA_ACCLEN_MASK)
+
+/* ASRC Datapath Processor Control Slot0 Register0 (DPCS0R0) */
+#define EASRC_DPCS0R0_MAXCH_SHIFT 24
+#define EASRC_DPCS0R0_MAXCH_WIDTH 5
+#define EASRC_DPCS0R0_MAXCH_MASK ((BIT(EASRC_DPCS0R0_MAXCH_WIDTH) - 1) \
+ << EASRC_DPCS0R0_MAXCH_SHIFT)
+#define EASRC_DPCS0R0_MAXCH(v) (((v) << EASRC_DPCS0R0_MAXCH_SHIFT) \
+ & EASRC_DPCS0R0_MAXCH_MASK)
+#define EASRC_DPCS0R0_MINCH_SHIFT 16
+#define EASRC_DPCS0R0_MINCH_WIDTH 5
+#define EASRC_DPCS0R0_MINCH_MASK ((BIT(EASRC_DPCS0R0_MINCH_WIDTH) - 1) \
+ << EASRC_DPCS0R0_MINCH_SHIFT)
+#define EASRC_DPCS0R0_MINCH(v) (((v) << EASRC_DPCS0R0_MINCH_SHIFT) \
+ & EASRC_DPCS0R0_MINCH_MASK)
+#define EASRC_DPCS0R0_NUMCH_SHIFT 8
+#define EASRC_DPCS0R0_NUMCH_WIDTH 5
+#define EASRC_DPCS0R0_NUMCH_MASK ((BIT(EASRC_DPCS0R0_NUMCH_WIDTH) - 1) \
+ << EASRC_DPCS0R0_NUMCH_SHIFT)
+#define EASRC_DPCS0R0_NUMCH(v) (((v) << EASRC_DPCS0R0_NUMCH_SHIFT) \
+ & EASRC_DPCS0R0_NUMCH_MASK)
+#define EASRC_DPCS0R0_CTXNUM_SHIFT 1
+#define EASRC_DPCS0R0_CTXNUM_WIDTH 2
+#define EASRC_DPCS0R0_CTXNUM_MASK ((BIT(EASRC_DPCS0R0_CTXNUM_WIDTH) - 1) \
+ << EASRC_DPCS0R0_CTXNUM_SHIFT)
+#define EASRC_DPCS0R0_CTXNUM(v) (((v) << EASRC_DPCS0R0_CTXNUM_SHIFT) \
+ & EASRC_DPCS0R0_CTXNUM_MASK)
+#define EASRC_DPCS0R0_EN_SHIFT 0
+#define EASRC_DPCS0R0_EN_MASK BIT(EASRC_DPCS0R0_EN_SHIFT)
+#define EASRC_DPCS0R0_EN BIT(EASRC_DPCS0R0_EN_SHIFT)
+
+/* ASRC Datapath Processor Control Slot0 Register1 (DPCS0R1) */
+#define EASRC_DPCS0R1_ST1_EXP_SHIFT 0
+#define EASRC_DPCS0R1_ST1_EXP_WIDTH 13
+#define EASRC_DPCS0R1_ST1_EXP_MASK ((BIT(EASRC_DPCS0R1_ST1_EXP_WIDTH) - 1) \
+ << EASRC_DPCS0R1_ST1_EXP_SHIFT)
+#define EASRC_DPCS0R1_ST1_EXP(v) (((v) << EASRC_DPCS0R1_ST1_EXP_SHIFT) \
+ & EASRC_DPCS0R1_ST1_EXP_MASK)
+
+/* ASRC Datapath Processor Control Slot0 Register2 (DPCS0R2) */
+#define EASRC_DPCS0R2_ST1_MA_SHIFT 16
+#define EASRC_DPCS0R2_ST1_MA_WIDTH 13
+#define EASRC_DPCS0R2_ST1_MA_MASK ((BIT(EASRC_DPCS0R2_ST1_MA_WIDTH) - 1) \
+ << EASRC_DPCS0R2_ST1_MA_SHIFT)
+#define EASRC_DPCS0R2_ST1_MA(v) (((v) << EASRC_DPCS0R2_ST1_MA_SHIFT) \
+ & EASRC_DPCS0R2_ST1_MA_MASK)
+#define EASRC_DPCS0R2_ST1_SA_SHIFT 0
+#define EASRC_DPCS0R2_ST1_SA_WIDTH 13
+#define EASRC_DPCS0R2_ST1_SA_MASK ((BIT(EASRC_DPCS0R2_ST1_SA_WIDTH) - 1) \
+ << EASRC_DPCS0R2_ST1_SA_SHIFT)
+#define EASRC_DPCS0R2_ST1_SA(v) (((v) << EASRC_DPCS0R2_ST1_SA_SHIFT) \
+ & EASRC_DPCS0R2_ST1_SA_MASK)
+
+/* ASRC Datapath Processor Control Slot0 Register3 (DPCS0R3) */
+#define EASRC_DPCS0R3_ST2_MA_SHIFT 16
+#define EASRC_DPCS0R3_ST2_MA_WIDTH 13
+#define EASRC_DPCS0R3_ST2_MA_MASK ((BIT(EASRC_DPCS0R3_ST2_MA_WIDTH) - 1) \
+ << EASRC_DPCS0R3_ST2_MA_SHIFT)
+#define EASRC_DPCS0R3_ST2_MA(v) (((v) << EASRC_DPCS0R3_ST2_MA_SHIFT) \
+ & EASRC_DPCS0R3_ST2_MA_MASK)
+#define EASRC_DPCS0R3_ST2_SA_SHIFT 0
+#define EASRC_DPCS0R3_ST2_SA_WIDTH 13
+#define EASRC_DPCS0R3_ST2_SA_MASK ((BIT(EASRC_DPCS0R3_ST2_SA_WIDTH) - 1) \
+ << EASRC_DPCS0R3_ST2_SA_SHIFT)
+#define EASRC_DPCS0R3_ST2_SA(v) (((v) << EASRC_DPCS0R3_ST2_SA_SHIFT) \
+ & EASRC_DPCS0R3_ST2_SA_MASK)
+
+/* ASRC Context Output Control (COC) */
+#define EASRC_COC_FWMDE_SHIFT 28
+#define EASRC_COC_FWMDE_MASK BIT(EASRC_COC_FWMDE_SHIFT)
+#define EASRC_COC_FWMDE BIT(EASRC_COC_FWMDE_SHIFT)
+#define EASRC_COC_FIFO_WTMK_SHIFT 16
+#define EASRC_COC_FIFO_WTMK_WIDTH 7
+#define EASRC_COC_FIFO_WTMK_MASK ((BIT(EASRC_COC_FIFO_WTMK_WIDTH) - 1) \
+ << EASRC_COC_FIFO_WTMK_SHIFT)
+#define EASRC_COC_FIFO_WTMK(v) (((v) << EASRC_COC_FIFO_WTMK_SHIFT) \
+ & EASRC_COC_FIFO_WTMK_MASK)
+#define EASRC_COC_SAMPLE_POS_SHIFT 11
+#define EASRC_COC_SAMPLE_POS_WIDTH 5
+#define EASRC_COC_SAMPLE_POS_MASK ((BIT(EASRC_COC_SAMPLE_POS_WIDTH) - 1) \
+ << EASRC_COC_SAMPLE_POS_SHIFT)
+#define EASRC_COC_SAMPLE_POS(v) (((v) << EASRC_COC_SAMPLE_POS_SHIFT) \
+ & EASRC_COC_SAMPLE_POS_MASK)
+#define EASRC_COC_ENDIANNESS_SHIFT 10
+#define EASRC_COC_ENDIANNESS_MASK BIT(EASRC_COC_ENDIANNESS_SHIFT)
+#define EASRC_COC_ENDIANNESS BIT(EASRC_COC_ENDIANNESS_SHIFT)
+#define EASRC_COC_BPS_SHIFT 8
+#define EASRC_COC_BPS_WIDTH 2
+#define EASRC_COC_BPS_MASK ((BIT(EASRC_COC_BPS_WIDTH) - 1) \
+ << EASRC_COC_BPS_SHIFT)
+#define EASRC_COC_BPS(v) (((v) << EASRC_COC_BPS_SHIFT) \
+ & EASRC_COC_BPS_MASK)
+#define EASRC_COC_FMT_SHIFT 7
+#define EASRC_COC_FMT_MASK BIT(EASRC_COC_FMT_SHIFT)
+#define EASRC_COC_FMT BIT(EASRC_COC_FMT_SHIFT)
+#define EASRC_COC_OUTSIGN_SHIFT 6
+#define EASRC_COC_OUTSIGN_MASK BIT(EASRC_COC_OUTSIGN_SHIFT)
+#define EASRC_COC_OUTSIGN_OUT BIT(EASRC_COC_OUTSIGN_SHIFT)
+#define EASRC_COC_IEC_VDATA_SHIFT 2
+#define EASRC_COC_IEC_VDATA_MASK BIT(EASRC_COC_IEC_VDATA_SHIFT)
+#define EASRC_COC_IEC_VDATA BIT(EASRC_COC_IEC_VDATA_SHIFT)
+#define EASRC_COC_IEC_EN_SHIFT 1
+#define EASRC_COC_IEC_EN_MASK BIT(EASRC_COC_IEC_EN_SHIFT)
+#define EASRC_COC_IEC_EN BIT(EASRC_COC_IEC_EN_SHIFT)
+#define EASRC_COC_DITHER_EN_SHIFT 0
+#define EASRC_COC_DITHER_EN_MASK BIT(EASRC_COC_DITHER_EN_SHIFT)
+#define EASRC_COC_DITHER_EN BIT(EASRC_COC_DITHER_EN_SHIFT)
+
+/* ASRC Control Output Access (COA) */
+#define EASRC_COA_ITER_SHIFT 16
+#define EASRC_COA_ITER_WIDTH 6
+#define EASRC_COA_ITER_MASK ((BIT(EASRC_COA_ITER_WIDTH) - 1) \
+ << EASRC_COA_ITER_SHIFT)
+#define EASRC_COA_ITER(v) (((v) << EASRC_COA_ITER_SHIFT) \
+ & EASRC_COA_ITER_MASK)
+#define EASRC_COA_GRLEN_SHIFT 8
+#define EASRC_COA_GRLEN_WIDTH 6
+#define EASRC_COA_GRLEN_MASK ((BIT(EASRC_COA_GRLEN_WIDTH) - 1) \
+ << EASRC_COA_GRLEN_SHIFT)
+#define EASRC_COA_GRLEN(v) (((v) << EASRC_COA_GRLEN_SHIFT) \
+ & EASRC_COA_GRLEN_MASK)
+#define EASRC_COA_ACCLEN_SHIFT 0
+#define EASRC_COA_ACCLEN_WIDTH 6
+#define EASRC_COA_ACCLEN_MASK ((BIT(EASRC_COA_ACCLEN_WIDTH) - 1) \
+ << EASRC_COA_ACCLEN_SHIFT)
+#define EASRC_COA_ACCLEN(v) (((v) << EASRC_COA_ACCLEN_SHIFT) \
+ & EASRC_COA_ACCLEN_MASK)
+
+/* ASRC Sample FIFO Status (SFS) */
+#define EASRC_SFS_IWTMK_SHIFT 23
+#define EASRC_SFS_IWTMK_MASK BIT(EASRC_SFS_IWTMK_SHIFT)
+#define EASRC_SFS_IWTMK BIT(EASRC_SFS_IWTMK_SHIFT)
+#define EASRC_SFS_NSGI_SHIFT 16
+#define EASRC_SFS_NSGI_WIDTH 7
+#define EASRC_SFS_NSGI_MASK ((BIT(EASRC_SFS_NSGI_WIDTH) - 1) \
+ << EASRC_SFS_NSGI_SHIFT)
+#define EASRC_SFS_NSGI(v) (((v) << EASRC_SFS_NSGI_SHIFT) \
+ & EASRC_SFS_NSGI_MASK)
+#define EASRC_SFS_OWTMK_SHIFT 7
+#define EASRC_SFS_OWTMK_MASK BIT(EASRC_SFS_OWTMK_SHIFT)
+#define EASRC_SFS_OWTMK BIT(EASRC_SFS_OWTMK_SHIFT)
+#define EASRC_SFS_NSGO_SHIFT 0
+#define EASRC_SFS_NSGO_WIDTH 7
+#define EASRC_SFS_NSGO_MASK ((BIT(EASRC_SFS_NSGO_WIDTH) - 1) \
+ << EASRC_SFS_NSGO_SHIFT)
+#define EASRC_SFS_NSGO(v) (((v) << EASRC_SFS_NSGO_SHIFT) \
+ & EASRC_SFS_NSGO_MASK)
+
+/* ASRC Resampling Ratio Low (RRL) */
+#define EASRC_RRL_RS_RL_SHIFT 0
+#define EASRC_RRL_RS_RL_WIDTH 32
+#define EASRC_RRL_RS_RL(v) ((v) << EASRC_RRL_RS_RL_SHIFT)
+
+/* ASRC Resampling Ratio High (RRH) */
+#define EASRC_RRH_RS_VLD_SHIFT 31
+#define EASRC_RRH_RS_VLD_MASK BIT(EASRC_RRH_RS_VLD_SHIFT)
+#define EASRC_RRH_RS_VLD BIT(EASRC_RRH_RS_VLD_SHIFT)
+#define EASRC_RRH_RS_RH_SHIFT 0
+#define EASRC_RRH_RS_RH_WIDTH 12
+#define EASRC_RRH_RS_RH_MASK ((BIT(EASRC_RRH_RS_RH_WIDTH) - 1) \
+ << EASRC_RRH_RS_RH_SHIFT)
+#define EASRC_RRH_RS_RH(v) (((v) << EASRC_RRH_RS_RH_SHIFT) \
+ & EASRC_RRH_RS_RH_MASK)
+
+/* ASRC Resampling Ratio Update Control (RSUC) */
+#define EASRC_RSUC_RS_RM_SHIFT 0
+#define EASRC_RSUC_RS_RM_WIDTH 32
+#define EASRC_RSUC_RS_RM(v) ((v) << EASRC_RSUC_RS_RM_SHIFT)
+
+/* ASRC Resampling Ratio Update Rate (RRUR) */
+#define EASRC_RRUR_RRR_SHIFT 0
+#define EASRC_RRUR_RRR_WIDTH 31
+#define EASRC_RRUR_RRR_MASK ((BIT(EASRC_RRUR_RRR_WIDTH) - 1) \
+ << EASRC_RRUR_RRR_SHIFT)
+#define EASRC_RRUR_RRR(v) (((v) << EASRC_RRUR_RRR_SHIFT) \
+ & EASRC_RRUR_RRR_MASK)
+
+/* ASRC Resampling Center Tap Coefficient Low (RCTCL) */
+#define EASRC_RCTCL_RS_CL_SHIFT 0
+#define EASRC_RCTCL_RS_CL_WIDTH 32
+#define EASRC_RCTCL_RS_CL(v) ((v) << EASRC_RCTCL_RS_CL_SHIFT)
+
+/* ASRC Resampling Center Tap Coefficient High (RCTCH) */
+#define EASRC_RCTCH_RS_CH_SHIFT 0
+#define EASRC_RCTCH_RS_CH_WIDTH 32
+#define EASRC_RCTCH_RS_CH(v) ((v) << EASRC_RCTCH_RS_CH_SHIFT)
+
+/* ASRC Prefilter Coefficient FIFO (PCF) */
+#define EASRC_PCF_CD_SHIFT 0
+#define EASRC_PCF_CD_WIDTH 32
+#define EASRC_PCF_CD(v) ((v) << EASRC_PCF_CD_SHIFT)
+
+/* ASRC Context Resampling Coefficient Memory (CRCM) */
+#define EASRC_CRCM_RS_CWD_SHIFT 0
+#define EASRC_CRCM_RS_CWD_WIDTH 32
+#define EASRC_CRCM_RS_CWD(v) ((v) << EASRC_CRCM_RS_CWD_SHIFT)
+
+/* ASRC Context Resampling Coefficient Control (CRCC) */
+#define EASRC_CRCC_RS_CA_SHIFT 16
+#define EASRC_CRCC_RS_CA_WIDTH 11
+#define EASRC_CRCC_RS_CA_MASK ((BIT(EASRC_CRCC_RS_CA_WIDTH) - 1) \
+ << EASRC_CRCC_RS_CA_SHIFT)
+#define EASRC_CRCC_RS_CA(v) (((v) << EASRC_CRCC_RS_CA_SHIFT) \
+ & EASRC_CRCC_RS_CA_MASK)
+#define EASRC_CRCC_RS_TAPS_SHIFT 1
+#define EASRC_CRCC_RS_TAPS_WIDTH 2
+#define EASRC_CRCC_RS_TAPS_MASK ((BIT(EASRC_CRCC_RS_TAPS_WIDTH) - 1) \
+ << EASRC_CRCC_RS_TAPS_SHIFT)
+#define EASRC_CRCC_RS_TAPS(v) (((v) << EASRC_CRCC_RS_TAPS_SHIFT) \
+ & EASRC_CRCC_RS_TAPS_MASK)
+#define EASRC_CRCC_RS_CPR_SHIFT 0
+#define EASRC_CRCC_RS_CPR_MASK BIT(EASRC_CRCC_RS_CPR_SHIFT)
+#define EASRC_CRCC_RS_CPR BIT(EASRC_CRCC_RS_CPR_SHIFT)
+
+/* ASRC Interrupt_Control (IC) */
+#define EASRC_IRQC_RSDM_SHIFT 8
+#define EASRC_IRQC_RSDM_WIDTH 4
+#define EASRC_IRQC_RSDM_MASK ((BIT(EASRC_IRQC_RSDM_WIDTH) - 1) \
+ << EASRC_IRQC_RSDM_SHIFT)
+#define EASRC_IRQC_RSDM(v) (((v) << EASRC_IRQC_RSDM_SHIFT) \
+ & EASRC_IRQC_RSDM_MASK)
+#define EASRC_IRQC_OERM_SHIFT 4
+#define EASRC_IRQC_OERM_WIDTH 4
+#define EASRC_IRQC_OERM_MASK ((BIT(EASRC_IRQC_OERM_WIDTH) - 1) \
+ << EASRC_IRQC_OERM_SHIFT)
+#define EASRC_IRQC_OERM(v) (((v) << EASRC_IRQC_OERM_SHIFT) \
+ & EASRC_IEQC_OERM_MASK)
+#define EASRC_IRQC_IOM_SHIFT 0
+#define EASRC_IRQC_IOM_WIDTH 4
+#define EASRC_IRQC_IOM_MASK ((BIT(EASRC_IRQC_IOM_WIDTH) - 1) \
+ << EASRC_IRQC_IOM_SHIFT)
+#define EASRC_IRQC_IOM(v) (((v) << EASRC_IRQC_IOM_SHIFT) \
+ & EASRC_IRQC_IOM_MASK)
+
+/* ASRC Interrupt Status Flags (ISF) */
+#define EASRC_IRQF_RSD_SHIFT 8
+#define EASRC_IRQF_RSD_WIDTH 4
+#define EASRC_IRQF_RSD_MASK ((BIT(EASRC_IRQF_RSD_WIDTH) - 1) \
+ << EASRC_IRQF_RSD_SHIFT)
+#define EASRC_IRQF_RSD(v) (((v) << EASRC_IRQF_RSD_SHIFT) \
+ & EASRC_IRQF_RSD_MASK)
+#define EASRC_IRQF_OER_SHIFT 4
+#define EASRC_IRQF_OER_WIDTH 4
+#define EASRC_IRQF_OER_MASK ((BIT(EASRC_IRQF_OER_WIDTH) - 1) \
+ << EASRC_IRQF_OER_SHIFT)
+#define EASRC_IRQF_OER(v) (((v) << EASRC_IRQF_OER_SHIFT) \
+ & EASRC_IRQF_OER_MASK)
+#define EASRC_IRQF_IFO_SHIFT 0
+#define EASRC_IRQF_IFO_WIDTH 4
+#define EASRC_IRQF_IFO_MASK ((BIT(EASRC_IRQF_IFO_WIDTH) - 1) \
+ << EASRC_IRQF_IFO_SHIFT)
+#define EASRC_IRQF_IFO(v) (((v) << EASRC_IRQF_IFO_SHIFT) \
+ & EASRC_IRQF_IFO_MASK)
+
+/* ASRC Context Channel STAT */
+#define EASRC_CSx_CSx_SHIFT 0
+#define EASRC_CSx_CSx_WIDTH 32
+#define EASRC_CSx_CSx(v) ((v) << EASRC_CSx_CSx_SHIFT)
+
+/* ASRC Debug Control Register */
+#define EASRC_DBGC_DMS_SHIFT 0
+#define EASRC_DBGC_DMS_WIDTH 6
+#define EASRC_DBGC_DMS_MASK ((BIT(EASRC_DBGC_DMS_WIDTH) - 1) \
+ << EASRC_DBGC_DMS_SHIFT)
+#define EASRC_DBGC_DMS(v) (((v) << EASRC_DBGC_DMS_SHIFT) \
+ & EASRC_DBGC_DMS_MASK)
+
+/* ASRC Debug Status Register */
+#define EASRC_DBGS_DS_SHIFT 0
+#define EASRC_DBGS_DS_WIDTH 32
+#define EASRC_DBGS_DS(v) ((v) << EASRC_DBGS_DS_SHIFT)
+
+/* General Constants */
+#define EASRC_CTX_MAX_NUM 4
+#define EASRC_RS_COEFF_MEM 0
+#define EASRC_PF_COEFF_MEM 1
+
+/* Prefilter constants */
+#define EASRC_PF_ST1_ONLY 0
+#define EASRC_PF_TWO_STAGE_MODE 1
+#define EASRC_PF_ST1_COEFF_WR 0
+#define EASRC_PF_ST2_COEFF_WR 1
+#define EASRC_MAX_PF_TAPS 384
+
+/* Resampling constants */
+#define EASRC_RS_32_TAPS 0
+#define EASRC_RS_64_TAPS 1
+#define EASRC_RS_128_TAPS 2
+
+/* Initialization mode */
+#define EASRC_INIT_MODE_SW_CONTROL 0
+#define EASRC_INIT_MODE_REPLICATE 1
+#define EASRC_INIT_MODE_ZERO_FILL 2
+
+/* FIFO watermarks */
+#define FSL_EASRC_INPUTFIFO_WML 0x4
+#define FSL_EASRC_OUTPUTFIFO_WML 0x1
+
+#define EASRC_INPUTFIFO_THRESHOLD_MIN 0
+#define EASRC_INPUTFIFO_THRESHOLD_MAX 127
+#define EASRC_OUTPUTFIFO_THRESHOLD_MIN 0
+#define EASRC_OUTPUTFIFO_THRESHOLD_MAX 63
+
+#define EASRC_DMA_BUFFER_SIZE (1024 * 48 * 9)
+#define EASRC_MAX_BUFFER_SIZE (1024 * 48)
+
+#define FIRMWARE_MAGIC 0xDEAD
+#define FIRMWARE_VERSION 1
+
+#define PREFILTER_MEM_LEN 0x1800
+
+enum easrc_word_width {
+ EASRC_WIDTH_16_BIT = 0,
+ EASRC_WIDTH_20_BIT = 1,
+ EASRC_WIDTH_24_BIT = 2,
+ EASRC_WIDTH_32_BIT = 3,
+};
+
+struct __attribute__((__packed__)) asrc_firmware_hdr {
+ u32 magic;
+ u32 interp_scen;
+ u32 prefil_scen;
+ u32 firmware_version;
+};
+
+struct __attribute__((__packed__)) interp_params {
+ u32 magic;
+ u32 num_taps;
+ u32 num_phases;
+ u64 center_tap;
+ u64 coeff[8192];
+};
+
+struct __attribute__((__packed__)) prefil_params {
+ u32 magic;
+ u32 insr;
+ u32 outsr;
+ u32 st1_taps;
+ u32 st2_taps;
+ u32 st1_exp;
+ u64 coeff[256];
+};
+
+struct dma_block {
+ void *dma_vaddr;
+ unsigned int length;
+ unsigned int max_buf_size;
+};
+
+struct fsl_easrc_data_fmt {
+ unsigned int width : 2;
+ unsigned int endianness : 1;
+ unsigned int unsign : 1;
+ unsigned int floating_point : 1;
+ unsigned int iec958: 1;
+ unsigned int sample_pos: 5;
+ unsigned int addexp;
+};
+
+struct fsl_easrc_io_params {
+ struct fsl_easrc_data_fmt fmt;
+ unsigned int group_len;
+ unsigned int iterations;
+ unsigned int access_len;
+ unsigned int fifo_wtmk;
+ unsigned int sample_rate;
+ unsigned int sample_format;
+ unsigned int norm_rate;
+};
+
+struct fsl_easrc_slot {
+ bool busy;
+ int ctx_index;
+ int slot_index;
+ int num_channel; /* maximum is 8 */
+ int min_channel;
+ int max_channel;
+ int pf_mem_used;
+};
+
+/**
+ * fsl_easrc_ctx_priv: EASRC context private data
+ *
+ * @in_params: input parameter
+ * @out_params: output parameter
+ * @st1_num_taps: tap number of stage 1
+ * @st2_num_taps: tap number of stage 2
+ * @st1_num_exp: exponent number of stage 1
+ * @pf_init_mode: prefilter init mode
+ * @rs_init_mode: resample filter init mode
+ * @ctx_streams: stream flag of ctx
+ * @rs_ratio: resampler ratio
+ * @st1_coeff: pointer of stage 1 coeff
+ * @st2_coeff: pointer of stage 2 coeff
+ * @in_filled_sample: input filled sample
+ * @out_missed_sample: sample missed in output
+ * @st1_addexp: exponent added for stage1
+ * @st2_addexp: exponent added for stage2
+ */
+struct fsl_easrc_ctx_priv {
+ struct fsl_easrc_io_params in_params;
+ struct fsl_easrc_io_params out_params;
+ unsigned int st1_num_taps;
+ unsigned int st2_num_taps;
+ unsigned int st1_num_exp;
+ unsigned int pf_init_mode;
+ unsigned int rs_init_mode;
+ unsigned int ctx_streams;
+ u64 rs_ratio;
+ u64 *st1_coeff;
+ u64 *st2_coeff;
+ int in_filled_sample;
+ int out_missed_sample;
+ int st1_addexp;
+ int st2_addexp;
+};
+
+/**
+ * fsl_easrc_priv: EASRC private data
+ *
+ * @slot: slot setting
+ * @firmware_hdr: the header of firmware
+ * @interp: pointer to interpolation filter coeff
+ * @prefil: pointer to prefilter coeff
+ * @fw: firmware of coeff table
+ * @fw_name: firmware name
+ * @rs_num_taps: resample filter taps, 32, 64, or 128
+ * @bps_iec958: bits per sample of iec958
+ * @rs_coeff: resampler coefficient
+ * @const_coeff: one tap prefilter coefficient
+ * @firmware_loaded: firmware is loaded
+ */
+struct fsl_easrc_priv {
+ struct fsl_easrc_slot slot[EASRC_CTX_MAX_NUM][2];
+ struct asrc_firmware_hdr *firmware_hdr;
+ struct interp_params *interp;
+ struct prefil_params *prefil;
+ const struct firmware *fw;
+ const char *fw_name;
+ unsigned int rs_num_taps;
+ unsigned int bps_iec958[EASRC_CTX_MAX_NUM];
+ u64 *rs_coeff;
+ u64 const_coeff;
+ int firmware_loaded;
+};
+#endif /* _FSL_EASRC_H */
diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c
index f7f2d29f1bfe..e73bd6570a08 100644
--- a/sound/soc/fsl/fsl_micfil.c
+++ b/sound/soc/fsl/fsl_micfil.c
@@ -702,10 +702,8 @@ static int fsl_micfil_probe(struct platform_device *pdev)
for (i = 0; i < MICFIL_IRQ_LINES; i++) {
micfil->irq[i] = platform_get_irq(pdev, i);
dev_err(&pdev->dev, "GET IRQ: %d\n", micfil->irq[i]);
- if (micfil->irq[i] < 0) {
- dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+ if (micfil->irq[i] < 0)
return micfil->irq[i];
- }
}
if (of_property_read_bool(np, "fsl,shared-interrupt"))
diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c
index ab3b76d298b3..fd5dcd6b9f85 100644
--- a/sound/soc/hisilicon/hi6210-i2s.c
+++ b/sound/soc/hisilicon/hi6210-i2s.c
@@ -547,7 +547,7 @@ static int hi6210_i2s_probe(struct platform_device *pdev)
struct resource *res;
int ret;
- i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
+ i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
if (!i2s)
return -ENOMEM;
@@ -562,28 +562,28 @@ static int hi6210_i2s_probe(struct platform_device *pdev)
i2s->base_phys = (phys_addr_t)res->start;
i2s->dai = hi6210_i2s_dai_init;
- dev_set_drvdata(&pdev->dev, i2s);
+ dev_set_drvdata(dev, i2s);
i2s->sysctrl = syscon_regmap_lookup_by_phandle(node,
"hisilicon,sysctrl-syscon");
if (IS_ERR(i2s->sysctrl))
return PTR_ERR(i2s->sysctrl);
- i2s->clk[CLK_DACODEC] = devm_clk_get(&pdev->dev, "dacodec");
- if (IS_ERR_OR_NULL(i2s->clk[CLK_DACODEC]))
+ i2s->clk[CLK_DACODEC] = devm_clk_get(dev, "dacodec");
+ if (IS_ERR(i2s->clk[CLK_DACODEC]))
return PTR_ERR(i2s->clk[CLK_DACODEC]);
i2s->clocks++;
- i2s->clk[CLK_I2S_BASE] = devm_clk_get(&pdev->dev, "i2s-base");
- if (IS_ERR_OR_NULL(i2s->clk[CLK_I2S_BASE]))
+ i2s->clk[CLK_I2S_BASE] = devm_clk_get(dev, "i2s-base");
+ if (IS_ERR(i2s->clk[CLK_I2S_BASE]))
return PTR_ERR(i2s->clk[CLK_I2S_BASE]);
i2s->clocks++;
- ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+ ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
if (ret)
return ret;
- ret = devm_snd_soc_register_component(&pdev->dev, &hi6210_i2s_i2s_comp,
+ ret = devm_snd_soc_register_component(dev, &hi6210_i2s_i2s_comp,
&i2s->dai, 1);
return ret;
}
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index c8de0bb5bed9..36f547939f0a 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -209,12 +209,8 @@ config SND_SOC_INTEL_SKYLAKE_SSP_CLK
config SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC
bool "HDAudio codec support"
help
- This option broke audio on Linus' Skylake laptop in December 2018
- and the race conditions during the probe were not fixed since.
- This option is DEPRECATED, all HDaudio codec support needs
- to be handled by the SOF driver.
- Distributions should not enable this option and there are no known
- users of this capability.
+ If you have Intel Skylake or Kabylake with HDaudio codec
+ and DMIC present then enable this option by saying Y.
config SND_SOC_INTEL_SKYLAKE_COMMON
tristate
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index 8160520fd74c..e16d6dc4d4e6 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
# Core support
obj-$(CONFIG_SND_SOC) += common/
diff --git a/sound/soc/intel/atom/Makefile b/sound/soc/intel/atom/Makefile
index 1dc60471b399..a9326d5ec44c 100644
--- a/sound/soc/intel/atom/Makefile
+++ b/sound/soc/intel/atom/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
snd-soc-sst-atom-hifi2-platform-objs := sst-mfld-platform-pcm.o \
sst-mfld-platform-compress.o \
sst-atom-controls.o
diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h
index 5356e954a732..620b48d2a064 100644
--- a/sound/soc/intel/atom/sst-atom-controls.h
+++ b/sound/soc/intel/atom/sst-atom-controls.h
@@ -410,7 +410,7 @@ struct sst_cmd_set_gain_dual {
struct sst_cmd_set_params {
struct sst_destination_id dst;
u16 command_id;
- char params[0];
+ char params[];
} __packed;
diff --git a/sound/soc/intel/atom/sst-mfld-platform-compress.c b/sound/soc/intel/atom/sst-mfld-platform-compress.c
index 4a7a9426a3b9..1595e01a7e12 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-compress.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-compress.c
@@ -39,7 +39,8 @@ static void sst_drain_notify(void *arg)
snd_compr_drain_notify(cstream);
}
-static int sst_platform_compr_open(struct snd_compr_stream *cstream)
+static int sst_platform_compr_open(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream)
{
int ret_val = 0;
@@ -72,7 +73,8 @@ out_ops:
return ret_val;
}
-static int sst_platform_compr_free(struct snd_compr_stream *cstream)
+static int sst_platform_compr_free(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream)
{
struct sst_runtime_stream *stream;
int ret_val = 0, str_id;
@@ -91,15 +93,14 @@ static int sst_platform_compr_free(struct snd_compr_stream *cstream)
return 0;
}
-static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
- struct snd_compr_params *params)
+static int sst_platform_compr_set_params(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_params *params)
{
struct sst_runtime_stream *stream;
int retval;
struct snd_sst_params str_params;
struct sst_compress_cb cb;
- struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct sst_data *ctx = snd_soc_component_get_drvdata(component);
stream = cstream->runtime->private_data;
@@ -166,7 +167,8 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
return 0;
}
-static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
+static int sst_platform_compr_trigger(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream, int cmd)
{
struct sst_runtime_stream *stream = cstream->runtime->private_data;
@@ -199,8 +201,9 @@ static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
return -EINVAL;
}
-static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
- struct snd_compr_tstamp *tstamp)
+static int sst_platform_compr_pointer(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_tstamp *tstamp)
{
struct sst_runtime_stream *stream;
@@ -212,8 +215,9 @@ static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
return 0;
}
-static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
- size_t bytes)
+static int sst_platform_compr_ack(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
+ size_t bytes)
{
struct sst_runtime_stream *stream;
@@ -224,8 +228,9 @@ static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
return 0;
}
-static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
- struct snd_compr_caps *caps)
+static int sst_platform_compr_get_caps(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_caps *caps)
{
struct sst_runtime_stream *stream =
cstream->runtime->private_data;
@@ -233,8 +238,9 @@ static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
return stream->compr_ops->get_caps(caps);
}
-static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
- struct snd_compr_codec_caps *codec)
+static int sst_platform_compr_get_codec_caps(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_codec_caps *codec)
{
struct sst_runtime_stream *stream =
cstream->runtime->private_data;
@@ -242,8 +248,9 @@ static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
return stream->compr_ops->get_codec_caps(codec);
}
-static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
- struct snd_compr_metadata *metadata)
+static int sst_platform_compr_set_metadata(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_metadata *metadata)
{
struct sst_runtime_stream *stream =
cstream->runtime->private_data;
@@ -251,7 +258,7 @@ static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata);
}
-const struct snd_compr_ops sst_platform_compr_ops = {
+const struct snd_compress_ops sst_platform_compress_ops = {
.open = sst_platform_compr_open,
.free = sst_platform_compr_free,
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index 82f2b6357778..2e9222ed9daa 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -684,7 +684,7 @@ static const struct snd_soc_component_driver sst_soc_platform_drv = {
.open = sst_soc_open,
.trigger = sst_soc_trigger,
.pointer = sst_soc_pointer,
- .compr_ops = &sst_platform_compr_ops,
+ .compress_ops = &sst_platform_compress_ops,
.pcm_construct = sst_soc_pcm_new,
};
diff --git a/sound/soc/intel/atom/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h
index fe4749cfa4f5..10c9ecfa7038 100644
--- a/sound/soc/intel/atom/sst-mfld-platform.h
+++ b/sound/soc/intel/atom/sst-mfld-platform.h
@@ -17,7 +17,7 @@
#include "sst-atom-controls.h"
extern struct sst_device *sst;
-extern const struct snd_compr_ops sst_platform_compr_ops;
+extern const struct snd_compress_ops sst_platform_compress_ops;
#define DRV_NAME "sst"
diff --git a/sound/soc/intel/atom/sst/Makefile b/sound/soc/intel/atom/sst/Makefile
index 795d1cf8f386..f17c905df3e2 100644
--- a/sound/soc/intel/atom/sst/Makefile
+++ b/sound/soc/intel/atom/sst/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
snd-intel-sst-core-objs := sst.o sst_ipc.o sst_stream.o sst_drv_interface.o sst_loader.o sst_pvt.o
snd-intel-sst-pci-objs += sst_pci.o
snd-intel-sst-acpi-objs += sst_acpi.o
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index 556c3104e641..91ce347b3a45 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -243,7 +243,7 @@ if SND_SOC_INTEL_SKL
config SND_SOC_INTEL_SKL_RT286_MACH
tristate "SKL with RT286 I2S mode"
- depends on I2C && ACPI
+ depends on I2C && ACPI && GPIOLIB
depends on MFD_INTEL_LPSS || COMPILE_TEST
select SND_SOC_RT286
select SND_SOC_DMIC
@@ -256,7 +256,7 @@ config SND_SOC_INTEL_SKL_RT286_MACH
config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
tristate "SKL with NAU88L25 and SSM4567 in I2S Mode"
- depends on I2C && ACPI
+ depends on I2C && ACPI && GPIOLIB
depends on MFD_INTEL_LPSS || COMPILE_TEST
select SND_SOC_NAU8825
select SND_SOC_SSM4567
@@ -270,7 +270,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
tristate "SKL with NAU88L25 and MAX98357A in I2S Mode"
- depends on I2C && ACPI
+ depends on I2C && ACPI && GPIOLIB
depends on MFD_INTEL_LPSS || COMPILE_TEST
select SND_SOC_NAU8825
select SND_SOC_MAX98357A
@@ -299,7 +299,7 @@ if SND_SOC_INTEL_APL
config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
tristate "Broxton with DA7219 and MAX98357A in I2S Mode"
- depends on I2C && ACPI
+ depends on I2C && ACPI && GPIOLIB
depends on MFD_INTEL_LPSS || COMPILE_TEST
depends on SND_HDA_CODEC_HDMI
select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON
@@ -311,7 +311,7 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
config SND_SOC_INTEL_BXT_RT298_MACH
tristate "Broxton with RT298 I2S mode"
- depends on I2C && ACPI
+ depends on I2C && ACPI && GPIOLIB
depends on MFD_INTEL_LPSS || COMPILE_TEST
select SND_SOC_RT298
select SND_SOC_DMIC
@@ -324,11 +324,26 @@ config SND_SOC_INTEL_BXT_RT298_MACH
endif ## SND_SOC_INTEL_APL
+if SND_SOC_SOF_APOLLOLAKE
+
+config SND_SOC_INTEL_SOF_WM8804_MACH
+ tristate "SOF with Wolfson/Cirrus WM8804 codec"
+ depends on I2C && ACPI
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_WM8804_I2C
+ help
+ This adds support for ASoC machine driver for Intel platforms
+ with the Wolfson/Cirrus WM8804 I2S audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+endif ## SND_SOC_SOF_APOLLOLAKE
+
if SND_SOC_INTEL_KBL
config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
tristate "KBL with RT5663 and MAX98927 in I2S Mode"
- depends on I2C && ACPI
+ depends on I2C && ACPI && GPIOLIB
depends on MFD_INTEL_LPSS || COMPILE_TEST
select SND_SOC_RT5663
select SND_SOC_MAX98927
@@ -370,7 +385,7 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH
config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH
tristate "KBL with DA7219 and MAX98927 in I2S Mode"
- depends on I2C && ACPI
+ depends on I2C && ACPI && GPIOLIB
depends on MFD_INTEL_LPSS || COMPILE_TEST
select SND_SOC_DA7219
select SND_SOC_MAX98927
@@ -400,7 +415,7 @@ if SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK
config SND_SOC_INTEL_GLK_DA7219_MAX98357A_MACH
tristate "GLK with DA7219 and MAX98357A in I2S Mode"
- depends on I2C && ACPI
+ depends on I2C && ACPI && GPIOLIB
depends on MFD_INTEL_LPSS || COMPILE_TEST
depends on SND_HDA_CODEC_HDMI
select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON
@@ -412,7 +427,7 @@ config SND_SOC_INTEL_GLK_DA7219_MAX98357A_MACH
config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
tristate "GLK with RT5682 and MAX98357A in I2S Mode"
- depends on I2C && ACPI
+ depends on I2C && ACPI && GPIOLIB
depends on MFD_INTEL_LPSS || COMPILE_TEST
depends on SND_HDA_CODEC_HDMI
select SND_SOC_RT5682
@@ -432,6 +447,7 @@ if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC
config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH
tristate "SKL/KBL/BXT/APL with HDA Codecs"
depends on SND_HDA_CODEC_HDMI
+ depends on GPIOLIB
select SND_SOC_HDAC_HDMI
select SND_SOC_DMIC
# SND_SOC_HDAC_HDA is already selected
@@ -446,7 +462,7 @@ endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC
if SND_SOC_SOF_HDA_LINK || SND_SOC_SOF_BAYTRAIL
config SND_SOC_INTEL_SOF_RT5682_MACH
tristate "SOF with rt5682 codec in I2S Mode"
- depends on I2C && ACPI
+ depends on I2C && ACPI && GPIOLIB
depends on (SND_SOC_SOF_HDA_LINK && (MFD_INTEL_LPSS || COMPILE_TEST)) ||\
(SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST))
depends on SND_HDA_CODEC_HDMI
@@ -480,7 +496,7 @@ if (SND_SOC_SOF_COMETLAKE_LP && SND_SOC_SOF_HDA_LINK)
config SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH
tristate "CML_LP with DA7219 and MAX98357A in I2S Mode"
- depends on I2C && ACPI
+ depends on I2C && ACPI && GPIOLIB
depends on MFD_INTEL_LPSS || COMPILE_TEST
select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON
help
@@ -491,7 +507,7 @@ config SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH
config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH
tristate "CML with RT1011 and RT5682 in I2S Mode"
- depends on I2C && ACPI
+ depends on I2C && ACPI && GPIOLIB
depends on MFD_INTEL_LPSS || COMPILE_TEST
depends on SND_HDA_CODEC_HDMI
select SND_SOC_RT1011
@@ -510,7 +526,7 @@ if SND_SOC_SOF_JASPERLAKE
config SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH
tristate "SOF with DA7219 and MAX98373/MAX98360A in I2S Mode"
- depends on I2C && ACPI
+ depends on I2C && ACPI && GPIOLIB
depends on MFD_INTEL_LPSS || COMPILE_TEST
depends on SND_HDA_CODEC_HDMI
select SND_SOC_DA7219
@@ -524,11 +540,26 @@ config SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH
endif ## SND_SOC_SOF_JASPERLAKE
+if SND_SOC_SOF_ELKHARTLAKE
+
+config SND_SOC_INTEL_EHL_RT5660_MACH
+ tristate "EHL with RT5660 in I2S mode"
+ depends on I2C && ACPI && GPIOLIB
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ depends on SND_HDA_CODEC_HDMI
+ select SND_SOC_RT5660
+ select SND_SOC_DMIC
+ help
+ This adds support for ASoC machine driver for Elkhart Lake
+ platform with RT5660 I2S audio codec.
+
+endif ## SND_SOC_SOF_ELKHARTLAKE
+
if SND_SOC_SOF_INTEL_SOUNDWIRE
config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
tristate "SoundWire generic machine driver"
- depends on I2C && ACPI
+ depends on I2C && ACPI && GPIOLIB
depends on MFD_INTEL_LPSS || COMPILE_TEST
depends on SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES || COMPILE_TEST
depends on SOUNDWIRE
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 1ef6e60bc2a0..15684610f8c6 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
snd-soc-sst-haswell-objs := haswell.o
snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
@@ -8,6 +8,7 @@ snd-soc-sst-broadwell-objs := broadwell.o
snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o hda_dsp_common.o
snd-soc-sst-bxt-rt298-objs := bxt_rt298.o hda_dsp_common.o
snd-soc-sst-sof-pcm512x-objs := sof_pcm512x.o hda_dsp_common.o
+snd-soc-sst-sof-wm8804-objs := sof_wm8804.o
snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o hda_dsp_common.o
snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o
@@ -31,6 +32,7 @@ snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o hda_dsp_c
snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o
snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o hda_dsp_common.o
+snd-soc-ehl-rt5660-objs := ehl_rt5660.o hda_dsp_common.o
snd-soc-sof-sdw-objs += sof_sdw.o \
sof_sdw_rt711.o sof_sdw_rt700.o \
sof_sdw_rt1308.o sof_sdw_rt715.o \
@@ -43,6 +45,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON) += snd-soc-sst-bxt-da7219_max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_PCM512x_MACH) += snd-soc-sst-sof-pcm512x.o
+obj-$(CONFIG_SND_SOC_INTEL_SOF_WM8804_MACH) += snd-soc-sst-sof-wm8804.o
obj-$(CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH) += snd-soc-sst-glk-rt5682_max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5650_MACH) += snd-soc-sst-bdw-rt5650-mach.o
@@ -68,4 +71,5 @@ obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max9
obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH) += snd-soc-sof_da7219_max98373.o
+obj-$(CONFIG_SND_SOC_INTEL_EHL_RT5660_MACH) += snd-soc-ehl-rt5660.o
obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_SOF_MACH) += snd-soc-sof-sdw.o
diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c
index af2f50293208..a97e912adf4b 100644
--- a/sound/soc/intel/boards/bdw-rt5650.c
+++ b/sound/soc/intel/boards/bdw-rt5650.c
@@ -162,6 +162,34 @@ static int bdw_rt5650_rtd_init(struct snd_soc_pcm_runtime *rtd)
}
#endif
+static const unsigned int channels[] = {
+ 2, 4,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+};
+
+static int bdw_rt5650_fe_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ /* Board supports stereo and quad configurations for capture */
+ if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+ return 0;
+
+ runtime->hw.channels_max = 4;
+ return snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+}
+
+static const struct snd_soc_ops bdw_rt5650_fe_ops = {
+ .startup = bdw_rt5650_fe_startup,
+};
+
static int bdw_rt5650_init(struct snd_soc_pcm_runtime *rtd)
{
struct bdw_rt5650_priv *bdw_rt5650 =
@@ -234,6 +262,7 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = {
.name = "System PCM",
.stream_name = "System Playback",
.dynamic = 1,
+ .ops = &bdw_rt5650_fe_ops,
#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
.init = bdw_rt5650_rtd_init,
#endif
diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c
index cc41a348295e..5f96d7ac0a22 100644
--- a/sound/soc/intel/boards/bdw-rt5677.c
+++ b/sound/soc/intel/boards/bdw-rt5677.c
@@ -222,6 +222,31 @@ static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd)
}
#endif
+static const unsigned int channels[] = {
+ 2,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+};
+
+static int bdw_rt5677_fe_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ /* Board supports stereo configuration only */
+ runtime->hw.channels_max = 2;
+ return snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+}
+
+static const struct snd_soc_ops bdw_rt5677_fe_ops = {
+ .startup = bdw_rt5677_fe_startup,
+};
+
static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd)
{
struct bdw_rt5677_priv *bdw_rt5677 =
@@ -321,6 +346,7 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = {
},
.dpcm_capture = 1,
.dpcm_playback = 1,
+ .ops = &bdw_rt5677_fe_ops,
SND_SOC_DAILINK_REG(fe, dummy, platform),
},
diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c
index 86deea6f136a..42f8723beef2 100644
--- a/sound/soc/intel/boards/broadwell.c
+++ b/sound/soc/intel/boards/broadwell.c
@@ -143,6 +143,31 @@ static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
}
#endif
+static const unsigned int channels[] = {
+ 2,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+};
+
+static int broadwell_fe_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ /* Board supports stereo configuration only */
+ runtime->hw.channels_max = 2;
+ return snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+}
+
+static const struct snd_soc_ops broadwell_fe_ops = {
+ .startup = broadwell_fe_startup,
+};
+
SND_SOC_DAILINK_DEF(system,
DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
@@ -180,6 +205,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
.init = broadwell_rtd_init,
#endif
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .ops = &broadwell_fe_ops,
.dpcm_playback = 1,
.dpcm_capture = 1,
SND_SOC_DAILINK_REG(system, dummy, platform),
diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c
index 3b3df7c9008c..c7f81a93d7c8 100644
--- a/sound/soc/intel/boards/bytcht_cx2072x.c
+++ b/sound/soc/intel/boards/bytcht_cx2072x.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
//
// ASoC DPCM Machine driver for Baytrail / Cherrytrail platforms with
// CX2072X codec
diff --git a/sound/soc/intel/boards/cml_rt1011_rt5682.c b/sound/soc/intel/boards/cml_rt1011_rt5682.c
index 8167b2977e1d..68eff29daf8f 100644
--- a/sound/soc/intel/boards/cml_rt1011_rt5682.c
+++ b/sound/soc/intel/boards/cml_rt1011_rt5682.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright(c) 2019 Intel Corporation.
/*
@@ -30,6 +30,36 @@
#define CML_RT5682_CODEC_DAI "rt5682-aif1"
#define NAME_SIZE 32
+#define SOF_RT1011_SPEAKER_WL BIT(0)
+#define SOF_RT1011_SPEAKER_WR BIT(1)
+#define SOF_RT1011_SPEAKER_TL BIT(2)
+#define SOF_RT1011_SPEAKER_TR BIT(3)
+#define SPK_CH 4
+
+/* Default: Woofer speakers */
+static unsigned long sof_rt1011_quirk = SOF_RT1011_SPEAKER_WL |
+ SOF_RT1011_SPEAKER_WR;
+
+static int sof_rt1011_quirk_cb(const struct dmi_system_id *id)
+{
+ sof_rt1011_quirk = (unsigned long)id->driver_data;
+ return 1;
+}
+
+static const struct dmi_system_id sof_rt1011_quirk_table[] = {
+ {
+ .callback = sof_rt1011_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Helios"),
+ },
+ .driver_data = (void *)(SOF_RT1011_SPEAKER_WL | SOF_RT1011_SPEAKER_WR |
+ SOF_RT1011_SPEAKER_TL | SOF_RT1011_SPEAKER_TR),
+ },
+ {
+ }
+};
+
static struct snd_soc_jack hdmi_jack[3];
struct hdmi_pcm {
@@ -48,15 +78,16 @@ struct card_private {
static const struct snd_kcontrol_new cml_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("TL Ext Spk"),
- SOC_DAPM_PIN_SWITCH("TR Ext Spk"),
SOC_DAPM_PIN_SWITCH("WL Ext Spk"),
SOC_DAPM_PIN_SWITCH("WR Ext Spk"),
};
+static const struct snd_kcontrol_new cml_rt1011_tt_controls[] = {
+ SOC_DAPM_PIN_SWITCH("TL Ext Spk"),
+ SOC_DAPM_PIN_SWITCH("TR Ext Spk"),
+};
+
static const struct snd_soc_dapm_widget cml_rt1011_rt5682_widgets[] = {
- SND_SOC_DAPM_SPK("TL Ext Spk", NULL),
- SND_SOC_DAPM_SPK("TR Ext Spk", NULL),
SND_SOC_DAPM_SPK("WL Ext Spk", NULL),
SND_SOC_DAPM_SPK("WR Ext Spk", NULL),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
@@ -64,10 +95,13 @@ static const struct snd_soc_dapm_widget cml_rt1011_rt5682_widgets[] = {
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
};
+static const struct snd_soc_dapm_widget cml_rt1011_tt_widgets[] = {
+ SND_SOC_DAPM_SPK("TL Ext Spk", NULL),
+ SND_SOC_DAPM_SPK("TR Ext Spk", NULL),
+};
+
static const struct snd_soc_dapm_route cml_rt1011_rt5682_map[] = {
- /*speaker*/
- {"TL Ext Spk", NULL, "TL SPO"},
- {"TR Ext Spk", NULL, "TR SPO"},
+ /*WL/WR speaker*/
{"WL Ext Spk", NULL, "WL SPO"},
{"WR Ext Spk", NULL, "WR SPO"},
@@ -82,6 +116,12 @@ static const struct snd_soc_dapm_route cml_rt1011_rt5682_map[] = {
{"DMic", NULL, "SoC DMIC"},
};
+static const struct snd_soc_dapm_route cml_rt1011_tt_map[] = {
+ /*TL/TR speaker*/
+ {"TL Ext Spk", NULL, "TL SPO" },
+ {"TR Ext Spk", NULL, "TR SPO" },
+};
+
static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
@@ -121,6 +161,35 @@ static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
};
+static int cml_rt1011_spk_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = 0;
+ struct snd_soc_card *card = rtd->card;
+
+ if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL |
+ SOF_RT1011_SPEAKER_TR)) {
+
+ ret = snd_soc_add_card_controls(card, cml_rt1011_tt_controls,
+ ARRAY_SIZE(cml_rt1011_tt_controls));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_new_controls(&card->dapm,
+ cml_rt1011_tt_widgets,
+ ARRAY_SIZE(cml_rt1011_tt_widgets));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(&card->dapm, cml_rt1011_tt_map,
+ ARRAY_SIZE(cml_rt1011_tt_map));
+
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
static int cml_rt5682_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -191,30 +260,38 @@ static int cml_rt1011_hw_params(struct snd_pcm_substream *substream,
* The feedback is captured for each codec individually.
* Hence all 4 codecs use 1 Tx slot each for feedback.
*/
- if (!strcmp(codec_dai->component->name, "i2c-10EC1011:00")) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai,
- 0x4, 0x1, 4, 24);
- if (ret < 0)
- break;
- }
- if (!strcmp(codec_dai->component->name, "i2c-10EC1011:02")) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai,
- 0x1, 0x1, 4, 24);
- if (ret < 0)
- break;
+ if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_WL |
+ SOF_RT1011_SPEAKER_WR)) {
+ if (!strcmp(codec_dai->component->name, "i2c-10EC1011:00")) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai,
+ 0x4, 0x1, 4, 24);
+ if (ret < 0)
+ break;
+ }
+
+ if (!strcmp(codec_dai->component->name, "i2c-10EC1011:01")) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai,
+ 0x8, 0x2, 4, 24);
+ if (ret < 0)
+ break;
+ }
}
- /* TDM Rx slot 2 is used for Right Woofer & Tweeters pair */
- if (!strcmp(codec_dai->component->name, "i2c-10EC1011:01")) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai,
- 0x8, 0x2, 4, 24);
- if (ret < 0)
- break;
- }
- if (!strcmp(codec_dai->component->name, "i2c-10EC1011:03")) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai,
- 0x2, 0x2, 4, 24);
- if (ret < 0)
- break;
+
+ if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL |
+ SOF_RT1011_SPEAKER_TR)) {
+ if (!strcmp(codec_dai->component->name, "i2c-10EC1011:02")) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai,
+ 0x1, 0x1, 4, 24);
+ if (ret < 0)
+ break;
+ }
+
+ if (!strcmp(codec_dai->component->name, "i2c-10EC1011:03")) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai,
+ 0x2, 0x2, 4, 24);
+ if (ret < 0)
+ break;
+ }
}
}
if (ret < 0)
@@ -302,9 +379,7 @@ SND_SOC_DAILINK_DEF(ssp1_pin,
SND_SOC_DAILINK_DEF(ssp1_codec,
DAILINK_COMP_ARRAY(
/* WL */ COMP_CODEC("i2c-10EC1011:00", CML_RT1011_CODEC_DAI),
- /* WR */ COMP_CODEC("i2c-10EC1011:01", CML_RT1011_CODEC_DAI),
- /* TL */ COMP_CODEC("i2c-10EC1011:02", CML_RT1011_CODEC_DAI),
- /* TR */ COMP_CODEC("i2c-10EC1011:03", CML_RT1011_CODEC_DAI)));
+ /* WR */ COMP_CODEC("i2c-10EC1011:01", CML_RT1011_CODEC_DAI)));
SND_SOC_DAILINK_DEF(dmic_pin,
DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
@@ -398,6 +473,7 @@ static struct snd_soc_dai_link cml_rt1011_rt5682_dailink[] = {
.dpcm_playback = 1,
.dpcm_capture = 1, /* Capture stream provides Feedback */
.no_pcm = 1,
+ .init = cml_rt1011_spk_init,
.ops = &cml_rt1011_ops,
SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform),
},
@@ -412,14 +488,6 @@ static struct snd_soc_codec_conf rt1011_conf[] = {
.dlc = COMP_CODEC_CONF("i2c-10EC1011:01"),
.name_prefix = "WR",
},
- {
- .dlc = COMP_CODEC_CONF("i2c-10EC1011:02"),
- .name_prefix = "TL",
- },
- {
- .dlc = COMP_CODEC_CONF("i2c-10EC1011:03"),
- .name_prefix = "TR",
- },
};
/* Cometlake audio machine driver for RT1011 and RT5682 */
@@ -441,10 +509,12 @@ static struct snd_soc_card snd_soc_card_cml = {
static int snd_cml_rt1011_probe(struct platform_device *pdev)
{
+ struct snd_soc_dai_link_component *rt1011_dais_components;
+ struct snd_soc_codec_conf *rt1011_dais_confs;
struct card_private *ctx;
struct snd_soc_acpi_mach *mach;
const char *platform_name;
- int ret;
+ int ret, i;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -455,6 +525,73 @@ static int snd_cml_rt1011_probe(struct platform_device *pdev)
snd_soc_card_cml.dev = &pdev->dev;
platform_name = mach->mach_params.platform;
+ dmi_check_system(sof_rt1011_quirk_table);
+
+ dev_info(&pdev->dev, "sof_rt1011_quirk = %lx\n", sof_rt1011_quirk);
+
+ if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL |
+ SOF_RT1011_SPEAKER_TR)) {
+ rt1011_dais_confs = devm_kzalloc(&pdev->dev,
+ sizeof(struct snd_soc_codec_conf) *
+ SPK_CH, GFP_KERNEL);
+
+ if (!rt1011_dais_confs)
+ return -ENOMEM;
+
+ rt1011_dais_components = devm_kzalloc(&pdev->dev,
+ sizeof(struct snd_soc_dai_link_component) *
+ SPK_CH, GFP_KERNEL);
+
+ if (!rt1011_dais_components)
+ return -ENOMEM;
+
+ for (i = 0; i < SPK_CH; i++) {
+ rt1011_dais_confs[i].dlc.name = devm_kasprintf(&pdev->dev,
+ GFP_KERNEL,
+ "i2c-10EC1011:0%d",
+ i);
+
+ if (!rt1011_dais_confs[i].dlc.name)
+ return -ENOMEM;
+
+ switch (i) {
+ case 0:
+ rt1011_dais_confs[i].name_prefix = "WL";
+ break;
+ case 1:
+ rt1011_dais_confs[i].name_prefix = "WR";
+ break;
+ case 2:
+ rt1011_dais_confs[i].name_prefix = "TL";
+ break;
+ case 3:
+ rt1011_dais_confs[i].name_prefix = "TR";
+ break;
+ default:
+ return -EINVAL;
+ }
+ rt1011_dais_components[i].name = devm_kasprintf(&pdev->dev,
+ GFP_KERNEL,
+ "i2c-10EC1011:0%d",
+ i);
+ if (!rt1011_dais_components[i].name)
+ return -ENOMEM;
+
+ rt1011_dais_components[i].dai_name = CML_RT1011_CODEC_DAI;
+ }
+
+ snd_soc_card_cml.codec_conf = rt1011_dais_confs;
+ snd_soc_card_cml.num_configs = SPK_CH;
+
+ for (i = 0; i < ARRAY_SIZE(cml_rt1011_rt5682_dailink); i++) {
+ if (!strcmp(cml_rt1011_rt5682_dailink[i].codecs->dai_name,
+ CML_RT1011_CODEC_DAI)) {
+ cml_rt1011_rt5682_dailink[i].codecs = rt1011_dais_components;
+ cml_rt1011_rt5682_dailink[i].num_codecs = SPK_CH;
+ }
+ }
+ }
+
/* set platform name for each dailink */
ret = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cml,
platform_name);
@@ -482,5 +619,6 @@ MODULE_DESCRIPTION("Cometlake Audio Machine driver - RT1011 and RT5682 in I2S mo
MODULE_AUTHOR("Naveen Manohar <[email protected]>");
MODULE_AUTHOR("Sathya Prakash M R <[email protected]>");
MODULE_AUTHOR("Shuming Fan <[email protected]>");
+MODULE_AUTHOR("Mac Chiang <[email protected]>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:cml_rt1011_rt5682");
diff --git a/sound/soc/intel/boards/ehl_rt5660.c b/sound/soc/intel/boards/ehl_rt5660.c
new file mode 100644
index 000000000000..78160e3b1615
--- /dev/null
+++ b/sound/soc/intel/boards/ehl_rt5660.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2020 Intel Corporation
+
+/*
+ * ehl_rt5660 - ASOC Machine driver for Elkhart Lake platforms
+ * with rt5660 codec
+ */
+
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gfp.h>
+#include <sound/jack.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+
+#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 {
+ struct list_head hdmi_pcm_list;
+ bool idisp_codec;
+};
+
+static const struct snd_kcontrol_new rt5660_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ /* There are two MICBIAS in rt5660, each for one MIC */
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic2"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
+};
+
+static const struct snd_soc_dapm_widget rt5660_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic2", NULL),
+ SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
+};
+
+static const struct snd_soc_dapm_route rt5660_map[] = {
+ {"Speaker", NULL, "SPO"},
+
+ {"Headset Mic", NULL, "MICBIAS1"},
+ {"Headset Mic2", NULL, "MICBIAS2"},
+
+ {"IN1P", NULL, "Headset Mic"},
+ {"IN2P", NULL, "Headset Mic2"},
+
+ {"Line Out", NULL, "LOUTL"},
+ {"Line Out", NULL, "LOUTR"},
+
+ {"DMic", NULL, "SoC DMIC"},
+};
+
+struct sof_hdmi_pcm {
+ struct list_head head;
+ struct snd_soc_dai *codec_dai;
+ int device;
+};
+
+static int hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
+ struct sof_hdmi_pcm *pcm;
+
+ pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
+ if (!pcm)
+ return -ENOMEM;
+
+ /* dai_link id is 1:1 mapped to the PCM device */
+ pcm->device = rtd->dai_link->id;
+ pcm->codec_dai = dai;
+
+ list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+ return 0;
+}
+
+static int card_late_probe(struct snd_soc_card *card)
+{
+ struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
+ struct sof_hdmi_pcm *pcm;
+
+ if (list_empty(&ctx->hdmi_pcm_list))
+ return -ENOENT;
+
+ if (!ctx->idisp_codec)
+ return 0;
+
+ pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head);
+
+ return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component);
+}
+
+static int rt5660_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ RT5660_SCLK_S_PLL1,
+ params_rate(params) * 512,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0,
+ RT5660_PLL1_S_BCLK,
+ params_rate(params) * 50,
+ params_rate(params) * 512);
+ if (ret < 0)
+ dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
+
+ return ret;
+}
+
+static struct snd_soc_ops rt5660_ops = {
+ .hw_params = rt5660_hw_params,
+};
+
+SND_SOC_DAILINK_DEF(ssp0_pin,
+ DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
+
+SND_SOC_DAILINK_DEF(rt5660_codec,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5660:00", "rt5660-aif1")));
+
+SND_SOC_DAILINK_DEF(platform,
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
+
+SND_SOC_DAILINK_DEF(dmic_pin,
+ DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
+SND_SOC_DAILINK_DEF(dmic_codec,
+ DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
+SND_SOC_DAILINK_DEF(dmic16k,
+ DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin")));
+
+SND_SOC_DAILINK_DEF(idisp1_pin,
+ DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
+SND_SOC_DAILINK_DEF(idisp1_codec,
+ DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
+
+SND_SOC_DAILINK_DEF(idisp2_pin,
+ DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
+SND_SOC_DAILINK_DEF(idisp2_codec,
+ DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
+
+SND_SOC_DAILINK_DEF(idisp3_pin,
+ DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
+SND_SOC_DAILINK_DEF(idisp3_codec,
+ DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
+
+SND_SOC_DAILINK_DEF(idisp4_pin,
+ DAILINK_COMP_ARRAY(COMP_CPU("iDisp4 Pin")));
+SND_SOC_DAILINK_DEF(idisp4_codec,
+ DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi4")));
+
+static struct snd_soc_dai_link ehl_rt5660_dailink[] = {
+ /* back ends */
+ {
+ .name = "SSP0-Codec",
+ .id = 0,
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ops = &rt5660_ops,
+ .nonatomic = true,
+ SND_SOC_DAILINK_REG(ssp0_pin, rt5660_codec, platform),
+ },
+ {
+ .name = "dmic48k",
+ .id = 1,
+ .ignore_suspend = 1,
+ .dpcm_capture = 1,
+ .no_pcm = 1,
+ SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
+ },
+ {
+ .name = "dmic16k",
+ .id = 2,
+ .ignore_suspend = 1,
+ .dpcm_capture = 1,
+ .no_pcm = 1,
+ SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform),
+ },
+ {
+ .name = "iDisp1",
+ .id = 5,
+ .init = hdmi_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
+ },
+ {
+ .name = "iDisp2",
+ .id = 6,
+ .init = hdmi_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
+ },
+ {
+ .name = "iDisp3",
+ .id = 7,
+ .init = hdmi_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
+ },
+ {
+ .name = "iDisp4",
+ .id = 8,
+ .init = hdmi_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform),
+ },
+};
+
+/* SoC card */
+static struct snd_soc_card snd_soc_card_ehl_rt5660 = {
+ .name = "ehl-rt5660",
+ .owner = THIS_MODULE,
+ .dai_link = ehl_rt5660_dailink,
+ .num_links = ARRAY_SIZE(ehl_rt5660_dailink),
+ .dapm_widgets = rt5660_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt5660_widgets),
+ .dapm_routes = rt5660_map,
+ .num_dapm_routes = ARRAY_SIZE(rt5660_map),
+ .controls = rt5660_controls,
+ .num_controls = ARRAY_SIZE(rt5660_controls),
+ .fully_routed = true,
+ .late_probe = card_late_probe,
+};
+
+/* If hdmi codec is not supported, switch to use dummy codec */
+static void hdmi_link_init(struct snd_soc_card *card,
+ struct sof_card_private *ctx,
+ struct snd_soc_acpi_mach *mach)
+{
+ struct snd_soc_dai_link *link;
+ int i;
+
+ if (mach->mach_params.common_hdmi_codec_drv &&
+ (mach->mach_params.codec_mask & IDISP_CODEC_MASK)) {
+ ctx->idisp_codec = true;
+ return;
+ }
+
+ /*
+ * if HDMI is not enabled in kernel config, or
+ * hdmi codec is not supported
+ */
+ for (i = HDMI_LINK_START; i <= HDMI_LINE_END; i++) {
+ link = &card->dai_link[i];
+ link->codecs[0].name = "snd-soc-dummy";
+ link->codecs[0].dai_name = "snd-soc-dummy-dai";
+ }
+}
+
+static int snd_ehl_rt5660_probe(struct platform_device *pdev)
+{
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card = &snd_soc_card_ehl_rt5660;
+ struct sof_card_private *ctx;
+ int ret;
+
+ card->dev = &pdev->dev;
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+ snd_soc_card_set_drvdata(card, ctx);
+
+ mach = pdev->dev.platform_data;
+ ret = snd_soc_fixup_dai_links_platform_name(card,
+ mach->mach_params.platform);
+ if (ret)
+ return ret;
+
+ hdmi_link_init(card, ctx, mach);
+
+ return devm_snd_soc_register_card(&pdev->dev, card);
+}
+
+static const struct platform_device_id ehl_board_ids[] = {
+ { .name = "ehl_rt5660" },
+ { }
+};
+
+static struct platform_driver snd_ehl_rt5660_driver = {
+ .driver = {
+ .name = "ehl_rt5660",
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = snd_ehl_rt5660_probe,
+ .id_table = ehl_board_ids,
+};
+
+module_platform_driver(snd_ehl_rt5660_driver);
+
+MODULE_DESCRIPTION("ASoC Intel(R) Elkhartlake + rt5660 Machine driver");
+MODULE_AUTHOR("[email protected]");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ehl_rt5660");
diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c
index f13158e4a1fc..48eda1a8aa6c 100644
--- a/sound/soc/intel/boards/glk_rt5682_max98357a.c
+++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright(c) 2018 Intel Corporation.
/*
diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c
index 9179f07f9ee4..244b57fba64c 100644
--- a/sound/soc/intel/boards/hda_dsp_common.c
+++ b/sound/soc/intel/boards/hda_dsp_common.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
//
// Copyright(c) 2019 Intel Corporation. All rights reserved.
diff --git a/sound/soc/intel/boards/hda_dsp_common.h b/sound/soc/intel/boards/hda_dsp_common.h
index 431f7f09dccb..727edd256962 100644
--- a/sound/soc/intel/boards/hda_dsp_common.h
+++ b/sound/soc/intel/boards/hda_dsp_common.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright(c) 2019 Intel Corporation.
*/
diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c
index 32cd90b8d4c4..dc3d897ad280 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98357a.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright(c) 2017-18 Intel Corporation.
/*
diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c
index abd4e3839678..cc9b5eab8b4a 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98927.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98927.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright(c) 2018 Intel Corporation.
/*
diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c
index 6460e3f0c974..d2a078454784 100644
--- a/sound/soc/intel/boards/kbl_rt5660.c
+++ b/sound/soc/intel/boards/kbl_rt5660.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright(c) 2018-19 Canonical Corporation.
/*
diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c
index 78ff5f24c40e..07bfb2e64b3b 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_common.c
+++ b/sound/soc/intel/boards/skl_hda_dsp_common.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright(c) 2015-18 Intel Corporation.
/*
diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h
index e8545d13062f..507750ef67f3 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_common.h
+++ b/sound/soc/intel/boards/skl_hda_dsp_common.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright(c) 2015-18 Intel Corporation.
*/
diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c
index 3be764299ab0..79c8947f840b 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_generic.c
+++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright(c) 2015-18 Intel Corporation.
/*
@@ -113,6 +113,8 @@ static char hda_soc_components[30];
#define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2)
#define IDISP_CODEC_MASK 0x4
+#define HDA_CODEC_AUTOSUSPEND_DELAY_MS 1000
+
static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params)
{
struct snd_soc_card *card = &hda_soc_card;
@@ -168,6 +170,29 @@ static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params)
return 0;
}
+static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ struct hdac_hda_priv *hda_pvt;
+ struct snd_soc_dai *dai;
+
+ for_each_card_rtds(card, rtd) {
+ if (!strstr(rtd->dai_link->codecs->name, "ehdaudio"))
+ continue;
+ dai = asoc_rtd_to_codec(rtd, 0);
+ hda_pvt = snd_soc_component_get_drvdata(dai->component);
+ if (hda_pvt) {
+ /*
+ * all codecs are on the same bus, so it's sufficient
+ * to look up only the first one
+ */
+ snd_hda_set_power_save(hda_pvt->codec.bus,
+ HDA_CODEC_AUTOSUSPEND_DELAY_MS);
+ break;
+ }
+ }
+}
+
static int skl_hda_audio_probe(struct platform_device *pdev)
{
struct snd_soc_acpi_mach *mach;
@@ -206,7 +231,11 @@ static int skl_hda_audio_probe(struct platform_device *pdev)
hda_soc_card.components = hda_soc_components;
}
- return devm_snd_soc_register_card(&pdev->dev, &hda_soc_card);
+ ret = devm_snd_soc_register_card(&pdev->dev, &hda_soc_card);
+ if (!ret)
+ skl_set_hda_codec_autosuspend_delay(&hda_soc_card);
+
+ return ret;
}
static struct platform_driver skl_hda_audio = {
diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c
index b707dd3b5625..703703858595 100644
--- a/sound/soc/intel/boards/sof_da7219_max98373.c
+++ b/sound/soc/intel/boards/sof_da7219_max98373.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright(c) 2019 Intel Corporation.
/*
@@ -86,6 +86,8 @@ static const struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
platform_clock_control, SND_SOC_DAPM_POST_PMD |
SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MIC("SoC DMIC", NULL),
};
static const struct snd_soc_dapm_route audio_map[] = {
@@ -99,6 +101,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
{ "Left Spk", NULL, "Left BE_OUT" },
{ "Right Spk", NULL, "Right BE_OUT" },
+
+ /* digital mics */
+ {"DMic", NULL, "SoC DMIC"},
};
/* For MAX98360A amp */
@@ -111,6 +116,8 @@ static const struct snd_soc_dapm_widget max98360a_widgets[] = {
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
platform_clock_control, SND_SOC_DAPM_POST_PMD |
SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MIC("SoC DMIC", NULL),
};
static const struct snd_soc_dapm_route max98360a_map[] = {
@@ -123,6 +130,9 @@ static const struct snd_soc_dapm_route max98360a_map[] = {
{ "Headset Mic", NULL, "Platform Clock" },
{"Spk", NULL, "Speaker"},
+
+ /* digital mics */
+ {"DMic", NULL, "SoC DMIC"},
};
static struct snd_soc_jack headset;
@@ -265,6 +275,9 @@ SND_SOC_DAILINK_DEF(dmic_pin,
SND_SOC_DAILINK_DEF(dmic_codec,
DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
+SND_SOC_DAILINK_DEF(dmic16k_pin,
+ DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin")));
+
SND_SOC_DAILINK_DEF(idisp1_pin,
DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
SND_SOC_DAILINK_DEF(idisp1_codec,
@@ -337,6 +350,14 @@ static struct snd_soc_dai_link dais[] = {
.no_pcm = 1,
SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
},
+ {
+ .name = "dmic16k",
+ .id = 6,
+ .ignore_suspend = 1,
+ .dpcm_capture = 1,
+ .no_pcm = 1,
+ SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform),
+ }
};
static struct snd_soc_card card_da7219_m98373 = {
diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c
index 463b39a7ccfd..1a549b32d1c9 100644
--- a/sound/soc/intel/boards/sof_maxim_common.c
+++ b/sound/soc/intel/boards/sof_maxim_common.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
//
// Copyright(c) 2020 Intel Corporation. All rights reserved.
#include <linux/string.h>
diff --git a/sound/soc/intel/boards/sof_maxim_common.h b/sound/soc/intel/boards/sof_maxim_common.h
index 406bf0e81155..785b34335368 100644
--- a/sound/soc/intel/boards/sof_maxim_common.h
+++ b/sound/soc/intel/boards/sof_maxim_common.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright(c) 2020 Intel Corporation.
*/
diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c
index fb7811899999..f983c7fbb1d1 100644
--- a/sound/soc/intel/boards/sof_pcm512x.c
+++ b/sound/soc/intel/boards/sof_pcm512x.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright(c) 2018-2020 Intel Corporation.
/*
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 8c29431b5847..13a48b0c35ae 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright(c) 2019-2020 Intel Corporation.
/*
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index a64dc563b47e..bbbc802624f8 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2020 Intel Corporation
/*
@@ -411,25 +411,36 @@ static int create_codec_dai_name(struct device *dev,
static int set_codec_init_func(const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
- bool playback)
+ bool playback, int group_id)
{
int i;
- for (i = 0; i < link->num_adr; i++) {
- unsigned int part_id;
- int codec_index;
-
- part_id = SDW_PART_ID(link->adr_d[i].adr);
- codec_index = find_codec_info_part(part_id);
+ do {
+ /*
+ * Initialize the codec. If codec is part of an aggregated
+ * group (group_id>0), initialize all codecs belonging to
+ * same group.
+ */
+ for (i = 0; i < link->num_adr; i++) {
+ unsigned int part_id;
+ int codec_index;
- if (codec_index < 0)
- return codec_index;
+ part_id = SDW_PART_ID(link->adr_d[i].adr);
+ codec_index = find_codec_info_part(part_id);
- if (codec_info_list[codec_index].init)
- codec_info_list[codec_index].init(link, dai_links,
- &codec_info_list[codec_index],
- playback);
- }
+ if (codec_index < 0)
+ return codec_index;
+ /* The group_id is > 0 iff the codec is aggregated */
+ if (link->adr_d[i].endpoints->group_id != group_id)
+ continue;
+ if (codec_info_list[codec_index].init)
+ codec_info_list[codec_index].init(link,
+ dai_links,
+ &codec_info_list[codec_index],
+ playback);
+ }
+ link++;
+ } while (link->mask && group_id);
return 0;
}
@@ -623,7 +634,7 @@ static int create_sdw_dailink(struct device *dev, int *be_index,
NULL, &sdw_ops);
ret = set_codec_init_func(link, dai_links + (*be_index)++,
- playback);
+ playback, group_id);
if (ret < 0) {
dev_err(dev, "failed to init codec %d", codec_index);
return ret;
@@ -898,6 +909,7 @@ static int mc_probe(struct platform_device *pdev)
struct snd_soc_card *card = &card_sof_sdw;
struct snd_soc_acpi_mach *mach;
struct mc_private *ctx;
+ int amp_num = 0, i;
int ret;
dev_dbg(&pdev->dev, "Entry %s\n", __func__);
@@ -924,9 +936,18 @@ static int mc_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(card, ctx);
+ /*
+ * the default amp_num is zero for each codec and
+ * amp_num will only be increased for active amp
+ * codecs on used platform
+ */
+ for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
+ amp_num += codec_info_list[i].amp_num;
+
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "cfg-spk:%d",
- (sof_sdw_quirk & SOF_SDW_FOUR_SPK) ? 4 : 2);
+ "cfg-spk:%d, cfg-amp:%d",
+ (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
+ ? 4 : 2, amp_num);
if (!card->components)
return -ENOMEM;
diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h
index dd593ff3575b..69b363b8a686 100644
--- a/sound/soc/intel/boards/sof_sdw_common.h
+++ b/sound/soc/intel/boards/sof_sdw_common.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0-only
* Copyright (c) 2020 Intel Corporation
*/
diff --git a/sound/soc/intel/boards/sof_sdw_dmic.c b/sound/soc/intel/boards/sof_sdw_dmic.c
index e92176bf0ad4..89b0824b2381 100644
--- a/sound/soc/intel/boards/sof_sdw_dmic.c
+++ b/sound/soc/intel/boards/sof_sdw_dmic.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2020 Intel Corporation
/*
diff --git a/sound/soc/intel/boards/sof_sdw_hdmi.c b/sound/soc/intel/boards/sof_sdw_hdmi.c
index c7b5612a39e6..b60852339330 100644
--- a/sound/soc/intel/boards/sof_sdw_hdmi.c
+++ b/sound/soc/intel/boards/sof_sdw_hdmi.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2020 Intel Corporation
/*
@@ -28,7 +28,7 @@ struct hdmi_pcm {
int sof_sdw_hdmi_init(struct snd_soc_pcm_runtime *rtd)
{
struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = rtd->codec_dai;
+ struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
struct hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
@@ -90,7 +90,7 @@ int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card)
return hdac_hdmi_jack_port_init(component, &card->dapm);
}
#else
-int hdmi_card_late_probe(struct snd_soc_card *card)
+int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card)
{
return 0;
}
diff --git a/sound/soc/intel/boards/sof_sdw_rt1308.c b/sound/soc/intel/boards/sof_sdw_rt1308.c
index 321768e54d08..177cc781ada6 100644
--- a/sound/soc/intel/boards/sof_sdw_rt1308.c
+++ b/sound/soc/intel/boards/sof_sdw_rt1308.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2020 Intel Corporation
/*
@@ -93,7 +93,7 @@ static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
int clk_id, clk_freq, pll_out;
int err;
diff --git a/sound/soc/intel/boards/sof_sdw_rt5682.c b/sound/soc/intel/boards/sof_sdw_rt5682.c
index 5aa6211a1ed9..da354ba83939 100644
--- a/sound/soc/intel/boards/sof_sdw_rt5682.c
+++ b/sound/soc/intel/boards/sof_sdw_rt5682.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2020 Intel Corporation
/*
@@ -47,7 +47,8 @@ static int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_component *component = rtd->codec_dai->component;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_component *component = codec_dai->component;
struct snd_soc_jack *jack;
int ret;
diff --git a/sound/soc/intel/boards/sof_sdw_rt700.c b/sound/soc/intel/boards/sof_sdw_rt700.c
index 2ee4e6910d7f..5515f397a3dd 100644
--- a/sound/soc/intel/boards/sof_sdw_rt700.c
+++ b/sound/soc/intel/boards/sof_sdw_rt700.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2020 Intel Corporation
/*
@@ -47,7 +47,8 @@ static int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_component *component = rtd->codec_dai->component;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_component *component = codec_dai->component;
struct snd_soc_jack *jack;
int ret;
diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/intel/boards/sof_sdw_rt711.c
index 2a4917e3d561..1ded5d9895cf 100644
--- a/sound/soc/intel/boards/sof_sdw_rt711.c
+++ b/sound/soc/intel/boards/sof_sdw_rt711.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2020 Intel Corporation
/*
@@ -71,7 +71,8 @@ static int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_component *component = rtd->codec_dai->component;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_component *component = codec_dai->component;
struct snd_soc_jack *jack;
int ret;
diff --git a/sound/soc/intel/boards/sof_sdw_rt715.c b/sound/soc/intel/boards/sof_sdw_rt715.c
index 321e1cbc03ed..9b298f79e784 100644
--- a/sound/soc/intel/boards/sof_sdw_rt715.c
+++ b/sound/soc/intel/boards/sof_sdw_rt715.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2020 Intel Corporation
/*
diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c
new file mode 100644
index 000000000000..c13fd20da559
--- /dev/null
+++ b/sound/soc/intel/boards/sof_wm8804.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2020, Intel Corporation
+//
+// sof-wm8804.c - ASoC machine driver for Up and Up2 board
+// based on WM8804/Hifiberry Digi+
+
+
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../codecs/wm8804.h"
+
+struct sof_card_private {
+ struct gpio_desc *gpio_44;
+ struct gpio_desc *gpio_48;
+ int sample_rate;
+};
+
+#define SOF_WM8804_UP2_QUIRK BIT(0)
+
+static unsigned long sof_wm8804_quirk;
+
+static int sof_wm8804_quirk_cb(const struct dmi_system_id *id)
+{
+ sof_wm8804_quirk = (unsigned long)id->driver_data;
+ return 1;
+}
+
+static const struct dmi_system_id sof_wm8804_quirk_table[] = {
+ {
+ .callback = sof_wm8804_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "UP-APL01"),
+ },
+ .driver_data = (void *)SOF_WM8804_UP2_QUIRK,
+ },
+ {}
+};
+
+static int sof_wm8804_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_component *codec = codec_dai->component;
+ const int sysclk = 27000000; /* This is fixed on this board */
+ int samplerate;
+ long mclk_freq;
+ int mclk_div;
+ int sampling_freq;
+ bool clk_44;
+ int ret;
+
+ samplerate = params_rate(params);
+ if (samplerate == ctx->sample_rate)
+ return 0;
+
+ ctx->sample_rate = 0;
+
+ if (samplerate <= 96000) {
+ mclk_freq = samplerate * 256;
+ mclk_div = WM8804_MCLKDIV_256FS;
+ } else {
+ mclk_freq = samplerate * 128;
+ mclk_div = WM8804_MCLKDIV_128FS;
+ }
+
+ switch (samplerate) {
+ case 32000:
+ sampling_freq = 0x03;
+ break;
+ case 44100:
+ sampling_freq = 0x00;
+ break;
+ case 48000:
+ sampling_freq = 0x02;
+ break;
+ case 88200:
+ sampling_freq = 0x08;
+ break;
+ case 96000:
+ sampling_freq = 0x0a;
+ break;
+ case 176400:
+ sampling_freq = 0x0c;
+ break;
+ case 192000:
+ sampling_freq = 0x0e;
+ break;
+ default:
+ dev_err(rtd->card->dev,
+ "unsupported samplerate %d\n", samplerate);
+ return -EINVAL;
+ }
+
+ if (samplerate % 16000)
+ clk_44 = true; /* use 44.1 kHz root frequency */
+ else
+ clk_44 = false;
+
+ if (!(IS_ERR_OR_NULL(ctx->gpio_44) ||
+ IS_ERR_OR_NULL(ctx->gpio_48))) {
+ /*
+ * ensure both GPIOs are LOW first, then drive the
+ * relevant one to HIGH
+ */
+ if (clk_44) {
+ gpiod_set_value_cansleep(ctx->gpio_48, !clk_44);
+ gpiod_set_value_cansleep(ctx->gpio_44, clk_44);
+ } else {
+ gpiod_set_value_cansleep(ctx->gpio_44, clk_44);
+ gpiod_set_value_cansleep(ctx->gpio_48, !clk_44);
+ }
+ }
+
+ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
+ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
+ sysclk, SND_SOC_CLOCK_OUT);
+ if (ret < 0) {
+ dev_err(rtd->card->dev,
+ "Failed to set WM8804 SYSCLK: %d\n", ret);
+ return ret;
+ }
+
+ /* set sampling frequency status bits */
+ snd_soc_component_update_bits(codec, WM8804_SPDTX4, 0x0f,
+ sampling_freq);
+
+ ctx->sample_rate = samplerate;
+
+ return 0;
+}
+
+/* machine stream operations */
+static struct snd_soc_ops sof_wm8804_ops = {
+ .hw_params = sof_wm8804_hw_params,
+};
+
+SND_SOC_DAILINK_DEF(ssp5_pin,
+ DAILINK_COMP_ARRAY(COMP_CPU("SSP5 Pin")));
+
+SND_SOC_DAILINK_DEF(ssp5_codec,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-1AEC8804:00", "wm8804-spdif")));
+
+SND_SOC_DAILINK_DEF(platform,
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:0e.0")));
+
+static struct snd_soc_dai_link dailink[] = {
+ /* back ends */
+ {
+ .name = "SSP5-Codec",
+ .id = 0,
+ .no_pcm = 1,
+ .nonatomic = true,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ops = &sof_wm8804_ops,
+ SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform),
+ },
+};
+
+/* SoC card */
+static struct snd_soc_card sof_wm8804_card = {
+ .name = "wm8804", /* sof- prefix added automatically */
+ .owner = THIS_MODULE,
+ .dai_link = dailink,
+ .num_links = ARRAY_SIZE(dailink),
+};
+
+ /* i2c-<HID>:00 with HID being 8 chars */
+static char codec_name[SND_ACPI_I2C_ID_LEN];
+
+/*
+ * to control the HifiBerry Digi+ PRO, it's required to toggle GPIO to
+ * select the clock source. On the Up2 board, this means
+ * Pin29/BCM5/Linux GPIO 430 and Pin 31/BCM6/ Linux GPIO 404.
+ *
+ * Using the ACPI device name is not very nice, but since we only use
+ * the value for the Up2 board there is no risk of conflict with other
+ * platforms.
+ */
+
+static struct gpiod_lookup_table up2_gpios_table = {
+ /* .dev_id is set during probe */
+ .table = {
+ GPIO_LOOKUP("INT3452:01", 73, "BCM-GPIO5", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("INT3452:01", 74, "BCM-GPIO6", GPIO_ACTIVE_HIGH),
+ { },
+ },
+};
+
+static int sof_wm8804_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card;
+ struct snd_soc_acpi_mach *mach;
+ struct sof_card_private *ctx;
+ struct acpi_device *adev;
+ int dai_index = 0;
+ int ret;
+ int i;
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ mach = pdev->dev.platform_data;
+ card = &sof_wm8804_card;
+ card->dev = &pdev->dev;
+
+ dmi_check_system(sof_wm8804_quirk_table);
+
+ if (sof_wm8804_quirk & SOF_WM8804_UP2_QUIRK) {
+ up2_gpios_table.dev_id = dev_name(&pdev->dev);
+ gpiod_add_lookup_table(&up2_gpios_table);
+
+ /*
+ * The gpios are required for specific boards with
+ * local oscillators, and optional in other cases.
+ * Since we can't identify when they are needed, use
+ * the GPIO as non-optional
+ */
+
+ ctx->gpio_44 = devm_gpiod_get(&pdev->dev, "BCM-GPIO5",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->gpio_44)) {
+ ret = PTR_ERR(ctx->gpio_44);
+ dev_err(&pdev->dev,
+ "could not get BCM-GPIO5: %d\n",
+ ret);
+ return ret;
+ }
+
+ ctx->gpio_48 = devm_gpiod_get(&pdev->dev, "BCM-GPIO6",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->gpio_48)) {
+ ret = PTR_ERR(ctx->gpio_48);
+ dev_err(&pdev->dev,
+ "could not get BCM-GPIO6: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ /* fix index of codec dai */
+ for (i = 0; i < ARRAY_SIZE(dailink); i++) {
+ if (!strcmp(dailink[i].codecs->name, "i2c-1AEC8804:00")) {
+ dai_index = i;
+ break;
+ }
+ }
+
+ /* fixup codec name based on HID */
+ adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1);
+ if (adev) {
+ snprintf(codec_name, sizeof(codec_name),
+ "%s%s", "i2c-", acpi_dev_name(adev));
+ put_device(&adev->dev);
+ dailink[dai_index].codecs->name = codec_name;
+ }
+
+ snd_soc_card_set_drvdata(card, ctx);
+
+ return devm_snd_soc_register_card(&pdev->dev, card);
+}
+
+static int sof_wm8804_remove(struct platform_device *pdev)
+{
+ if (sof_wm8804_quirk & SOF_WM8804_UP2_QUIRK)
+ gpiod_remove_lookup_table(&up2_gpios_table);
+ return 0;
+}
+
+static struct platform_driver sof_wm8804_driver = {
+ .driver = {
+ .name = "sof-wm8804",
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = sof_wm8804_probe,
+ .remove = sof_wm8804_remove,
+};
+module_platform_driver(sof_wm8804_driver);
+
+MODULE_DESCRIPTION("ASoC Intel(R) SOF + WM8804 Machine driver");
+MODULE_AUTHOR("Pierre-Louis Bossart");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sof-wm8804");
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index bd352878f89a..2674c9790fa1 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
snd-soc-sst-dsp-objs := sst-dsp.o
snd-soc-sst-acpi-objs := sst-acpi.o
snd-soc-sst-ipc-objs := sst-ipc.o
diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c
index f5092bc48364..68758e7a16d8 100644
--- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* soc-acpi-intel-bxt-match.c - tables and support for BXT ACPI enumeration.
*
diff --git a/sound/soc/intel/common/soc-acpi-intel-cfl-match.c b/sound/soc/intel/common/soc-acpi-intel-cfl-match.c
index ff9d6938b9f6..27b4b73d94d4 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cfl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cfl-match.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* soc-apci-intel-cfl-match.c - tables and support for CFL ACPI enumeration.
*
diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
index 7d85bd5aff9f..cdea0c09fe0a 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* soc-acpi-intel-cml-match.c - tables and support for CML ACPI enumeration.
*
diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
index 828980d5630d..6a0bcc1a8429 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* soc-acpi-intel-cnl-match.c - tables and support for CNL ACPI enumeration.
*
diff --git a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c
index a1290c3fa99f..45e07d886013 100644
--- a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* soc-apci-intel-ehl-match.c - tables and support for EHL ACPI enumeration.
*
@@ -8,8 +8,15 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+#include "../skylake/skl.h"
struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[] = {
+ {
+ .id = "INTC1027",
+ .drv_name = "ehl_rt5660",
+ .sof_fw_filename = "sof-ehl.ri",
+ .sof_tplg_filename = "sof-ehl-rt5660.tplg",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ehl_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c
index 60dea358fa04..26cb3b16cdd3 100644
--- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* soc-acpi-intel-glk-match.c - tables and support for GLK ACPI enumeration.
*
diff --git a/sound/soc/intel/common/soc-acpi-intel-hda-match.c b/sound/soc/intel/common/soc-acpi-intel-hda-match.c
index cc972d2ac691..aa9cb522aac9 100644
--- a/sound/soc/intel/common/soc-acpi-intel-hda-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-hda-match.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2018, Intel Corporation.
/*
diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
index 16ec9f382b0f..6927bbbc66fc 100644
--- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* soc-acpi-intel-icl-match.c - tables and support for ICL ACPI enumeration.
*
diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
index 4388a32718d8..859f8a1bd914 100644
--- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* soc-apci-intel-jsl-match.c - tables and support for JSL ACPI enumeration.
*
diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
index e200baa11011..a4fbe6707ca7 100644
--- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* soc-acpi-intel-kbl-match.c - tables and support for KBL ACPI enumeration.
*
diff --git a/sound/soc/intel/common/soc-acpi-intel-skl-match.c b/sound/soc/intel/common/soc-acpi-intel-skl-match.c
index 42fa40a8d932..26f9ce146523 100644
--- a/sound/soc/intel/common/soc-acpi-intel-skl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-skl-match.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* soc-acpi-intel-skl-match.c - tables and support for SKL ACPI enumeration.
*
diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
index 449d9d2286ae..5a56f4359479 100644
--- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* soc-apci-intel-tgl-match.c - tables and support for ICL ACPI enumeration.
*
diff --git a/sound/soc/intel/common/soc-intel-quirks.h b/sound/soc/intel/common/soc-intel-quirks.h
index a9176150c6ed..b07df3059926 100644
--- a/sound/soc/intel/common/soc-intel-quirks.h
+++ b/sound/soc/intel/common/soc-intel-quirks.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* soc-intel-quirks.h - prototypes for quirk autodetection
*
diff --git a/sound/soc/intel/haswell/sst-haswell-dsp.c b/sound/soc/intel/haswell/sst-haswell-dsp.c
index 88c3f63bded9..de80e19454c1 100644
--- a/sound/soc/intel/haswell/sst-haswell-dsp.c
+++ b/sound/soc/intel/haswell/sst-haswell-dsp.c
@@ -243,45 +243,92 @@ static irqreturn_t hsw_irq(int irq, void *context)
return ret;
}
+#define CSR_DEFAULT_VALUE 0x8480040E
+#define ISC_DEFAULT_VALUE 0x0
+#define ISD_DEFAULT_VALUE 0x0
+#define IMC_DEFAULT_VALUE 0x7FFF0003
+#define IMD_DEFAULT_VALUE 0x7FFF0003
+#define IPCC_DEFAULT_VALUE 0x0
+#define IPCD_DEFAULT_VALUE 0x0
+#define CLKCTL_DEFAULT_VALUE 0x7FF
+#define CSR2_DEFAULT_VALUE 0x0
+#define LTR_CTRL_DEFAULT_VALUE 0x0
+#define HMD_CTRL_DEFAULT_VALUE 0x0
+
+static void hsw_set_shim_defaults(struct sst_dsp *sst)
+{
+ sst_dsp_shim_write_unlocked(sst, SST_CSR, CSR_DEFAULT_VALUE);
+ sst_dsp_shim_write_unlocked(sst, SST_ISRX, ISC_DEFAULT_VALUE);
+ sst_dsp_shim_write_unlocked(sst, SST_ISRD, ISD_DEFAULT_VALUE);
+ sst_dsp_shim_write_unlocked(sst, SST_IMRX, IMC_DEFAULT_VALUE);
+ sst_dsp_shim_write_unlocked(sst, SST_IMRD, IMD_DEFAULT_VALUE);
+ sst_dsp_shim_write_unlocked(sst, SST_IPCX, IPCC_DEFAULT_VALUE);
+ sst_dsp_shim_write_unlocked(sst, SST_IPCD, IPCD_DEFAULT_VALUE);
+ sst_dsp_shim_write_unlocked(sst, SST_CLKCTL, CLKCTL_DEFAULT_VALUE);
+ sst_dsp_shim_write_unlocked(sst, SST_CSR2, CSR2_DEFAULT_VALUE);
+ sst_dsp_shim_write_unlocked(sst, SST_LTRC, LTR_CTRL_DEFAULT_VALUE);
+ sst_dsp_shim_write_unlocked(sst, SST_HMDC, HMD_CTRL_DEFAULT_VALUE);
+}
+
+/* all clock-gating minus DCLCGE and DTCGE */
+#define SST_VDRTCL2_CG_OTHER 0xB7D
+
static void hsw_set_dsp_D3(struct sst_dsp *sst)
{
- u32 val;
u32 reg;
- /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
+ /* disable clock core gating */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
- reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
+ reg &= ~(SST_VDRTCL2_DCLCGE);
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
- /* enable power gating and switch off DRAM & IRAM blocks */
- val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
- val |= SST_VDRTCL0_DSRAMPGE_MASK |
- SST_VDRTCL0_ISRAMPGE_MASK;
- val &= ~(SST_VDRTCL0_D3PGD | SST_VDRTCL0_D3SRAMPGD);
- writel(val, sst->addr.pci_cfg + SST_VDRTCTL0);
+ /* stall, reset and set 24MHz XOSC */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
+ SST_CSR_24MHZ_LPCS | SST_CSR_STALL | SST_CSR_RST,
+ SST_CSR_24MHZ_LPCS | SST_CSR_STALL | SST_CSR_RST);
- /* switch off audio PLL */
- val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
- val |= SST_VDRTCL2_APLLSE_MASK;
- writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
+ /* DRAM power gating all */
+ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+ reg |= SST_VDRTCL0_ISRAMPGE_MASK |
+ SST_VDRTCL0_DSRAMPGE_MASK;
+ reg &= ~(SST_VDRTCL0_D3SRAMPGD);
+ reg |= SST_VDRTCL0_D3PGD;
+ writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
+ udelay(50);
- /* disable MCLK(clkctl.smos = 0) */
- sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
- SST_CLKCTL_MASK, 0);
+ /* PLL shutdown enable */
+ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+ reg |= SST_VDRTCL2_APLLSE_MASK;
+ writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
- /* Set D3 state, delay 50 us */
- val = readl(sst->addr.pci_cfg + SST_PMCS);
- val |= SST_PMCS_PS_MASK;
- writel(val, sst->addr.pci_cfg + SST_PMCS);
- udelay(50);
+ /* disable MCLK */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
+ SST_CLKCTL_MASK, 0);
- /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
+ /* switch clock gating */
+ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+ reg |= SST_VDRTCL2_CG_OTHER;
+ reg &= ~(SST_VDRTCL2_DTCGE);
+ writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+ /* enable DTCGE separatelly */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
- reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
+ reg |= SST_VDRTCL2_DTCGE;
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+ /* set shim defaults */
+ hsw_set_shim_defaults(sst);
+
+ /* set D3 */
+ reg = readl(sst->addr.pci_cfg + SST_PMCS);
+ reg |= SST_PMCS_PS_MASK;
+ writel(reg, sst->addr.pci_cfg + SST_PMCS);
udelay(50);
+ /* enable clock core gating */
+ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+ reg |= SST_VDRTCL2_DCLCGE;
+ writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+ udelay(50);
}
static void hsw_reset(struct sst_dsp *sst)
@@ -299,75 +346,62 @@ static void hsw_reset(struct sst_dsp *sst)
SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
}
+/* recommended CSR state for power-up */
+#define SST_CSR_D0_MASK (0x18A09C0C | SST_CSR_DCS_MASK)
+
static int hsw_set_dsp_D0(struct sst_dsp *sst)
{
- int tries = 10;
- u32 reg, fw_dump_bit;
+ u32 reg;
- /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
+ /* disable clock core gating */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
- reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
+ reg &= ~(SST_VDRTCL2_DCLCGE);
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
- /* Disable D3PG (VDRTCTL0.D3PGD = 1) */
- reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
- reg |= SST_VDRTCL0_D3PGD;
- writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
+ /* switch clock gating */
+ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+ reg |= SST_VDRTCL2_CG_OTHER;
+ reg &= ~(SST_VDRTCL2_DTCGE);
+ writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
- /* Set D0 state */
+ /* set D0 */
reg = readl(sst->addr.pci_cfg + SST_PMCS);
- reg &= ~SST_PMCS_PS_MASK;
+ reg &= ~(SST_PMCS_PS_MASK);
writel(reg, sst->addr.pci_cfg + SST_PMCS);
- /* check that ADSP shim is enabled */
- while (tries--) {
- reg = readl(sst->addr.pci_cfg + SST_PMCS) & SST_PMCS_PS_MASK;
- if (reg == 0)
- goto finish;
-
- msleep(1);
- }
-
- return -ENODEV;
-
-finish:
- /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */
- sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
- SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0);
+ /* DRAM power gating none */
+ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+ reg &= ~(SST_VDRTCL0_ISRAMPGE_MASK |
+ SST_VDRTCL0_DSRAMPGE_MASK);
+ reg |= SST_VDRTCL0_D3SRAMPGD;
+ reg |= SST_VDRTCL0_D3PGD;
+ writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
+ mdelay(10);
- /* stall DSP core, set clk to 192/96Mhz */
- sst_dsp_shim_update_bits_unlocked(sst,
- SST_CSR, SST_CSR_STALL | SST_CSR_DCS_MASK,
- SST_CSR_STALL | SST_CSR_DCS(4));
+ /* set shim defaults */
+ hsw_set_shim_defaults(sst);
- /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */
+ /* restore MCLK */
sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
- SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0,
- SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0);
+ SST_CLKCTL_MASK, SST_CLKCTL_MASK);
- /* Stall and reset core, set CSR */
- hsw_reset(sst);
-
- /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
+ /* PLL shutdown disable */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
- reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
+ reg &= ~(SST_VDRTCL2_APLLSE_MASK);
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+ sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
+ SST_CSR_D0_MASK, SST_CSR_SBCS0 | SST_CSR_SBCS1 |
+ SST_CSR_STALL | SST_CSR_DCS(4));
udelay(50);
- /* switch on audio PLL */
+ /* enable clock core gating */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
- reg &= ~SST_VDRTCL2_APLLSE_MASK;
+ reg |= SST_VDRTCL2_DCLCGE;
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
- /* set default power gating control, enable power gating control for all blocks. that is,
- can't be accessed, please enable each block before accessing. */
- reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
- reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK;
- /* for D0, always enable the block(DSRAM[0]) used for FW dump */
- fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
- writel(reg & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
-
+ /* clear reset */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_RST, 0);
/* disable DMA finish function for SSP0 & SSP1 */
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1,
@@ -384,12 +418,6 @@ finish:
sst_dsp_shim_update_bits(sst, SST_IMRD, (SST_IMRD_DONE | SST_IMRD_BUSY |
SST_IMRD_SSP0 | SST_IMRD_DMAC), 0x0);
- /* clear IPC registers */
- sst_dsp_shim_write(sst, SST_IPCX, 0x0);
- sst_dsp_shim_write(sst, SST_IPCD, 0x0);
- sst_dsp_shim_write(sst, 0x80, 0x6);
- sst_dsp_shim_write(sst, 0xe0, 0x300a);
-
return 0;
}
@@ -415,11 +443,6 @@ static void hsw_sleep(struct sst_dsp *sst)
{
dev_dbg(sst->dev, "HSW_PM dsp runtime suspend\n");
- /* put DSP into reset and stall */
- sst_dsp_shim_update_bits(sst, SST_CSR,
- SST_CSR_24MHZ_LPCS | SST_CSR_RST | SST_CSR_STALL,
- SST_CSR_RST | SST_CSR_STALL | SST_CSR_24MHZ_LPCS);
-
hsw_set_dsp_D3(sst);
dev_dbg(sst->dev, "HSW_PM dsp runtime suspend exit\n");
}
diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile
index 48544ff1a3e6..dd39149b89b1 100644
--- a/sound/soc/intel/skylake/Makefile
+++ b/sound/soc/intel/skylake/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o skl-topology.o \
skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o skl-sst-cldma.o \
skl-sst.o bxt-sst.o cnl-sst.o skl-sst-utils.o
diff --git a/sound/soc/intel/skylake/skl-i2s.h b/sound/soc/intel/skylake/skl-i2s.h
index d7c15873c0d4..dfce91e11be1 100644
--- a/sound/soc/intel/skylake/skl-i2s.h
+++ b/sound/soc/intel/skylake/skl-i2s.h
@@ -46,7 +46,7 @@ struct skl_i2s_config_mclk {
struct skl_i2s_config_mclk_ext {
u32 mdivctrl;
u32 mdivr_count;
- u32 mdivr[0];
+ u32 mdivr[];
} __packed;
struct skl_i2s_config_blob_signature {
diff --git a/sound/soc/intel/skylake/skl-ssp-clk.c b/sound/soc/intel/skylake/skl-ssp-clk.c
index bd43885f3805..a3a73c26f9aa 100644
--- a/sound/soc/intel/skylake/skl-ssp-clk.c
+++ b/sound/soc/intel/skylake/skl-ssp-clk.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright(c) 2015-17 Intel Corporation
/*
diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c
index d43cbf4a71ef..b233f89517c1 100644
--- a/sound/soc/intel/skylake/skl-sst-utils.c
+++ b/sound/soc/intel/skylake/skl-sst-utils.c
@@ -290,7 +290,7 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw,
goto free_uuid_list;
}
- guid_copy(&module->uuid, (guid_t *)&mod_entry->uuid);
+ import_guid(&module->uuid, mod_entry->uuid);
module->id = (i | (index << 12));
module->is_loadable = mod_entry->type.load_type;
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 69cd7a81bf2a..b9aab47d1202 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -14,6 +14,7 @@
#include <linux/uuid.h>
#include <sound/intel-nhlt.h>
#include <sound/soc.h>
+#include <sound/soc-acpi.h>
#include <sound/soc-topology.h>
#include <uapi/sound/snd_sst_tokens.h>
#include <uapi/sound/skl-tplg-interface.h>
@@ -578,6 +579,38 @@ static int skl_tplg_unload_pipe_modules(struct skl_dev *skl,
return ret;
}
+static bool skl_tplg_is_multi_fmt(struct skl_dev *skl, struct skl_pipe *pipe)
+{
+ struct skl_pipe_fmt *cur_fmt;
+ struct skl_pipe_fmt *next_fmt;
+ int i;
+
+ if (pipe->nr_cfgs <= 1)
+ return false;
+
+ if (pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
+ return true;
+
+ for (i = 0; i < pipe->nr_cfgs - 1; i++) {
+ if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ cur_fmt = &pipe->configs[i].out_fmt;
+ next_fmt = &pipe->configs[i + 1].out_fmt;
+ } else {
+ cur_fmt = &pipe->configs[i].in_fmt;
+ next_fmt = &pipe->configs[i + 1].in_fmt;
+ }
+
+ if (!CHECK_HW_PARAMS(cur_fmt->channels, cur_fmt->freq,
+ cur_fmt->bps,
+ next_fmt->channels,
+ next_fmt->freq,
+ next_fmt->bps))
+ return true;
+ }
+
+ return false;
+}
+
/*
* Here, we select pipe format based on the pipe type and pipe
* direction to determine the current config index for the pipeline.
@@ -600,6 +633,14 @@ skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
return 0;
}
+ if (skl_tplg_is_multi_fmt(skl, pipe)) {
+ pipe->cur_config_idx = pipe->pipe_config_idx;
+ pipe->memory_pages = pconfig->mem_pages;
+ dev_dbg(skl->dev, "found pipe config idx:%d\n",
+ pipe->cur_config_idx);
+ return 0;
+ }
+
if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) {
dev_dbg(skl->dev, "No conn_type detected, take 0th config\n");
pipe->cur_config_idx = 0;
@@ -1314,6 +1355,68 @@ static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol,
+ bool is_set)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct hdac_bus *bus = snd_soc_component_get_drvdata(component);
+ struct skl_dev *skl = bus_to_skl(bus);
+ struct skl_pipeline *ppl;
+ struct skl_pipe *pipe = NULL;
+ struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+ u32 *pipe_id;
+
+ if (!ec)
+ return -EINVAL;
+
+ if (is_set && ucontrol->value.enumerated.item[0] > ec->items)
+ return -EINVAL;
+
+ pipe_id = ec->dobj.private;
+
+ list_for_each_entry(ppl, &skl->ppl_list, node) {
+ if (ppl->pipe->ppl_id == *pipe_id) {
+ pipe = ppl->pipe;
+ break;
+ }
+ }
+ if (!pipe)
+ return -EIO;
+
+ if (is_set)
+ pipe->pipe_config_idx = ucontrol->value.enumerated.item[0];
+ else
+ ucontrol->value.enumerated.item[0] = pipe->pipe_config_idx;
+
+ return 0;
+}
+
+static int skl_tplg_multi_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false);
+}
+
+static int skl_tplg_multi_config_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true);
+}
+
+static int skl_tplg_multi_config_get_dmic(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false);
+}
+
+static int skl_tplg_multi_config_set_dmic(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true);
+}
+
static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
unsigned int __user *data, unsigned int size)
{
@@ -1853,6 +1956,16 @@ static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
.get = skl_tplg_mic_control_get,
.put = skl_tplg_mic_control_set,
},
+ {
+ .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT,
+ .get = skl_tplg_multi_config_get,
+ .put = skl_tplg_multi_config_set,
+ },
+ {
+ .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC,
+ .get = skl_tplg_multi_config_get_dmic,
+ .put = skl_tplg_multi_config_set_dmic,
+ }
};
static int skl_tplg_fill_pipe_cfg(struct device *dev,
@@ -1989,7 +2102,7 @@ static int skl_tplg_get_uuid(struct device *dev, guid_t *guid,
struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
{
if (uuid_tkn->token == SKL_TKN_UUID) {
- guid_copy(guid, (guid_t *)&uuid_tkn->uuid);
+ import_guid(guid, uuid_tkn->uuid);
return 0;
}
@@ -3013,12 +3126,21 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
case SND_SOC_TPLG_CTL_ENUM:
tplg_ec = container_of(hdr,
struct snd_soc_tplg_enum_control, hdr);
- if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READWRITE) {
+ if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READ) {
se = (struct soc_enum *)kctl->private_value;
if (tplg_ec->priv.size)
- return skl_init_enum_data(bus->dev, se,
- tplg_ec);
+ skl_init_enum_data(bus->dev, se, tplg_ec);
}
+
+ /*
+ * now that the control initializations are done, remove
+ * write permission for the DMIC configuration enums to
+ * avoid conflicts between NHLT settings and user interaction
+ */
+
+ if (hdr->ops.get == SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC)
+ kctl->access = SNDRV_CTL_ELEM_ACCESS_READ;
+
break;
default:
@@ -3376,8 +3498,8 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
dev_err(dev, "Too many UUID tokens\n");
return -EINVAL;
}
- guid_copy(&skl->modules[uuid_index++]->uuid,
- (guid_t *)&array->uuid->uuid);
+ import_guid(&skl->modules[uuid_index++]->uuid,
+ array->uuid->uuid);
tuple_size += sizeof(*array->uuid);
continue;
@@ -3488,6 +3610,37 @@ static int skl_manifest_load(struct snd_soc_component *cmpnt, int index,
return 0;
}
+static void skl_tplg_complete(struct snd_soc_component *component)
+{
+ struct snd_soc_dobj *dobj;
+ struct snd_soc_acpi_mach *mach =
+ dev_get_platdata(component->card->dev);
+ int i;
+
+ list_for_each_entry(dobj, &component->dobj_list, list) {
+ struct snd_kcontrol *kcontrol = dobj->control.kcontrol;
+ struct soc_enum *se =
+ (struct soc_enum *)kcontrol->private_value;
+ char **texts = dobj->control.dtexts;
+ char chan_text[4];
+
+ if (dobj->type != SND_SOC_DOBJ_ENUM ||
+ dobj->control.kcontrol->put !=
+ skl_tplg_multi_config_set_dmic)
+ continue;
+ sprintf(chan_text, "c%d", mach->mach_params.dmic_num);
+
+ for (i = 0; i < se->items; i++) {
+ struct snd_ctl_elem_value val;
+
+ if (strstr(texts[i], chan_text)) {
+ val.value.enumerated.item[0] = i;
+ kcontrol->put(kcontrol, &val);
+ }
+ }
+ }
+}
+
static struct snd_soc_tplg_ops skl_tplg_ops = {
.widget_load = skl_tplg_widget_load,
.control_load = skl_tplg_control_load,
@@ -3497,6 +3650,7 @@ static struct snd_soc_tplg_ops skl_tplg_ops = {
.io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops),
.manifest = skl_manifest_load,
.dai_load = skl_dai_load,
+ .complete = skl_tplg_complete,
};
/*
@@ -3565,8 +3719,20 @@ int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
ret = request_firmware(&fw, skl->tplg_name, bus->dev);
if (ret < 0) {
- dev_info(bus->dev, "tplg fw %s load failed with %d, falling back to dfw_sst.bin",
- skl->tplg_name, ret);
+ char alt_tplg_name[64];
+
+ snprintf(alt_tplg_name, sizeof(alt_tplg_name), "%s-tplg.bin",
+ skl->mach->drv_name);
+ dev_info(bus->dev, "tplg fw %s load failed with %d, trying alternative tplg name %s",
+ skl->tplg_name, ret, alt_tplg_name);
+
+ ret = request_firmware(&fw, alt_tplg_name, bus->dev);
+ if (!ret)
+ goto component_load;
+
+ dev_info(bus->dev, "tplg %s failed with %d, falling back to dfw_sst.bin",
+ alt_tplg_name, ret);
+
ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
if (ret < 0) {
dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n",
@@ -3575,6 +3741,8 @@ int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
}
}
+component_load:
+
/*
* The complete tplg for SKL is loaded as index 0, we don't use
* any other index
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index e967800dbb62..9889f728752c 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -119,7 +119,7 @@ struct skl_cpr_gtw_cfg {
struct skl_dma_control {
u32 node_id;
u32 config_length;
- u32 config_data[0];
+ u32 config_data[];
} __packed;
struct skl_cpr_cfg {
@@ -152,7 +152,7 @@ struct skl_up_down_mixer_cfg {
struct skl_algo_cfg {
struct skl_base_cfg base_cfg;
- char params[0];
+ char params[];
} __packed;
struct skl_base_outfmt_cfg {
@@ -306,6 +306,7 @@ struct skl_pipe {
struct skl_path_config configs[SKL_MAX_PATH_CONFIGS];
struct list_head w_list;
bool passthru;
+ u32 pipe_config_idx;
};
enum skl_module_state {
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index 2bfbf59277c4..26057f38a014 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -49,7 +49,7 @@ struct skl_astate_param {
struct skl_astate_config {
u32 count;
- struct skl_astate_param astate_table[0];
+ struct skl_astate_param astate_table[];
};
struct skl_fw_config {
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
index 7f930556d961..7f3ac04b9425 100644
--- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
@@ -807,10 +807,9 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
/* request irq */
irq_id = platform_get_irq(pdev, 0);
- if (!irq_id) {
- dev_err(dev, "%pOFn no irq found\n", dev->of_node);
- return -ENXIO;
- }
+ if (irq_id < 0)
+ return irq_id;
+
ret = devm_request_irq(dev, irq_id, mt6797_afe_irq_handler,
IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
if (ret) {
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
index 5b3dfa79b4ae..ffd7c931e7bb 100644
--- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
@@ -6,11 +6,12 @@
// Copyright (c) 2018 MediaTek Inc.
// Author: Shunli Wang <[email protected]>
+#include <linux/input.h>
#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
+#include <sound/jack.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <sound/jack.h>
-#include <linux/pinctrl/consumer.h>
#include "mt8183-afe-common.h"
#include "../../codecs/da7219-aad.h"
@@ -471,9 +472,18 @@ mt8183_da7219_max98357_headset_init(struct snd_soc_component *component)
if (ret)
return ret;
+ snd_jack_set_key(
+ priv->headset_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(
+ priv->headset_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+ snd_jack_set_key(
+ priv->headset_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+ snd_jack_set_key(
+ priv->headset_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+
da7219_aad_jack_det(component, &priv->headset_jack);
- return ret;
+ return 0;
}
static int mt8183_da7219_max98357_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index 1e38ce858326..07f8cf9980e3 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -733,12 +733,9 @@ static int mxs_saif_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct mxs_saif *saif;
- int irq, ret = 0;
+ int irq, ret;
struct device_node *master;
- if (!np)
- return -EINVAL;
-
saif = devm_kzalloc(&pdev->dev, sizeof(*saif), GFP_KERNEL);
if (!saif)
return -ENOMEM;
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c
index 90a9bc81be80..86277471974a 100644
--- a/sound/soc/pxa/mmp-sspa.c
+++ b/sound/soc/pxa/mmp-sspa.c
@@ -11,9 +11,9 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/slab.h>
-#include <linux/pxa2xx_ssp.h>
#include <linux/io.h>
#include <linux/dmaengine.h>
+#include <linux/pm_runtime.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -28,59 +28,60 @@
* SSPA audio private data
*/
struct sspa_priv {
- struct ssp_device *sspa;
- struct snd_dmaengine_dai_dma_data *dma_params;
+ void __iomem *mmio_base;
+ struct snd_dmaengine_dai_dma_data playback_dma_data;
+ struct snd_dmaengine_dai_dma_data capture_dma_data;
+ struct clk *clk;
struct clk *audio_clk;
struct clk *sysclk;
- int dai_fmt;
int running_cnt;
+ u32 sp;
+ u32 ctrl;
};
-static void mmp_sspa_write_reg(struct ssp_device *sspa, u32 reg, u32 val)
+static void mmp_sspa_write_reg(struct sspa_priv *sspa, u32 reg, u32 val)
{
__raw_writel(val, sspa->mmio_base + reg);
}
-static u32 mmp_sspa_read_reg(struct ssp_device *sspa, u32 reg)
+static u32 mmp_sspa_read_reg(struct sspa_priv *sspa, u32 reg)
{
return __raw_readl(sspa->mmio_base + reg);
}
-static void mmp_sspa_tx_enable(struct ssp_device *sspa)
+static void mmp_sspa_tx_enable(struct sspa_priv *sspa)
{
- unsigned int sspa_sp;
+ unsigned int sspa_sp = sspa->sp;
- sspa_sp = mmp_sspa_read_reg(sspa, SSPA_TXSP);
+ sspa_sp &= ~SSPA_SP_MSL;
sspa_sp |= SSPA_SP_S_EN;
sspa_sp |= SSPA_SP_WEN;
mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
}
-static void mmp_sspa_tx_disable(struct ssp_device *sspa)
+static void mmp_sspa_tx_disable(struct sspa_priv *sspa)
{
- unsigned int sspa_sp;
+ unsigned int sspa_sp = sspa->sp;
- sspa_sp = mmp_sspa_read_reg(sspa, SSPA_TXSP);
+ sspa_sp &= ~SSPA_SP_MSL;
sspa_sp &= ~SSPA_SP_S_EN;
sspa_sp |= SSPA_SP_WEN;
mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
}
-static void mmp_sspa_rx_enable(struct ssp_device *sspa)
+static void mmp_sspa_rx_enable(struct sspa_priv *sspa)
{
- unsigned int sspa_sp;
+ unsigned int sspa_sp = sspa->sp;
- sspa_sp = mmp_sspa_read_reg(sspa, SSPA_RXSP);
sspa_sp |= SSPA_SP_S_EN;
sspa_sp |= SSPA_SP_WEN;
mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
}
-static void mmp_sspa_rx_disable(struct ssp_device *sspa)
+static void mmp_sspa_rx_disable(struct sspa_priv *sspa)
{
- unsigned int sspa_sp;
+ unsigned int sspa_sp = sspa->sp;
- sspa_sp = mmp_sspa_read_reg(sspa, SSPA_RXSP);
sspa_sp &= ~SSPA_SP_S_EN;
sspa_sp |= SSPA_SP_WEN;
mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
@@ -89,10 +90,10 @@ static void mmp_sspa_rx_disable(struct ssp_device *sspa)
static int mmp_sspa_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct sspa_priv *priv = snd_soc_dai_get_drvdata(dai);
+ struct sspa_priv *sspa = snd_soc_dai_get_drvdata(dai);
- clk_enable(priv->sysclk);
- clk_enable(priv->sspa->clk);
+ clk_prepare_enable(sspa->sysclk);
+ clk_prepare_enable(sspa->clk);
return 0;
}
@@ -100,10 +101,10 @@ static int mmp_sspa_startup(struct snd_pcm_substream *substream,
static void mmp_sspa_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct sspa_priv *priv = snd_soc_dai_get_drvdata(dai);
+ struct sspa_priv *sspa = snd_soc_dai_get_drvdata(dai);
- clk_disable(priv->sspa->clk);
- clk_disable(priv->sysclk);
+ clk_disable_unprepare(sspa->clk);
+ clk_disable_unprepare(sspa->sysclk);
}
@@ -113,12 +114,12 @@ static void mmp_sspa_shutdown(struct snd_pcm_substream *substream,
static int mmp_sspa_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
- struct sspa_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+ struct sspa_priv *sspa = snd_soc_dai_get_drvdata(cpu_dai);
int ret = 0;
switch (clk_id) {
case MMP_SSPA_CLK_AUDIO:
- ret = clk_set_rate(priv->audio_clk, freq);
+ ret = clk_set_rate(sspa->audio_clk, freq);
if (ret)
return ret;
break;
@@ -137,17 +138,17 @@ static int mmp_sspa_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
int source, unsigned int freq_in,
unsigned int freq_out)
{
- struct sspa_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+ struct sspa_priv *sspa = snd_soc_dai_get_drvdata(cpu_dai);
int ret = 0;
switch (pll_id) {
case MMP_SYSCLK:
- ret = clk_set_rate(priv->sysclk, freq_out);
+ ret = clk_set_rate(sspa->sysclk, freq_out);
if (ret)
return ret;
break;
case MMP_SSPA_CLK:
- ret = clk_set_rate(priv->sspa->clk, freq_out);
+ ret = clk_set_rate(sspa->clk, freq_out);
if (ret)
return ret;
break;
@@ -159,36 +160,20 @@ static int mmp_sspa_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
}
/*
- * Set up the sspa dai format. The sspa port must be inactive
- * before calling this function as the physical
- * interface format is changed.
+ * Set up the sspa dai format.
*/
static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(cpu_dai);
- struct ssp_device *sspa = sspa_priv->sspa;
- u32 sspa_sp, sspa_ctrl;
-
- /* check if we need to change anything at all */
- if (sspa_priv->dai_fmt == fmt)
- return 0;
-
- /* we can only change the settings if the port is not in use */
- if ((mmp_sspa_read_reg(sspa, SSPA_TXSP) & SSPA_SP_S_EN) ||
- (mmp_sspa_read_reg(sspa, SSPA_RXSP) & SSPA_SP_S_EN)) {
- dev_err(sspa->dev,
- "can't change hardware dai format: stream is in use\n");
- return -EINVAL;
- }
+ struct sspa_priv *sspa = snd_soc_dai_get_drvdata(cpu_dai);
/* reset port settings */
- sspa_sp = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH;
- sspa_ctrl = 0;
+ sspa->sp = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH;
+ sspa->ctrl = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
- sspa_sp |= SSPA_SP_MSL;
+ sspa->sp |= SSPA_SP_MSL;
break;
case SND_SOC_DAIFMT_CBM_CFM:
break;
@@ -198,7 +183,7 @@ static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai,
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
- sspa_sp |= SSPA_SP_FSP;
+ sspa->sp |= SSPA_SP_FSP;
break;
default:
return -EINVAL;
@@ -206,39 +191,16 @@ static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai,
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
- sspa_sp |= SSPA_TXSP_FPER(63);
- sspa_sp |= SSPA_SP_FWID(31);
- sspa_ctrl |= SSPA_CTL_XDATDLY(1);
+ sspa->ctrl |= SSPA_CTL_XDATDLY(1);
break;
default:
return -EINVAL;
}
- mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
- mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
-
- sspa_sp &= ~(SSPA_SP_S_RST | SSPA_SP_FFLUSH);
- mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
- mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
-
- /*
- * FIXME: hw issue, for the tx serial port,
- * can not config the master/slave mode;
- * so must clean this bit.
- * The master/slave mode has been set in the
- * rx port.
- */
- sspa_sp &= ~SSPA_SP_MSL;
- mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
-
- mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl);
- mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl);
-
/* Since we are configuring the timings for the format by hand
* we have to defer some things until hw_params() where we
* know parameters like the sample size.
*/
- sspa_priv->dai_fmt = fmt;
return 0;
}
@@ -250,41 +212,50 @@ static int mmp_sspa_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai);
- struct ssp_device *sspa = sspa_priv->sspa;
- struct snd_dmaengine_dai_dma_data *dma_params;
- u32 sspa_ctrl;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- sspa_ctrl = mmp_sspa_read_reg(sspa, SSPA_TXCTL);
- else
- sspa_ctrl = mmp_sspa_read_reg(sspa, SSPA_RXCTL);
-
- sspa_ctrl &= ~SSPA_CTL_XFRLEN1_MASK;
- sspa_ctrl |= SSPA_CTL_XFRLEN1(params_channels(params) - 1);
- sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK;
- sspa_ctrl |= SSPA_CTL_XWDLEN1(SSPA_CTL_32_BITS);
- sspa_ctrl &= ~SSPA_CTL_XSSZ1_MASK;
+ struct sspa_priv *sspa = snd_soc_dai_get_drvdata(dai);
+ u32 sspa_ctrl = sspa->ctrl;
+ int bits;
+ int bitval;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
- sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_8_BITS);
+ bits = 8;
+ bitval = SSPA_CTL_8_BITS;
break;
case SNDRV_PCM_FORMAT_S16_LE:
- sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_16_BITS);
+ bits = 16;
+ bitval = SSPA_CTL_16_BITS;
break;
case SNDRV_PCM_FORMAT_S24_3LE:
- sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_24_BITS);
+ bits = 24;
+ bitval = SSPA_CTL_24_BITS;
break;
case SNDRV_PCM_FORMAT_S32_LE:
- sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_32_BITS);
+ bits = 32;
+ bitval = SSPA_CTL_32_BITS;
break;
default:
return -EINVAL;
}
+ if (params_channels(params) == 2)
+ sspa_ctrl |= SSPA_CTL_XPH;
+
+ sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK;
+ sspa_ctrl |= SSPA_CTL_XWDLEN1(bitval);
+
+ sspa_ctrl &= ~SSPA_CTL_XSSZ1_MASK;
+ sspa_ctrl |= SSPA_CTL_XSSZ1(bitval);
+
+ sspa_ctrl &= ~SSPA_CTL_XSSZ2_MASK;
+ sspa_ctrl |= SSPA_CTL_XSSZ2(bitval);
+
+ sspa->sp &= ~SSPA_SP_FWID_MASK;
+ sspa->sp |= SSPA_SP_FWID(bits - 1);
+
+ sspa->sp &= ~SSPA_TXSP_FPER_MASK;
+ sspa->sp |= SSPA_TXSP_FPER(bits * 2 - 1);
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl);
mmp_sspa_write_reg(sspa, SSPA_TXFIFO_LL, 0x1);
@@ -293,19 +264,13 @@ static int mmp_sspa_hw_params(struct snd_pcm_substream *substream,
mmp_sspa_write_reg(sspa, SSPA_RXFIFO_UL, 0x0);
}
- dma_params = &sspa_priv->dma_params[substream->stream];
- dma_params->addr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
- (sspa->phys_base + SSPA_TXD) :
- (sspa->phys_base + SSPA_RXD);
- snd_soc_dai_set_dma_data(cpu_dai, substream, dma_params);
return 0;
}
static int mmp_sspa_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai);
- struct ssp_device *sspa = sspa_priv->sspa;
+ struct sspa_priv *sspa = snd_soc_dai_get_drvdata(dai);
int ret = 0;
switch (cmd) {
@@ -318,25 +283,25 @@ static int mmp_sspa_trigger(struct snd_pcm_substream *substream, int cmd,
* enabled or not; if has been enabled by another
* stream, do not enable again.
*/
- if (!sspa_priv->running_cnt)
+ if (!sspa->running_cnt)
mmp_sspa_rx_enable(sspa);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
mmp_sspa_tx_enable(sspa);
- sspa_priv->running_cnt++;
+ sspa->running_cnt++;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- sspa_priv->running_cnt--;
+ sspa->running_cnt--;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
mmp_sspa_tx_disable(sspa);
/* have no capture stream, disable rx port */
- if (!sspa_priv->running_cnt)
+ if (!sspa->running_cnt)
mmp_sspa_rx_disable(sspa);
break;
@@ -349,11 +314,14 @@ static int mmp_sspa_trigger(struct snd_pcm_substream *substream, int cmd,
static int mmp_sspa_probe(struct snd_soc_dai *dai)
{
- struct sspa_priv *priv = dev_get_drvdata(dai->dev);
+ struct sspa_priv *sspa = dev_get_drvdata(dai->dev);
- snd_soc_dai_set_drvdata(dai, priv);
- return 0;
+ snd_soc_dai_init_dma_data(dai,
+ &sspa->playback_dma_data,
+ &sspa->capture_dma_data);
+ snd_soc_dai_set_drvdata(dai, sspa);
+ return 0;
}
#define MMP_SSPA_RATES SNDRV_PCM_RATE_8000_192000
@@ -389,50 +357,146 @@ static struct snd_soc_dai_driver mmp_sspa_dai = {
.ops = &mmp_sspa_dai_ops,
};
+#define MMP_PCM_INFO (SNDRV_PCM_INFO_MMAP | \
+ SNDRV_PCM_INFO_MMAP_VALID | \
+ SNDRV_PCM_INFO_INTERLEAVED | \
+ SNDRV_PCM_INFO_PAUSE | \
+ SNDRV_PCM_INFO_RESUME | \
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP)
+
+static const struct snd_pcm_hardware mmp_pcm_hardware[] = {
+ {
+ .info = MMP_PCM_INFO,
+ .period_bytes_min = 1024,
+ .period_bytes_max = 2048,
+ .periods_min = 2,
+ .periods_max = 32,
+ .buffer_bytes_max = 4096,
+ .fifo_size = 32,
+ },
+ {
+ .info = MMP_PCM_INFO,
+ .period_bytes_min = 1024,
+ .period_bytes_max = 2048,
+ .periods_min = 2,
+ .periods_max = 32,
+ .buffer_bytes_max = 4096,
+ .fifo_size = 32,
+ },
+};
+
+static const struct snd_dmaengine_pcm_config mmp_pcm_config = {
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+ .pcm_hardware = mmp_pcm_hardware,
+ .prealloc_buffer_size = 4096,
+};
+
+static int mmp_pcm_mmap(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ return remap_pfn_range(vma, vma->vm_start,
+ substream->dma_buffer.addr >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+static int mmp_sspa_open(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct sspa_priv *sspa = snd_soc_component_get_drvdata(component);
+
+ pm_runtime_get_sync(component->dev);
+
+ /* we can only change the settings if the port is not in use */
+ if ((mmp_sspa_read_reg(sspa, SSPA_TXSP) & SSPA_SP_S_EN) ||
+ (mmp_sspa_read_reg(sspa, SSPA_RXSP) & SSPA_SP_S_EN)) {
+ dev_err(component->dev,
+ "can't change hardware dai format: stream is in use\n");
+ return -EBUSY;
+ }
+
+ mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa->sp);
+ mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa->sp);
+
+ sspa->sp &= ~(SSPA_SP_S_RST | SSPA_SP_FFLUSH);
+ mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa->sp);
+ mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa->sp);
+
+ /*
+ * FIXME: hw issue, for the tx serial port,
+ * can not config the master/slave mode;
+ * so must clean this bit.
+ * The master/slave mode has been set in the
+ * rx port.
+ */
+ mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa->sp & ~SSPA_SP_MSL);
+
+ mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa->ctrl);
+ mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa->ctrl);
+
+ return 0;
+}
+
+static int mmp_sspa_close(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ pm_runtime_put_sync(component->dev);
+ return 0;
+}
+
static const struct snd_soc_component_driver mmp_sspa_component = {
.name = "mmp-sspa",
+ .mmap = mmp_pcm_mmap,
+ .open = mmp_sspa_open,
+ .close = mmp_sspa_close,
};
static int asoc_mmp_sspa_probe(struct platform_device *pdev)
{
- struct sspa_priv *priv;
+ struct sspa_priv *sspa;
- priv = devm_kzalloc(&pdev->dev,
+ sspa = devm_kzalloc(&pdev->dev,
sizeof(struct sspa_priv), GFP_KERNEL);
- if (!priv)
+ if (!sspa)
return -ENOMEM;
- priv->sspa = devm_kzalloc(&pdev->dev,
- sizeof(struct ssp_device), GFP_KERNEL);
- if (priv->sspa == NULL)
- return -ENOMEM;
+ sspa->mmio_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(sspa->mmio_base))
+ return PTR_ERR(sspa->mmio_base);
- priv->dma_params = devm_kcalloc(&pdev->dev,
- 2, sizeof(struct snd_dmaengine_dai_dma_data),
- GFP_KERNEL);
- if (priv->dma_params == NULL)
- return -ENOMEM;
+ sspa->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(sspa->clk))
+ return PTR_ERR(sspa->clk);
+
+ sspa->audio_clk = clk_get(NULL, "mmp-audio");
+ if (IS_ERR(sspa->audio_clk))
+ return PTR_ERR(sspa->audio_clk);
- priv->sspa->mmio_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(priv->sspa->mmio_base))
- return PTR_ERR(priv->sspa->mmio_base);
+ sspa->sysclk = clk_get(NULL, "mmp-sysclk");
+ if (IS_ERR(sspa->sysclk)) {
+ clk_put(sspa->audio_clk);
+ return PTR_ERR(sspa->sysclk);
+ }
+ pm_runtime_enable(&pdev->dev);
+ clk_prepare_enable(sspa->audio_clk);
+ platform_set_drvdata(pdev, sspa);
- priv->sspa->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(priv->sspa->clk))
- return PTR_ERR(priv->sspa->clk);
+ sspa->playback_dma_data.maxburst = 4;
+ sspa->capture_dma_data.maxburst = 4;
+ /* You know, these addresses are actually ignored. */
+ sspa->playback_dma_data.addr = SSPA_TXD;
+ sspa->capture_dma_data.addr = SSPA_RXD;
- priv->audio_clk = clk_get(NULL, "mmp-audio");
- if (IS_ERR(priv->audio_clk))
- return PTR_ERR(priv->audio_clk);
+ if (pdev->dev.of_node) {
+ int ret;
- priv->sysclk = clk_get(NULL, "mmp-sysclk");
- if (IS_ERR(priv->sysclk)) {
- clk_put(priv->audio_clk);
- return PTR_ERR(priv->sysclk);
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
+ &mmp_pcm_config, 0);
+ if (ret)
+ return ret;
}
- clk_enable(priv->audio_clk);
- priv->dai_fmt = (unsigned int) -1;
- platform_set_drvdata(pdev, priv);
return devm_snd_soc_register_component(&pdev->dev, &mmp_sspa_component,
&mmp_sspa_dai, 1);
@@ -440,11 +504,12 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev)
static int asoc_mmp_sspa_remove(struct platform_device *pdev)
{
- struct sspa_priv *priv = platform_get_drvdata(pdev);
+ struct sspa_priv *sspa = platform_get_drvdata(pdev);
- clk_disable(priv->audio_clk);
- clk_put(priv->audio_clk);
- clk_put(priv->sysclk);
+ clk_disable_unprepare(sspa->audio_clk);
+ pm_runtime_disable(&pdev->dev);
+ clk_put(sspa->audio_clk);
+ clk_put(sspa->sysclk);
return 0;
}
diff --git a/sound/soc/pxa/mmp-sspa.h b/sound/soc/pxa/mmp-sspa.h
index 7d1b7c7325df..328969b57ad1 100644
--- a/sound/soc/pxa/mmp-sspa.h
+++ b/sound/soc/pxa/mmp-sspa.h
@@ -38,7 +38,7 @@
#define SSPA_CTL_XFRLEN2(x) ((x) << 24) /* Transmit Frame Length in Phase 2 */
#define SSPA_CTL_XWDLEN2_MASK (7 << 21)
#define SSPA_CTL_XWDLEN2(x) ((x) << 21) /* Transmit Word Length in Phase 2 */
-#define SSPA_CTL_XDATDLY(x) ((x) << 19) /* Tansmit Data Delay */
+#define SSPA_CTL_XDATDLY(x) ((x) << 19) /* Transmit Data Delay */
#define SSPA_CTL_XSSZ2_MASK (7 << 16)
#define SSPA_CTL_XSSZ2(x) ((x) << 16) /* Transmit Sample Audio Size */
#define SSPA_CTL_XFRLEN1_MASK (7 << 8)
@@ -63,7 +63,9 @@
#define SSPA_SP_FFLUSH (1 << 2) /* FIFO Flush */
#define SSPA_SP_S_RST (1 << 1) /* Active High Reset Signal */
#define SSPA_SP_S_EN (1 << 0) /* Serial Clock Domain Enable */
+#define SSPA_SP_FWID_MASK (0x3f << 20)
#define SSPA_SP_FWID(x) ((x) << 20) /* Frame-Sync Width */
+#define SSPA_TXSP_FPER_MASK (0x3f << 4)
#define SSPA_TXSP_FPER(x) ((x) << 4) /* Frame-Sync Active */
/* sspa clock sources */
diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c
index 6575da549237..b3610d05b651 100644
--- a/sound/soc/qcom/lpass-apq8016.c
+++ b/sound/soc/qcom/lpass-apq8016.c
@@ -166,28 +166,27 @@ static int apq8016_lpass_init(struct platform_device *pdev)
drvdata->pcnoc_mport_clk = devm_clk_get(dev, "pcnoc-mport-clk");
if (IS_ERR(drvdata->pcnoc_mport_clk)) {
- dev_err(&pdev->dev, "error getting pcnoc-mport-clk: %ld\n",
+ dev_err(dev, "error getting pcnoc-mport-clk: %ld\n",
PTR_ERR(drvdata->pcnoc_mport_clk));
return PTR_ERR(drvdata->pcnoc_mport_clk);
}
ret = clk_prepare_enable(drvdata->pcnoc_mport_clk);
if (ret) {
- dev_err(&pdev->dev, "Error enabling pcnoc-mport-clk: %d\n",
- ret);
+ dev_err(dev, "Error enabling pcnoc-mport-clk: %d\n", ret);
return ret;
}
drvdata->pcnoc_sway_clk = devm_clk_get(dev, "pcnoc-sway-clk");
if (IS_ERR(drvdata->pcnoc_sway_clk)) {
- dev_err(&pdev->dev, "error getting pcnoc-sway-clk: %ld\n",
+ dev_err(dev, "error getting pcnoc-sway-clk: %ld\n",
PTR_ERR(drvdata->pcnoc_sway_clk));
return PTR_ERR(drvdata->pcnoc_sway_clk);
}
ret = clk_prepare_enable(drvdata->pcnoc_sway_clk);
if (ret) {
- dev_err(&pdev->dev, "Error enabling pcnoc_sway_clk: %d\n", ret);
+ dev_err(dev, "Error enabling pcnoc_sway_clk: %d\n", ret);
return ret;
}
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index dbce7e92baf3..e00a4af29c13 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -19,6 +19,16 @@
#include "lpass-lpaif-reg.h"
#include "lpass.h"
+#define LPASS_CPU_MAX_MI2S_LINES 4
+#define LPASS_CPU_I2S_SD0_MASK BIT(0)
+#define LPASS_CPU_I2S_SD1_MASK BIT(1)
+#define LPASS_CPU_I2S_SD2_MASK BIT(2)
+#define LPASS_CPU_I2S_SD3_MASK BIT(3)
+#define LPASS_CPU_I2S_SD0_1_MASK GENMASK(1, 0)
+#define LPASS_CPU_I2S_SD2_3_MASK GENMASK(3, 2)
+#define LPASS_CPU_I2S_SD0_1_2_MASK GENMASK(2, 0)
+#define LPASS_CPU_I2S_SD0_1_2_3_MASK GENMASK(3, 0)
+
static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
@@ -72,6 +82,7 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
snd_pcm_format_t format = params_format(params);
unsigned int channels = params_channels(params);
unsigned int rate = params_rate(params);
+ unsigned int mode;
unsigned int regval;
int bitwidth, ret;
@@ -99,60 +110,84 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- switch (channels) {
- case 1:
- regval |= LPAIF_I2SCTL_SPKMODE_SD0;
- regval |= LPAIF_I2SCTL_SPKMONO_MONO;
- break;
- case 2:
- regval |= LPAIF_I2SCTL_SPKMODE_SD0;
- regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
- break;
- case 4:
- regval |= LPAIF_I2SCTL_SPKMODE_QUAD01;
- regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
- break;
- case 6:
- regval |= LPAIF_I2SCTL_SPKMODE_6CH;
- regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ mode = drvdata->mi2s_playback_sd_mode[dai->driver->id];
+ else
+ mode = drvdata->mi2s_capture_sd_mode[dai->driver->id];
+
+ if (!mode) {
+ dev_err(dai->dev, "no line is assigned\n");
+ return -EINVAL;
+ }
+
+ switch (channels) {
+ case 1:
+ case 2:
+ switch (mode) {
+ case LPAIF_I2SCTL_MODE_QUAD01:
+ case LPAIF_I2SCTL_MODE_6CH:
+ case LPAIF_I2SCTL_MODE_8CH:
+ mode = LPAIF_I2SCTL_MODE_SD0;
break;
- case 8:
- regval |= LPAIF_I2SCTL_SPKMODE_8CH;
- regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
+ case LPAIF_I2SCTL_MODE_QUAD23:
+ mode = LPAIF_I2SCTL_MODE_SD2;
break;
- default:
- dev_err(dai->dev, "invalid channels given: %u\n",
- channels);
+ }
+
+ break;
+ case 4:
+ if (mode < LPAIF_I2SCTL_MODE_QUAD01) {
+ dev_err(dai->dev, "cannot configure 4 channels with mode %d\n",
+ mode);
return -EINVAL;
}
- } else {
- switch (channels) {
- case 1:
- regval |= LPAIF_I2SCTL_MICMODE_SD0;
- regval |= LPAIF_I2SCTL_MICMONO_MONO;
- break;
- case 2:
- regval |= LPAIF_I2SCTL_MICMODE_SD0;
- regval |= LPAIF_I2SCTL_MICMONO_STEREO;
- break;
- case 4:
- regval |= LPAIF_I2SCTL_MICMODE_QUAD01;
- regval |= LPAIF_I2SCTL_MICMONO_STEREO;
- break;
- case 6:
- regval |= LPAIF_I2SCTL_MICMODE_6CH;
- regval |= LPAIF_I2SCTL_MICMONO_STEREO;
+
+ switch (mode) {
+ case LPAIF_I2SCTL_MODE_6CH:
+ case LPAIF_I2SCTL_MODE_8CH:
+ mode = LPAIF_I2SCTL_MODE_QUAD01;
break;
- case 8:
- regval |= LPAIF_I2SCTL_MICMODE_8CH;
- regval |= LPAIF_I2SCTL_MICMONO_STEREO;
+ }
+ break;
+ case 6:
+ if (mode < LPAIF_I2SCTL_MODE_6CH) {
+ dev_err(dai->dev, "cannot configure 6 channels with mode %d\n",
+ mode);
+ return -EINVAL;
+ }
+
+ switch (mode) {
+ case LPAIF_I2SCTL_MODE_8CH:
+ mode = LPAIF_I2SCTL_MODE_6CH;
break;
- default:
- dev_err(dai->dev, "invalid channels given: %u\n",
- channels);
+ }
+ break;
+ case 8:
+ if (mode < LPAIF_I2SCTL_MODE_8CH) {
+ dev_err(dai->dev, "cannot configure 8 channels with mode %d\n",
+ mode);
return -EINVAL;
}
+ break;
+ default:
+ dev_err(dai->dev, "invalid channels given: %u\n", channels);
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ regval |= LPAIF_I2SCTL_SPKMODE(mode);
+
+ if (channels >= 2)
+ regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
+ else
+ regval |= LPAIF_I2SCTL_SPKMONO_MONO;
+ } else {
+ regval |= LPAIF_I2SCTL_MICMODE(mode);
+
+ if (channels >= 2)
+ regval |= LPAIF_I2SCTL_MICMONO_STEREO;
+ else
+ regval |= LPAIF_I2SCTL_MICMONO_MONO;
}
ret = regmap_write(drvdata->lpaif_map,
@@ -413,6 +448,73 @@ static struct regmap_config lpass_cpu_regmap_config = {
.cache_type = REGCACHE_FLAT,
};
+static unsigned int of_lpass_cpu_parse_sd_lines(struct device *dev,
+ struct device_node *node,
+ const char *name)
+{
+ unsigned int lines[LPASS_CPU_MAX_MI2S_LINES];
+ unsigned int sd_line_mask = 0;
+ int num_lines, i;
+
+ num_lines = of_property_read_variable_u32_array(node, name, lines, 0,
+ LPASS_CPU_MAX_MI2S_LINES);
+ if (num_lines < 0)
+ return LPAIF_I2SCTL_MODE_NONE;
+
+ for (i = 0; i < num_lines; i++)
+ sd_line_mask |= BIT(lines[i]);
+
+ switch (sd_line_mask) {
+ case LPASS_CPU_I2S_SD0_MASK:
+ return LPAIF_I2SCTL_MODE_SD0;
+ case LPASS_CPU_I2S_SD1_MASK:
+ return LPAIF_I2SCTL_MODE_SD1;
+ case LPASS_CPU_I2S_SD2_MASK:
+ return LPAIF_I2SCTL_MODE_SD2;
+ case LPASS_CPU_I2S_SD3_MASK:
+ return LPAIF_I2SCTL_MODE_SD3;
+ case LPASS_CPU_I2S_SD0_1_MASK:
+ return LPAIF_I2SCTL_MODE_QUAD01;
+ case LPASS_CPU_I2S_SD2_3_MASK:
+ return LPAIF_I2SCTL_MODE_QUAD23;
+ case LPASS_CPU_I2S_SD0_1_2_MASK:
+ return LPAIF_I2SCTL_MODE_6CH;
+ case LPASS_CPU_I2S_SD0_1_2_3_MASK:
+ return LPAIF_I2SCTL_MODE_8CH;
+ default:
+ dev_err(dev, "Unsupported SD line mask: %#x\n", sd_line_mask);
+ return LPAIF_I2SCTL_MODE_NONE;
+ }
+}
+
+static void of_lpass_cpu_parse_dai_data(struct device *dev,
+ struct lpass_data *data)
+{
+ struct device_node *node;
+ int ret, id;
+
+ /* Allow all channels by default for backwards compatibility */
+ for (id = 0; id < data->variant->num_dai; id++) {
+ data->mi2s_playback_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
+ data->mi2s_capture_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
+ }
+
+ for_each_child_of_node(dev->of_node, node) {
+ ret = of_property_read_u32(node, "reg", &id);
+ if (ret || id < 0 || id >= data->variant->num_dai) {
+ dev_err(dev, "valid dai id not found: %d\n", ret);
+ continue;
+ }
+
+ data->mi2s_playback_sd_mode[id] =
+ of_lpass_cpu_parse_sd_lines(dev, node,
+ "qcom,playback-sd-lines");
+ data->mi2s_capture_sd_mode[id] =
+ of_lpass_cpu_parse_sd_lines(dev, node,
+ "qcom,capture-sd-lines");
+ }
+}
+
int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
{
struct lpass_data *drvdata;
@@ -425,12 +527,11 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
if (dsp_of_node) {
- dev_err(&pdev->dev, "DSP exists and holds audio resources\n");
+ dev_err(dev, "DSP exists and holds audio resources\n");
return -EBUSY;
}
- drvdata = devm_kzalloc(&pdev->dev, sizeof(struct lpass_data),
- GFP_KERNEL);
+ drvdata = devm_kzalloc(dev, sizeof(struct lpass_data), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
platform_set_drvdata(pdev, drvdata);
@@ -442,11 +543,13 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
drvdata->variant = (struct lpass_variant *)match->data;
variant = drvdata->variant;
+ of_lpass_cpu_parse_dai_data(dev, drvdata);
+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif");
- drvdata->lpaif = devm_ioremap_resource(&pdev->dev, res);
+ drvdata->lpaif = devm_ioremap_resource(dev, res);
if (IS_ERR((void const __force *)drvdata->lpaif)) {
- dev_err(&pdev->dev, "error mapping reg resource: %ld\n",
+ dev_err(dev, "error mapping reg resource: %ld\n",
PTR_ERR((void const __force *)drvdata->lpaif));
return PTR_ERR((void const __force *)drvdata->lpaif);
}
@@ -455,10 +558,10 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
variant->wrdma_channels +
variant->wrdma_channel_start);
- drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif,
+ drvdata->lpaif_map = devm_regmap_init_mmio(dev, drvdata->lpaif,
&lpass_cpu_regmap_config);
if (IS_ERR(drvdata->lpaif_map)) {
- dev_err(&pdev->dev, "error initializing regmap: %ld\n",
+ dev_err(dev, "error initializing regmap: %ld\n",
PTR_ERR(drvdata->lpaif_map));
return PTR_ERR(drvdata->lpaif_map);
}
@@ -468,10 +571,10 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
for (i = 0; i < variant->num_dai; i++) {
dai_id = variant->dai_driver[i].id;
- drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(&pdev->dev,
+ drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(dev,
variant->dai_osr_clk_names[i]);
if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
- dev_warn(&pdev->dev,
+ dev_warn(dev,
"%s() error getting optional %s: %ld\n",
__func__,
variant->dai_osr_clk_names[i],
@@ -480,10 +583,10 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
drvdata->mi2s_osr_clk[dai_id] = NULL;
}
- drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(&pdev->dev,
+ drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(dev,
variant->dai_bit_clk_names[i]);
if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
- dev_err(&pdev->dev,
+ dev_err(dev,
"error getting %s: %ld\n",
variant->dai_bit_clk_names[i],
PTR_ERR(drvdata->mi2s_bit_clk[dai_id]));
@@ -491,41 +594,39 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
}
}
- drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk");
+ drvdata->ahbix_clk = devm_clk_get(dev, "ahbix-clk");
if (IS_ERR(drvdata->ahbix_clk)) {
- dev_err(&pdev->dev, "error getting ahbix-clk: %ld\n",
+ dev_err(dev, "error getting ahbix-clk: %ld\n",
PTR_ERR(drvdata->ahbix_clk));
return PTR_ERR(drvdata->ahbix_clk);
}
ret = clk_set_rate(drvdata->ahbix_clk, LPASS_AHBIX_CLOCK_FREQUENCY);
if (ret) {
- dev_err(&pdev->dev, "error setting rate on ahbix_clk: %d\n",
- ret);
+ dev_err(dev, "error setting rate on ahbix_clk: %d\n", ret);
return ret;
}
- dev_dbg(&pdev->dev, "set ahbix_clk rate to %lu\n",
+ dev_dbg(dev, "set ahbix_clk rate to %lu\n",
clk_get_rate(drvdata->ahbix_clk));
ret = clk_prepare_enable(drvdata->ahbix_clk);
if (ret) {
- dev_err(&pdev->dev, "error enabling ahbix_clk: %d\n", ret);
+ dev_err(dev, "error enabling ahbix_clk: %d\n", ret);
return ret;
}
- ret = devm_snd_soc_register_component(&pdev->dev,
+ ret = devm_snd_soc_register_component(dev,
&lpass_cpu_comp_driver,
variant->dai_driver,
variant->num_dai);
if (ret) {
- dev_err(&pdev->dev, "error registering cpu driver: %d\n", ret);
+ dev_err(dev, "error registering cpu driver: %d\n", ret);
goto err_clk;
}
ret = asoc_qcom_lpass_platform_register(pdev);
if (ret) {
- dev_err(&pdev->dev, "error registering platform driver: %d\n",
- ret);
+ dev_err(dev, "error registering platform driver: %d\n", ret);
goto err_clk;
}
diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
index 3d74ae123e9d..72a3e2f69572 100644
--- a/sound/soc/qcom/lpass-lpaif-reg.h
+++ b/sound/soc/qcom/lpass-lpaif-reg.h
@@ -22,17 +22,19 @@
#define LPAIF_I2SCTL_SPKEN_DISABLE (0 << LPAIF_I2SCTL_SPKEN_SHIFT)
#define LPAIF_I2SCTL_SPKEN_ENABLE (1 << LPAIF_I2SCTL_SPKEN_SHIFT)
+#define LPAIF_I2SCTL_MODE_NONE 0
+#define LPAIF_I2SCTL_MODE_SD0 1
+#define LPAIF_I2SCTL_MODE_SD1 2
+#define LPAIF_I2SCTL_MODE_SD2 3
+#define LPAIF_I2SCTL_MODE_SD3 4
+#define LPAIF_I2SCTL_MODE_QUAD01 5
+#define LPAIF_I2SCTL_MODE_QUAD23 6
+#define LPAIF_I2SCTL_MODE_6CH 7
+#define LPAIF_I2SCTL_MODE_8CH 8
+
#define LPAIF_I2SCTL_SPKMODE_MASK 0x3C00
#define LPAIF_I2SCTL_SPKMODE_SHIFT 10
-#define LPAIF_I2SCTL_SPKMODE_NONE (0 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD0 (1 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD1 (2 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD2 (3 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD3 (4 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_QUAD01 (5 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_QUAD23 (6 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_6CH (7 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_8CH (8 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE(mode) ((mode) << LPAIF_I2SCTL_SPKMODE_SHIFT)
#define LPAIF_I2SCTL_SPKMONO_MASK 0x0200
#define LPAIF_I2SCTL_SPKMONO_SHIFT 9
@@ -46,15 +48,7 @@
#define LPAIF_I2SCTL_MICMODE_MASK GENMASK(7, 4)
#define LPAIF_I2SCTL_MICMODE_SHIFT 4
-#define LPAIF_I2SCTL_MICMODE_NONE (0 << LPAIF_I2SCTL_MICMODE_SHIFT)
-#define LPAIF_I2SCTL_MICMODE_SD0 (1 << LPAIF_I2SCTL_MICMODE_SHIFT)
-#define LPAIF_I2SCTL_MICMODE_SD1 (2 << LPAIF_I2SCTL_MICMODE_SHIFT)
-#define LPAIF_I2SCTL_MICMODE_SD2 (3 << LPAIF_I2SCTL_MICMODE_SHIFT)
-#define LPAIF_I2SCTL_MICMODE_SD3 (4 << LPAIF_I2SCTL_MICMODE_SHIFT)
-#define LPAIF_I2SCTL_MICMODE_QUAD01 (5 << LPAIF_I2SCTL_MICMODE_SHIFT)
-#define LPAIF_I2SCTL_MICMODE_QUAD23 (6 << LPAIF_I2SCTL_MICMODE_SHIFT)
-#define LPAIF_I2SCTL_MICMODE_6CH (7 << LPAIF_I2SCTL_MICMODE_SHIFT)
-#define LPAIF_I2SCTL_MICMODE_8CH (8 << LPAIF_I2SCTL_MICMODE_SHIFT)
+#define LPAIF_I2SCTL_MICMODE(mode) ((mode) << LPAIF_I2SCTL_MICMODE_SHIFT)
#define LPAIF_I2SCTL_MIMONO_MASK GENMASK(3, 3)
#define LPAIF_I2SCTL_MICMONO_SHIFT 3
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 17113d380dcc..bd19ec57c73d 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -29,6 +29,10 @@ struct lpass_data {
/* MI2S bit clock (derived from system clock by a divider */
struct clk *mi2s_bit_clk[LPASS_MAX_MI2S_PORTS];
+ /* MI2S SD lines to use for playback/capture */
+ unsigned int mi2s_playback_sd_mode[LPASS_MAX_MI2S_PORTS];
+ unsigned int mi2s_capture_sd_mode[LPASS_MAX_MI2S_PORTS];
+
/* low-power audio interface (LPAIF) registers */
void __iomem *lpaif;
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 125af00bba53..ce77446dbbdd 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -540,19 +540,19 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
}
}
-static int q6asm_dai_compr_open(struct snd_compr_stream *stream)
+static int q6asm_dai_compr_open(struct snd_soc_component *component,
+ struct snd_compr_stream *stream)
{
struct snd_soc_pcm_runtime *rtd = stream->private_data;
- struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct snd_compr_runtime *runtime = stream->runtime;
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct q6asm_dai_data *pdata;
- struct device *dev = c->dev;
+ struct device *dev = component->dev;
struct q6asm_dai_rtd *prtd;
int stream_id, size, ret;
stream_id = cpu_dai->driver->id;
- pdata = snd_soc_component_get_drvdata(c);
+ pdata = snd_soc_component_get_drvdata(component);
if (!pdata) {
dev_err(dev, "Drv data not found ..\n");
return -EINVAL;
@@ -600,7 +600,8 @@ free_prtd:
return ret;
}
-static int q6asm_dai_compr_free(struct snd_compr_stream *stream)
+static int q6asm_dai_compr_free(struct snd_soc_component *component,
+ struct snd_compr_stream *stream)
{
struct snd_compr_runtime *runtime = stream->runtime;
struct q6asm_dai_rtd *prtd = runtime->private_data;
@@ -622,13 +623,13 @@ static int q6asm_dai_compr_free(struct snd_compr_stream *stream)
return 0;
}
-static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream,
+static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
struct snd_compr_params *params)
{
struct snd_compr_runtime *runtime = stream->runtime;
struct q6asm_dai_rtd *prtd = runtime->private_data;
struct snd_soc_pcm_runtime *rtd = stream->private_data;
- struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
int dir = stream->direction;
struct q6asm_dai_data *pdata;
struct q6asm_flac_cfg flac_cfg;
@@ -636,7 +637,7 @@ static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream,
struct q6asm_alac_cfg alac_cfg;
struct q6asm_ape_cfg ape_cfg;
unsigned int wma_v9 = 0;
- struct device *dev = c->dev;
+ struct device *dev = component->dev;
int ret;
union snd_codec_options *codec_options;
struct snd_dec_flac *flac;
@@ -649,7 +650,7 @@ static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream,
memcpy(&prtd->codec_param, params, sizeof(*params));
- pdata = snd_soc_component_get_drvdata(c);
+ pdata = snd_soc_component_get_drvdata(component);
if (!pdata)
return -EINVAL;
@@ -842,7 +843,8 @@ static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream,
return 0;
}
-static int q6asm_dai_compr_trigger(struct snd_compr_stream *stream, int cmd)
+static int q6asm_dai_compr_trigger(struct snd_soc_component *component,
+ struct snd_compr_stream *stream, int cmd)
{
struct snd_compr_runtime *runtime = stream->runtime;
struct q6asm_dai_rtd *prtd = runtime->private_data;
@@ -870,8 +872,9 @@ static int q6asm_dai_compr_trigger(struct snd_compr_stream *stream, int cmd)
return ret;
}
-static int q6asm_dai_compr_pointer(struct snd_compr_stream *stream,
- struct snd_compr_tstamp *tstamp)
+static int q6asm_dai_compr_pointer(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_tstamp *tstamp)
{
struct snd_compr_runtime *runtime = stream->runtime;
struct q6asm_dai_rtd *prtd = runtime->private_data;
@@ -887,8 +890,9 @@ static int q6asm_dai_compr_pointer(struct snd_compr_stream *stream,
return 0;
}
-static int q6asm_dai_compr_ack(struct snd_compr_stream *stream,
- size_t count)
+static int q6asm_dai_compr_ack(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ size_t count)
{
struct snd_compr_runtime *runtime = stream->runtime;
struct q6asm_dai_rtd *prtd = runtime->private_data;
@@ -901,21 +905,21 @@ static int q6asm_dai_compr_ack(struct snd_compr_stream *stream,
return count;
}
-static int q6asm_dai_compr_mmap(struct snd_compr_stream *stream,
- struct vm_area_struct *vma)
+static int q6asm_dai_compr_mmap(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct vm_area_struct *vma)
{
struct snd_compr_runtime *runtime = stream->runtime;
struct q6asm_dai_rtd *prtd = runtime->private_data;
- struct snd_soc_pcm_runtime *rtd = stream->private_data;
- struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
- struct device *dev = c->dev;
+ struct device *dev = component->dev;
return dma_mmap_coherent(dev, vma,
prtd->dma_buffer.area, prtd->dma_buffer.addr,
prtd->dma_buffer.bytes);
}
-static int q6asm_dai_compr_get_caps(struct snd_compr_stream *stream,
+static int q6asm_dai_compr_get_caps(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
struct snd_compr_caps *caps)
{
caps->direction = SND_COMPRESS_PLAYBACK;
@@ -933,7 +937,8 @@ static int q6asm_dai_compr_get_caps(struct snd_compr_stream *stream,
return 0;
}
-static int q6asm_dai_compr_get_codec_caps(struct snd_compr_stream *stream,
+static int q6asm_dai_compr_get_codec_caps(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
struct snd_compr_codec_caps *codec)
{
switch (codec->codec) {
@@ -947,7 +952,7 @@ static int q6asm_dai_compr_get_codec_caps(struct snd_compr_stream *stream,
return 0;
}
-static struct snd_compr_ops q6asm_dai_compr_ops = {
+static struct snd_compress_ops q6asm_dai_compress_ops = {
.open = q6asm_dai_compr_open,
.free = q6asm_dai_compr_free,
.set_params = q6asm_dai_compr_set_params,
@@ -1021,7 +1026,7 @@ static const struct snd_soc_component_driver q6asm_fe_dai_component = {
.mmap = q6asm_dai_mmap,
.pcm_construct = q6asm_dai_pcm_new,
.pcm_destruct = q6asm_dai_pcm_free,
- .compr_ops = &q6asm_dai_compr_ops,
+ .compress_ops = &q6asm_dai_compress_ops,
};
static struct snd_soc_dai_driver q6asm_fe_dais_template[] = {
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index af19010b9d88..8bd49c8a9517 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -224,6 +224,14 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884),
RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888),
RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE1, 0x854),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE3, 0x85c),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE5, 0x894),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE7, 0x89c),
RSND_GEN_S_REG(HDMI0_SEL, 0x9e0),
RSND_GEN_S_REG(HDMI1_SEL, 0x9e4),
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index ea6cbaa9743e..d47608ff5fac 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -189,6 +189,14 @@ enum rsnd_reg {
SSI_SYS_STATUS5,
SSI_SYS_STATUS6,
SSI_SYS_STATUS7,
+ SSI_SYS_INT_ENABLE0,
+ SSI_SYS_INT_ENABLE1,
+ SSI_SYS_INT_ENABLE2,
+ SSI_SYS_INT_ENABLE3,
+ SSI_SYS_INT_ENABLE4,
+ SSI_SYS_INT_ENABLE5,
+ SSI_SYS_INT_ENABLE6,
+ SSI_SYS_INT_ENABLE7,
HDMI0_SEL,
HDMI1_SEL,
SSI9_BUSIF0_MODE,
@@ -237,6 +245,7 @@ enum rsnd_reg {
#define SSI9_BUSIF_ADINR(i) (SSI9_BUSIF0_ADINR + (i))
#define SSI9_BUSIF_DALIGN(i) (SSI9_BUSIF0_DALIGN + (i))
#define SSI_SYS_STATUS(i) (SSI_SYS_STATUS0 + (i))
+#define SSI_SYS_INT_ENABLE(i) (SSI_SYS_INT_ENABLE0 + (i))
struct rsnd_priv;
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 4a7d3413917f..47d5ddb526f2 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -372,6 +372,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
u32 wsr = ssi->wsr;
int width;
int is_tdm, is_tdm_split;
+ int id = rsnd_mod_id(mod);
+ int i;
+ u32 sys_int_enable = 0;
is_tdm = rsnd_runtime_is_tdm(io);
is_tdm_split = rsnd_runtime_is_tdm_split(io);
@@ -447,6 +450,38 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
cr_mode = DIEN; /* PIO : enable Data interrupt */
}
+ /* enable busif buffer over/under run interrupt. */
+ if (is_tdm || is_tdm_split) {
+ switch (id) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ for (i = 0; i < 4; i++) {
+ sys_int_enable = rsnd_mod_read(mod,
+ SSI_SYS_INT_ENABLE(i * 2));
+ sys_int_enable |= 0xf << (id * 4);
+ rsnd_mod_write(mod,
+ SSI_SYS_INT_ENABLE(i * 2),
+ sys_int_enable);
+ }
+
+ break;
+ case 9:
+ for (i = 0; i < 4; i++) {
+ sys_int_enable = rsnd_mod_read(mod,
+ SSI_SYS_INT_ENABLE((i * 2) + 1));
+ sys_int_enable |= 0xf << 4;
+ rsnd_mod_write(mod,
+ SSI_SYS_INT_ENABLE((i * 2) + 1),
+ sys_int_enable);
+ }
+
+ break;
+ }
+ }
+
init_end:
ssi->cr_own = cr_own;
ssi->cr_mode = cr_mode;
@@ -496,6 +531,13 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct device *dev = rsnd_priv_to_dev(priv);
+ int is_tdm, is_tdm_split;
+ int id = rsnd_mod_id(mod);
+ int i;
+ u32 sys_int_enable = 0;
+
+ is_tdm = rsnd_runtime_is_tdm(io);
+ is_tdm_split = rsnd_runtime_is_tdm_split(io);
if (!rsnd_ssi_is_run_mods(mod, io))
return 0;
@@ -517,6 +559,38 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
ssi->wsr = 0;
}
+ /* disable busif buffer over/under run interrupt. */
+ if (is_tdm || is_tdm_split) {
+ switch (id) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ for (i = 0; i < 4; i++) {
+ sys_int_enable = rsnd_mod_read(mod,
+ SSI_SYS_INT_ENABLE(i * 2));
+ sys_int_enable &= ~(0xf << (id * 4));
+ rsnd_mod_write(mod,
+ SSI_SYS_INT_ENABLE(i * 2),
+ sys_int_enable);
+ }
+
+ break;
+ case 9:
+ for (i = 0; i < 4; i++) {
+ sys_int_enable = rsnd_mod_read(mod,
+ SSI_SYS_INT_ENABLE((i * 2) + 1));
+ sys_int_enable &= ~(0xf << 4);
+ rsnd_mod_write(mod,
+ SSI_SYS_INT_ENABLE((i * 2) + 1),
+ sys_int_enable);
+ }
+
+ break;
+ }
+ }
+
return 0;
}
@@ -622,6 +696,11 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod,
int enable)
{
u32 val = 0;
+ int is_tdm, is_tdm_split;
+ int id = rsnd_mod_id(mod);
+
+ is_tdm = rsnd_runtime_is_tdm(io);
+ is_tdm_split = rsnd_runtime_is_tdm_split(io);
if (rsnd_is_gen1(priv))
return 0;
@@ -635,6 +714,19 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod,
if (enable)
val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000;
+ if (is_tdm || is_tdm_split) {
+ switch (id) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 9:
+ val |= 0x0000ff00;
+ break;
+ }
+ }
+
rsnd_mod_write(mod, SSI_INT_ENABLE, val);
return 0;
@@ -651,6 +743,12 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
u32 status;
bool elapsed = false;
bool stop = false;
+ int id = rsnd_mod_id(mod);
+ int i;
+ int is_tdm, is_tdm_split;
+
+ is_tdm = rsnd_runtime_is_tdm(io);
+ is_tdm_split = rsnd_runtime_is_tdm_split(io);
spin_lock(&priv->lock);
@@ -672,6 +770,53 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
stop = true;
}
+ status = 0;
+
+ if (is_tdm || is_tdm_split) {
+ switch (id) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ for (i = 0; i < 4; i++) {
+ status = rsnd_mod_read(mod,
+ SSI_SYS_STATUS(i * 2));
+ status &= 0xf << (id * 4);
+
+ if (status) {
+ rsnd_dbg_irq_status(dev,
+ "%s err status : 0x%08x\n",
+ rsnd_mod_name(mod), status);
+ rsnd_mod_write(mod,
+ SSI_SYS_STATUS(i * 2),
+ 0xf << (id * 4));
+ stop = true;
+ break;
+ }
+ }
+ break;
+ case 9:
+ for (i = 0; i < 4; i++) {
+ status = rsnd_mod_read(mod,
+ SSI_SYS_STATUS((i * 2) + 1));
+ status &= 0xf << 4;
+
+ if (status) {
+ rsnd_dbg_irq_status(dev,
+ "%s err status : 0x%08x\n",
+ rsnd_mod_name(mod), status);
+ rsnd_mod_write(mod,
+ SSI_SYS_STATUS((i * 2) + 1),
+ 0xf << 4);
+ stop = true;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
rsnd_ssi_status_clear(mod);
rsnd_ssi_interrupt_out:
spin_unlock(&priv->lock);
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 50062eb79adb..def3ae78b4a7 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -29,11 +29,11 @@ static int soc_compr_components_open(struct snd_compr_stream *cstream,
int i, ret;
for_each_rtd_components(rtd, i, component) {
- if (!component->driver->compr_ops ||
- !component->driver->compr_ops->open)
+ if (!component->driver->compress_ops ||
+ !component->driver->compress_ops->open)
continue;
- ret = component->driver->compr_ops->open(cstream);
+ ret = component->driver->compress_ops->open(component, cstream);
if (ret < 0) {
dev_err(component->dev,
"Compress ASoC: can't open platform %s: %d\n",
@@ -59,11 +59,11 @@ static int soc_compr_components_free(struct snd_compr_stream *cstream,
if (component == last)
break;
- if (!component->driver->compr_ops ||
- !component->driver->compr_ops->free)
+ if (!component->driver->compress_ops ||
+ !component->driver->compress_ops->free)
continue;
- component->driver->compr_ops->free(cstream);
+ component->driver->compress_ops->free(component, cstream);
}
return 0;
@@ -72,8 +72,8 @@ static int soc_compr_components_free(struct snd_compr_stream *cstream,
static int soc_compr_open(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_component *component, *save = NULL;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_component *component = NULL, *save = NULL;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
int ret, i;
for_each_rtd_components(rtd, i, component) {
@@ -87,15 +87,9 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
- ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
- if (ret < 0) {
- dev_err(cpu_dai->dev,
- "Compress ASoC: can't open interface %s: %d\n",
- cpu_dai->name, ret);
- goto out;
- }
- }
+ ret = snd_soc_dai_compr_startup(cpu_dai, cstream);
+ if (ret < 0)
+ goto out;
ret = soc_compr_components_open(cstream, &component);
if (ret < 0)
@@ -120,8 +114,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
machine_err:
soc_compr_components_free(cstream, component);
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
- cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
+ snd_soc_dai_compr_shutdown(cpu_dai, cstream);
out:
mutex_unlock(&rtd->card->pcm_mutex);
pm_err:
@@ -141,7 +134,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
struct snd_pcm_substream *fe_substream =
fe->pcm->streams[cstream->direction].substream;
struct snd_soc_component *component;
- struct snd_soc_dai *cpu_dai = fe->cpu_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
struct snd_soc_dpcm *dpcm;
struct snd_soc_dapm_widget_list *list;
int stream;
@@ -178,15 +171,9 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
goto out;
}
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
- ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
- if (ret < 0) {
- dev_err(cpu_dai->dev,
- "Compress ASoC: can't open interface %s: %d\n",
- cpu_dai->name, ret);
- goto out;
- }
- }
+ ret = snd_soc_dai_compr_startup(cpu_dai, cstream);
+ if (ret < 0)
+ goto out;
ret = soc_compr_components_open(cstream, &component);
if (ret < 0)
@@ -216,8 +203,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
machine_err:
soc_compr_components_free(cstream, component);
open_err:
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
- cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
+ snd_soc_dai_compr_shutdown(cpu_dai, cstream);
out:
dpcm_path_put(&list);
be_err:
@@ -230,8 +216,8 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_component *component;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
int stream, i;
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
@@ -256,8 +242,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
soc_compr_components_free(cstream, NULL);
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
- cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
+ snd_soc_dai_compr_shutdown(cpu_dai, cstream);
snd_soc_dapm_stream_stop(rtd, stream);
@@ -274,7 +259,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
static int soc_compr_free_fe(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *fe = cstream->private_data;
- struct snd_soc_dai *cpu_dai = fe->cpu_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
struct snd_soc_dpcm *dpcm;
int stream, ret;
@@ -313,8 +298,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
soc_compr_components_free(cstream, NULL);
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
- cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
+ snd_soc_dai_compr_shutdown(cpu_dai, cstream);
mutex_unlock(&fe->card->mutex);
return 0;
@@ -328,11 +312,12 @@ static int soc_compr_components_trigger(struct snd_compr_stream *cstream,
int i, ret;
for_each_rtd_components(rtd, i, component) {
- if (!component->driver->compr_ops ||
- !component->driver->compr_ops->trigger)
+ if (!component->driver->compress_ops ||
+ !component->driver->compress_ops->trigger)
continue;
- ret = component->driver->compr_ops->trigger(cstream, cmd);
+ ret = component->driver->compress_ops->trigger(
+ component, cstream, cmd);
if (ret < 0)
return ret;
}
@@ -343,8 +328,8 @@ static int soc_compr_components_trigger(struct snd_compr_stream *cstream,
static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
int ret;
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
@@ -353,8 +338,9 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
if (ret < 0)
goto out;
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger)
- cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
+ ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd);
+ if (ret < 0)
+ goto out;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -373,7 +359,7 @@ out:
static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
{
struct snd_soc_pcm_runtime *fe = cstream->private_data;
- struct snd_soc_dai *cpu_dai = fe->cpu_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
int ret, stream;
if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
@@ -387,11 +373,9 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) {
- ret = cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
- if (ret < 0)
- goto out;
- }
+ ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd);
+ if (ret < 0)
+ goto out;
ret = soc_compr_components_trigger(cstream, cmd);
if (ret < 0)
@@ -430,11 +414,12 @@ static int soc_compr_components_set_params(struct snd_compr_stream *cstream,
int i, ret;
for_each_rtd_components(rtd, i, component) {
- if (!component->driver->compr_ops ||
- !component->driver->compr_ops->set_params)
+ if (!component->driver->compress_ops ||
+ !component->driver->compress_ops->set_params)
continue;
- ret = component->driver->compr_ops->set_params(cstream, params);
+ ret = component->driver->compress_ops->set_params(
+ component, cstream, params);
if (ret < 0)
return ret;
}
@@ -446,7 +431,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
struct snd_compr_params *params)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
int ret;
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
@@ -458,11 +443,9 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
* that these callbacks will configure everything for this compress
* path, like configuring a PCM port for a CODEC.
*/
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
- ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
- if (ret < 0)
- goto err;
- }
+ ret = snd_soc_dai_compr_set_params(cpu_dai, cstream, params);
+ if (ret < 0)
+ goto err;
ret = soc_compr_components_set_params(cstream, params);
if (ret < 0)
@@ -500,7 +483,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
struct snd_soc_pcm_runtime *fe = cstream->private_data;
struct snd_pcm_substream *fe_substream =
fe->pcm->streams[cstream->direction].substream;
- struct snd_soc_dai *cpu_dai = fe->cpu_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
int ret, stream;
if (cstream->direction == SND_COMPRESS_PLAYBACK)
@@ -528,11 +511,9 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
if (ret < 0)
goto out;
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
- ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
- if (ret < 0)
- goto out;
- }
+ ret = snd_soc_dai_compr_set_params(cpu_dai, cstream, params);
+ if (ret < 0)
+ goto out;
ret = soc_compr_components_set_params(cstream, params);
if (ret < 0)
@@ -558,23 +539,22 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream,
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_component *component;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
int i, ret = 0;
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_params) {
- ret = cpu_dai->driver->cops->get_params(cstream, params, cpu_dai);
- if (ret < 0)
- goto err;
- }
+ ret = snd_soc_dai_compr_get_params(cpu_dai, cstream, params);
+ if (ret < 0)
+ goto err;
for_each_rtd_components(rtd, i, component) {
- if (!component->driver->compr_ops ||
- !component->driver->compr_ops->get_params)
+ if (!component->driver->compress_ops ||
+ !component->driver->compress_ops->get_params)
continue;
- ret = component->driver->compr_ops->get_params(cstream, params);
+ ret = component->driver->compress_ops->get_params(
+ component, cstream, params);
break;
}
@@ -593,11 +573,12 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream,
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
for_each_rtd_components(rtd, i, component) {
- if (!component->driver->compr_ops ||
- !component->driver->compr_ops->get_caps)
+ if (!component->driver->compress_ops ||
+ !component->driver->compress_ops->get_caps)
continue;
- ret = component->driver->compr_ops->get_caps(cstream, caps);
+ ret = component->driver->compress_ops->get_caps(
+ component, cstream, caps);
break;
}
@@ -615,12 +596,12 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
for_each_rtd_components(rtd, i, component) {
- if (!component->driver->compr_ops ||
- !component->driver->compr_ops->get_codec_caps)
+ if (!component->driver->compress_ops ||
+ !component->driver->compress_ops->get_codec_caps)
continue;
- ret = component->driver->compr_ops->get_codec_caps(cstream,
- codec);
+ ret = component->driver->compress_ops->get_codec_caps(
+ component, cstream, codec);
break;
}
@@ -632,23 +613,22 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_component *component;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
int i, ret = 0;
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->ack) {
- ret = cpu_dai->driver->cops->ack(cstream, bytes, cpu_dai);
- if (ret < 0)
- goto err;
- }
+ ret = snd_soc_dai_compr_ack(cpu_dai, cstream, bytes);
+ if (ret < 0)
+ goto err;
for_each_rtd_components(rtd, i, component) {
- if (!component->driver->compr_ops ||
- !component->driver->compr_ops->ack)
+ if (!component->driver->compress_ops ||
+ !component->driver->compress_ops->ack)
continue;
- ret = component->driver->compr_ops->ack(cstream, bytes);
+ ret = component->driver->compress_ops->ack(
+ component, cstream, bytes);
if (ret < 0)
goto err;
}
@@ -664,22 +644,24 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream,
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_component *component;
int i, ret = 0;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer)
- cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai);
+ ret = snd_soc_dai_compr_pointer(cpu_dai, cstream, tstamp);
+ if (ret < 0)
+ goto out;
for_each_rtd_components(rtd, i, component) {
- if (!component->driver->compr_ops ||
- !component->driver->compr_ops->pointer)
+ if (!component->driver->compress_ops ||
+ !component->driver->compress_ops->pointer)
continue;
- ret = component->driver->compr_ops->pointer(cstream, tstamp);
+ ret = component->driver->compress_ops->pointer(
+ component, cstream, tstamp);
break;
}
-
+out:
mutex_unlock(&rtd->card->pcm_mutex);
return ret;
}
@@ -694,11 +676,12 @@ static int soc_compr_copy(struct snd_compr_stream *cstream,
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
for_each_rtd_components(rtd, i, component) {
- if (!component->driver->compr_ops ||
- !component->driver->compr_ops->copy)
+ if (!component->driver->compress_ops ||
+ !component->driver->compress_ops->copy)
continue;
- ret = component->driver->compr_ops->copy(cstream, buf, count);
+ ret = component->driver->compress_ops->copy(
+ component, cstream, buf, count);
break;
}
@@ -711,22 +694,20 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_component *component;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
int i, ret;
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) {
- ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai);
- if (ret < 0)
- return ret;
- }
+ ret = snd_soc_dai_compr_set_metadata(cpu_dai, cstream, metadata);
+ if (ret < 0)
+ return ret;
for_each_rtd_components(rtd, i, component) {
- if (!component->driver->compr_ops ||
- !component->driver->compr_ops->set_metadata)
+ if (!component->driver->compress_ops ||
+ !component->driver->compress_ops->set_metadata)
continue;
- ret = component->driver->compr_ops->set_metadata(cstream,
- metadata);
+ ret = component->driver->compress_ops->set_metadata(
+ component, cstream, metadata);
if (ret < 0)
return ret;
}
@@ -739,22 +720,20 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_component *component;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
int i, ret;
- if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) {
- ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai);
- if (ret < 0)
- return ret;
- }
+ ret = snd_soc_dai_compr_get_metadata(cpu_dai, cstream, metadata);
+ if (ret < 0)
+ return ret;
for_each_rtd_components(rtd, i, component) {
- if (!component->driver->compr_ops ||
- !component->driver->compr_ops->get_metadata)
+ if (!component->driver->compress_ops ||
+ !component->driver->compress_ops->get_metadata)
continue;
- return component->driver->compr_ops->get_metadata(cstream,
- metadata);
+ return component->driver->compress_ops->get_metadata(
+ component, cstream, metadata);
}
return 0;
@@ -801,8 +780,8 @@ static struct snd_compr_ops soc_compr_dyn_ops = {
int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
{
struct snd_soc_component *component;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_compr *compr;
struct snd_pcm *be_pcm;
char new_name[64];
@@ -879,8 +858,8 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
}
for_each_rtd_components(rtd, i, component) {
- if (!component->driver->compr_ops ||
- !component->driver->compr_ops->copy)
+ if (!component->driver->compress_ops ||
+ !component->driver->compress_ops->copy)
continue;
compr->ops->copy = soc_compr_copy;
@@ -891,7 +870,7 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
ret = snd_compress_new(rtd->card->snd_card, num, direction,
new_name, compr);
if (ret < 0) {
- component = rtd->codec_dai->component;
+ component = asoc_rtd_to_codec(rtd, 0)->component;
dev_err(component->dev,
"Compress ASoC: can't create compress for codec %s: %d\n",
component->name, ret);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 843b8b1c89d4..95d8189e45ab 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -364,7 +364,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime);
*/
void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
int playback = SNDRV_PCM_STREAM_PLAYBACK;
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
@@ -487,20 +487,18 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
* dais = [][][][][][][][][][][][][][][][][][]
* ^cpu_dais ^codec_dais
* |--- num_cpus ---|--- num_codecs --|
+ * see
+ * asoc_rtd_to_cpu()
+ * asoc_rtd_to_codec()
*/
- rtd->cpu_dais = &rtd->dais[0];
- rtd->codec_dais = &rtd->dais[dai_link->num_cpus];
-
- /*
- * rtd remaining settings
- */
- rtd->card = card;
- rtd->dai_link = dai_link;
+ rtd->num_cpus = dai_link->num_cpus;
+ rtd->num_codecs = dai_link->num_codecs;
+ rtd->card = card;
+ rtd->dai_link = dai_link;
+ rtd->num = card->num_rtd++;
/* see for_each_card_rtds */
list_add_tail(&rtd->list, &card->rtd_list);
- rtd->num = card->num_rtd;
- card->num_rtd++;
return rtd;
@@ -744,9 +742,6 @@ static inline void soc_resume_init(struct snd_soc_card *card)
}
#endif
-static const struct snd_soc_dai_ops null_dai_ops = {
-};
-
static struct device_node
*soc_component_to_node(struct snd_soc_component *component)
{
@@ -865,8 +860,12 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card,
* Defer card registration if codec component is not added to
* component list.
*/
- if (!soc_find_component(codec))
+ if (!soc_find_component(codec)) {
+ dev_dbg(card->dev,
+ "ASoC: codec component %s not found for link %s\n",
+ codec->name, link->name);
return -EPROBE_DEFER;
+ }
}
for_each_link_platforms(link, i, platform) {
@@ -886,8 +885,12 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card,
* Defer card registration if platform component is not added to
* component list.
*/
- if (!soc_find_component(platform))
+ if (!soc_find_component(platform)) {
+ dev_dbg(card->dev,
+ "ASoC: platform component %s not found for link %s\n",
+ platform->name, link->name);
return -EPROBE_DEFER;
+ }
}
for_each_link_cpus(link, i, cpu) {
@@ -908,8 +911,12 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card,
* component list.
*/
if ((cpu->of_node || cpu->name) &&
- !soc_find_component(cpu))
+ !soc_find_component(cpu)) {
+ dev_dbg(card->dev,
+ "ASoC: cpu component %s not found for link %s\n",
+ cpu->name, link->name);
return -EPROBE_DEFER;
+ }
/*
* At least one of CPU DAI name or CPU device name/node must be
@@ -989,36 +996,28 @@ int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
if (!rtd)
return -ENOMEM;
- rtd->num_cpus = dai_link->num_cpus;
for_each_link_cpus(dai_link, i, cpu) {
- rtd->cpu_dais[i] = snd_soc_find_dai(cpu);
- if (!rtd->cpu_dais[i]) {
+ asoc_rtd_to_cpu(rtd, i) = snd_soc_find_dai(cpu);
+ if (!asoc_rtd_to_cpu(rtd, i)) {
dev_info(card->dev, "ASoC: CPU DAI %s not registered\n",
cpu->dai_name);
goto _err_defer;
}
- snd_soc_rtd_add_component(rtd, rtd->cpu_dais[i]->component);
+ snd_soc_rtd_add_component(rtd, asoc_rtd_to_cpu(rtd, i)->component);
}
- /* Single cpu links expect cpu and cpu_dai in runtime data */
- rtd->cpu_dai = rtd->cpu_dais[0];
-
/* Find CODEC from registered CODECs */
- rtd->num_codecs = dai_link->num_codecs;
for_each_link_codecs(dai_link, i, codec) {
- rtd->codec_dais[i] = snd_soc_find_dai(codec);
- if (!rtd->codec_dais[i]) {
+ asoc_rtd_to_codec(rtd, i) = snd_soc_find_dai(codec);
+ if (!asoc_rtd_to_codec(rtd, i)) {
dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n",
codec->dai_name);
goto _err_defer;
}
- snd_soc_rtd_add_component(rtd, rtd->codec_dais[i]->component);
+ snd_soc_rtd_add_component(rtd, asoc_rtd_to_codec(rtd, i)->component);
}
- /* Single codec links expect codec and codec_dai in runtime data */
- rtd->codec_dai = rtd->codec_dais[0];
-
/* Find PLATFORM from registered PLATFORMs */
for_each_link_platforms(dai_link, i, platform) {
for_each_component(component) {
@@ -1037,32 +1036,11 @@ _err_defer:
}
EXPORT_SYMBOL_GPL(snd_soc_add_pcm_runtime);
-static int soc_dai_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dai *dai;
- int i, ret = 0;
-
- for_each_rtd_dais(rtd, i, dai) {
- struct snd_soc_dai_driver *drv = dai->driver;
-
- if (drv->pcm_new)
- ret = drv->pcm_new(rtd, dai);
- if (ret < 0) {
- dev_err(dai->dev,
- "ASoC: Failed to bind %s with pcm device\n",
- dai->name);
- return ret;
- }
- }
-
- return 0;
-}
-
static int soc_init_pcm_runtime(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai_link *dai_link = rtd->dai_link;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_component *component;
int ret, num, i;
@@ -1122,7 +1100,7 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card,
return ret;
}
- return soc_dai_pcm_new(rtd);
+ return snd_soc_pcm_dai_new(rtd);
}
static void soc_set_name_prefix(struct snd_soc_card *card,
@@ -1278,64 +1256,23 @@ err_probe:
return ret;
}
-static void soc_remove_dai(struct snd_soc_dai *dai, int order)
-{
- int err;
-
- if (!dai || !dai->probed || !dai->driver ||
- dai->driver->remove_order != order)
- return;
-
- err = snd_soc_dai_remove(dai);
- if (err < 0)
- dev_err(dai->dev,
- "ASoC: failed to remove %s: %d\n",
- dai->name, err);
-
- dai->probed = 0;
-}
-
-static int soc_probe_dai(struct snd_soc_dai *dai, int order)
-{
- int ret;
-
- if (dai->probed ||
- dai->driver->probe_order != order)
- return 0;
-
- ret = snd_soc_dai_probe(dai);
- if (ret < 0) {
- dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n",
- dai->name, ret);
- return ret;
- }
-
- dai->probed = 1;
-
- return 0;
-}
-
static void soc_remove_link_dais(struct snd_soc_card *card)
{
- int i;
- struct snd_soc_dai *dai;
struct snd_soc_pcm_runtime *rtd;
int order;
for_each_comp_order(order) {
for_each_card_rtds(card, rtd) {
- /* remove DAIs */
- for_each_rtd_dais(rtd, i, dai)
- soc_remove_dai(dai, order);
+ /* remove all rtd connected DAIs in good order */
+ snd_soc_pcm_dai_remove(rtd, order);
}
}
}
static int soc_probe_link_dais(struct snd_soc_card *card)
{
- struct snd_soc_dai *dai;
struct snd_soc_pcm_runtime *rtd;
- int i, order, ret;
+ int order, ret;
for_each_comp_order(order) {
for_each_card_rtds(card, rtd) {
@@ -1344,12 +1281,10 @@ static int soc_probe_link_dais(struct snd_soc_card *card)
"ASoC: probe %s dai link %d late %d\n",
card->name, rtd->num, order);
- /* probe the CPU DAI */
- for_each_rtd_dais(rtd, i, dai) {
- ret = soc_probe_dai(dai, order);
- if (ret)
- return ret;
- }
+ /* probe all rtd connected DAIs in good order */
+ ret = snd_soc_pcm_dai_probe(rtd, order);
+ if (ret)
+ return ret;
}
}
@@ -2404,8 +2339,6 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
dai->component = component;
dai->dev = dev;
dai->driver = dai_drv;
- if (!dai->driver->ops)
- dai->driver->ops = &null_dai_ops;
/* see for_each_component_dais */
list_add_tail(&dai->list, &component->dai_list);
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 31c41559034b..8e5fe012aa1d 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -9,6 +9,24 @@
#include <sound/soc.h>
#include <sound/soc-dai.h>
+#define soc_dai_ret(dai, ret) _soc_dai_ret(dai, __func__, ret)
+static inline int _soc_dai_ret(struct snd_soc_dai *dai,
+ const char *func, int ret)
+{
+ switch (ret) {
+ case -EPROBE_DEFER:
+ case -ENOTSUPP:
+ case 0:
+ break;
+ default:
+ dev_err(dai->dev,
+ "ASoC: error at %s on %s: %d\n",
+ func, dai->name, ret);
+ }
+
+ return ret;
+}
+
/**
* snd_soc_dai_set_sysclk - configure DAI system or master clock.
* @dai: DAI
@@ -21,11 +39,16 @@
int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
- if (dai->driver->ops->set_sysclk)
- return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
+ int ret;
- return snd_soc_component_set_sysclk(dai->component, clk_id, 0,
- freq, dir);
+ if (dai->driver->ops &&
+ dai->driver->ops->set_sysclk)
+ ret = dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
+ else
+ ret = snd_soc_component_set_sysclk(dai->component, clk_id, 0,
+ freq, dir);
+
+ return soc_dai_ret(dai, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
@@ -42,10 +65,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
int div_id, int div)
{
- if (dai->driver->ops->set_clkdiv)
- return dai->driver->ops->set_clkdiv(dai, div_id, div);
- else
- return -EINVAL;
+ int ret = -EINVAL;
+
+ if (dai->driver->ops &&
+ dai->driver->ops->set_clkdiv)
+ ret = dai->driver->ops->set_clkdiv(dai, div_id, div);
+
+ return soc_dai_ret(dai, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
@@ -62,12 +88,17 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
unsigned int freq_in, unsigned int freq_out)
{
- if (dai->driver->ops->set_pll)
- return dai->driver->ops->set_pll(dai, pll_id, source,
- freq_in, freq_out);
+ int ret;
+
+ if (dai->driver->ops &&
+ dai->driver->ops->set_pll)
+ ret = dai->driver->ops->set_pll(dai, pll_id, source,
+ freq_in, freq_out);
+ else
+ ret = snd_soc_component_set_pll(dai->component, pll_id, source,
+ freq_in, freq_out);
- return snd_soc_component_set_pll(dai->component, pll_id, source,
- freq_in, freq_out);
+ return soc_dai_ret(dai, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
@@ -80,10 +111,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
*/
int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
{
- if (dai->driver->ops->set_bclk_ratio)
- return dai->driver->ops->set_bclk_ratio(dai, ratio);
- else
- return -EINVAL;
+ int ret = -EINVAL;
+
+ if (dai->driver->ops &&
+ dai->driver->ops->set_bclk_ratio)
+ ret = dai->driver->ops->set_bclk_ratio(dai, ratio);
+
+ return soc_dai_ret(dai, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
@@ -96,9 +130,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
*/
int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
- if (dai->driver->ops->set_fmt == NULL)
- return -ENOTSUPP;
- return dai->driver->ops->set_fmt(dai, fmt);
+ int ret = -ENOTSUPP;
+
+ if (dai->driver->ops &&
+ dai->driver->ops->set_fmt)
+ ret = dai->driver->ops->set_fmt(dai, fmt);
+
+ return soc_dai_ret(dai, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
@@ -153,7 +191,10 @@ 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)
{
- if (dai->driver->ops->xlate_tdm_slot_mask)
+ int ret = -ENOTSUPP;
+
+ if (dai->driver->ops &&
+ dai->driver->ops->xlate_tdm_slot_mask)
dai->driver->ops->xlate_tdm_slot_mask(slots,
&tx_mask, &rx_mask);
else
@@ -162,11 +203,11 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
dai->tx_mask = tx_mask;
dai->rx_mask = rx_mask;
- if (dai->driver->ops->set_tdm_slot)
- return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
+ if (dai->driver->ops &&
+ dai->driver->ops->set_tdm_slot)
+ ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
slots, slot_width);
- else
- return -ENOTSUPP;
+ return soc_dai_ret(dai, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
@@ -186,11 +227,13 @@ int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
unsigned int tx_num, unsigned int *tx_slot,
unsigned int rx_num, unsigned int *rx_slot)
{
- if (dai->driver->ops->set_channel_map)
- return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
- rx_num, rx_slot);
- else
- return -ENOTSUPP;
+ int ret = -ENOTSUPP;
+
+ if (dai->driver->ops &&
+ dai->driver->ops->set_channel_map)
+ ret = dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
+ rx_num, rx_slot);
+ return soc_dai_ret(dai, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
@@ -208,11 +251,13 @@ int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
unsigned int *tx_num, unsigned int *tx_slot,
unsigned int *rx_num, unsigned int *rx_slot)
{
- if (dai->driver->ops->get_channel_map)
- return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
- rx_num, rx_slot);
- else
- return -ENOTSUPP;
+ int ret = -ENOTSUPP;
+
+ if (dai->driver->ops &&
+ dai->driver->ops->get_channel_map)
+ ret = dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
+ rx_num, rx_slot);
+ return soc_dai_ret(dai, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
@@ -225,10 +270,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
*/
int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
{
- if (dai->driver->ops->set_tristate)
- return dai->driver->ops->set_tristate(dai, tristate);
- else
- return -EINVAL;
+ int ret = -EINVAL;
+
+ if (dai->driver->ops &&
+ dai->driver->ops->set_tristate)
+ ret = dai->driver->ops->set_tristate(dai, tristate);
+
+ return soc_dai_ret(dai, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
@@ -243,13 +291,17 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
int direction)
{
- if (dai->driver->ops->mute_stream)
- return dai->driver->ops->mute_stream(dai, mute, direction);
+ int ret = -ENOTSUPP;
+
+ if (dai->driver->ops &&
+ dai->driver->ops->mute_stream)
+ ret = dai->driver->ops->mute_stream(dai, mute, direction);
else if (direction == SNDRV_PCM_STREAM_PLAYBACK &&
+ dai->driver->ops &&
dai->driver->ops->digital_mute)
- return dai->driver->ops->digital_mute(dai, mute);
- else
- return -ENOTSUPP;
+ ret = dai->driver->ops->digital_mute(dai, mute);
+
+ return soc_dai_ret(dai, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
@@ -258,35 +310,27 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- int ret;
+ int ret = 0;
/* perform any topology hw_params fixups before DAI */
if (rtd->dai_link->be_hw_params_fixup) {
ret = rtd->dai_link->be_hw_params_fixup(rtd, params);
- if (ret < 0) {
- dev_err(rtd->dev,
- "ASoC: hw_params topology fixup failed %d\n",
- ret);
- return ret;
- }
+ if (ret < 0)
+ goto end;
}
- if (dai->driver->ops->hw_params) {
+ if (dai->driver->ops &&
+ dai->driver->ops->hw_params)
ret = dai->driver->ops->hw_params(substream, params, dai);
- if (ret < 0) {
- dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n",
- dai->name, ret);
- return ret;
- }
- }
-
- return 0;
+end:
+ return soc_dai_ret(dai, ret);
}
void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
struct snd_pcm_substream *substream)
{
- if (dai->driver->ops->hw_free)
+ if (dai->driver->ops &&
+ dai->driver->ops->hw_free)
dai->driver->ops->hw_free(substream, dai);
}
@@ -295,96 +339,287 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
{
int ret = 0;
- if (dai->driver->ops->startup)
+ if (dai->driver->ops &&
+ dai->driver->ops->startup)
ret = dai->driver->ops->startup(substream, dai);
- return ret;
+ return soc_dai_ret(dai, ret);
}
void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
struct snd_pcm_substream *substream)
{
- if (dai->driver->ops->shutdown)
+ if (dai->driver->ops &&
+ dai->driver->ops->shutdown)
dai->driver->ops->shutdown(substream, dai);
}
-int snd_soc_dai_prepare(struct snd_soc_dai *dai,
- struct snd_pcm_substream *substream)
+snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
+ struct snd_pcm_substream *substream)
{
- int ret = 0;
+ int delay = 0;
- if (dai->driver->ops->prepare)
- ret = dai->driver->ops->prepare(substream, dai);
+ if (dai->driver->ops &&
+ dai->driver->ops->delay)
+ delay = dai->driver->ops->delay(substream, dai);
- return ret;
+ return delay;
}
-int snd_soc_dai_trigger(struct snd_soc_dai *dai,
- struct snd_pcm_substream *substream,
- int cmd)
+int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
+ struct snd_soc_pcm_runtime *rtd, int num)
{
- int ret = 0;
+ int ret = -ENOTSUPP;
+ if (dai->driver->compress_new)
+ ret = dai->driver->compress_new(rtd, num);
+ return soc_dai_ret(dai, ret);
+}
+
+/*
+ * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
+ *
+ * Returns true if the DAI supports the indicated stream type.
+ */
+bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
+{
+ struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
- if (dai->driver->ops->trigger)
- ret = dai->driver->ops->trigger(substream, cmd, dai);
+ /* If the codec specifies any channels at all, it supports the stream */
+ return stream->channels_min;
+}
- return ret;
+int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
+{
+ struct snd_soc_dai *dai;
+ int i;
+
+ for_each_rtd_dais(rtd, i, dai) {
+ if (dai->driver->probe_order != order)
+ continue;
+
+ if (dai->driver->probe) {
+ int ret = dai->driver->probe(dai);
+
+ if (ret < 0)
+ return soc_dai_ret(dai, ret);
+ }
+
+ dai->probed = 1;
+ }
+
+ return 0;
}
-int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai,
- struct snd_pcm_substream *substream,
- int cmd)
+int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
{
- int ret = 0;
+ struct snd_soc_dai *dai;
+ int i, r, ret = 0;
+
+ for_each_rtd_dais(rtd, i, dai) {
+ if (dai->driver->remove_order != order)
+ continue;
+
+ if (dai->probed &&
+ dai->driver->remove) {
+ r = dai->driver->remove(dai);
+ if (r < 0)
+ ret = r; /* use last error */
+ }
- if (dai->driver->ops->bespoke_trigger)
- ret = dai->driver->ops->bespoke_trigger(substream, cmd, dai);
+ dai->probed = 0;
+ }
return ret;
}
-snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
- struct snd_pcm_substream *substream)
+int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
{
- int delay = 0;
+ struct snd_soc_dai *dai;
+ int i, ret = 0;
+
+ for_each_rtd_dais(rtd, i, dai) {
+ if (dai->driver->pcm_new) {
+ ret = dai->driver->pcm_new(rtd, dai);
+ if (ret < 0)
+ return soc_dai_ret(dai, ret);
+ }
+ }
- if (dai->driver->ops->delay)
- delay = dai->driver->ops->delay(substream, dai);
+ return 0;
+}
- return delay;
+int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *dai;
+ int i, ret;
+
+ for_each_rtd_dais(rtd, i, dai) {
+ if (dai->driver->ops &&
+ dai->driver->ops->prepare) {
+ ret = dai->driver->ops->prepare(substream, dai);
+ if (ret < 0)
+ return soc_dai_ret(dai, ret);
+ }
+ }
+
+ return 0;
}
-int snd_soc_dai_probe(struct snd_soc_dai *dai)
+int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd)
{
- if (dai->driver->probe)
- return dai->driver->probe(dai);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *dai;
+ int i, ret;
+
+ for_each_rtd_dais(rtd, i, dai) {
+ if (dai->driver->ops &&
+ dai->driver->ops->trigger) {
+ ret = dai->driver->ops->trigger(substream, cmd, dai);
+ if (ret < 0)
+ return soc_dai_ret(dai, ret);
+ }
+ }
+
return 0;
}
-int snd_soc_dai_remove(struct snd_soc_dai *dai)
+int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
+ int cmd)
{
- if (dai->driver->remove)
- return dai->driver->remove(dai);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *dai;
+ int i, ret;
+
+ for_each_rtd_dais(rtd, i, dai) {
+ if (dai->driver->ops &&
+ dai->driver->ops->bespoke_trigger) {
+ ret = dai->driver->ops->bespoke_trigger(substream,
+ cmd, dai);
+ if (ret < 0)
+ return soc_dai_ret(dai, ret);
+ }
+ }
+
return 0;
}
-int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
- struct snd_soc_pcm_runtime *rtd, int num)
+int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream)
{
- if (dai->driver->compress_new)
- return dai->driver->compress_new(rtd, num);
- return -ENOTSUPP;
+ int ret = 0;
+
+ if (dai->driver->cops &&
+ dai->driver->cops->startup)
+ ret = dai->driver->cops->startup(cstream, dai);
+
+ return soc_dai_ret(dai, ret);
}
+EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);
-/*
- * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
- *
- * Returns true if the DAI supports the indicated stream type.
- */
-bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
+void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream)
{
- struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
+ if (dai->driver->cops &&
+ dai->driver->cops->shutdown)
+ dai->driver->cops->shutdown(cstream, dai);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);
- /* If the codec specifies any channels at all, it supports the stream */
- return stream->channels_min;
+int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream, int cmd)
+{
+ int ret = 0;
+
+ if (dai->driver->cops &&
+ dai->driver->cops->trigger)
+ ret = dai->driver->cops->trigger(cstream, cmd, dai);
+
+ return soc_dai_ret(dai, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_compr_trigger);
+
+int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_params *params)
+{
+ int ret = 0;
+
+ if (dai->driver->cops &&
+ dai->driver->cops->set_params)
+ ret = dai->driver->cops->set_params(cstream, params, dai);
+
+ return soc_dai_ret(dai, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_params);
+
+int snd_soc_dai_compr_get_params(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream,
+ struct snd_codec *params)
+{
+ int ret = 0;
+
+ if (dai->driver->cops &&
+ dai->driver->cops->get_params)
+ ret = dai->driver->cops->get_params(cstream, params, dai);
+
+ return soc_dai_ret(dai, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_params);
+
+int snd_soc_dai_compr_ack(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream,
+ size_t bytes)
+{
+ int ret = 0;
+
+ if (dai->driver->cops &&
+ dai->driver->cops->ack)
+ ret = dai->driver->cops->ack(cstream, bytes, dai);
+
+ return soc_dai_ret(dai, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_compr_ack);
+
+int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_tstamp *tstamp)
+{
+ int ret = 0;
+
+ if (dai->driver->cops &&
+ dai->driver->cops->pointer)
+ ret = dai->driver->cops->pointer(cstream, tstamp, dai);
+
+ return soc_dai_ret(dai, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_compr_pointer);
+
+int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_metadata *metadata)
+{
+ int ret = 0;
+
+ if (dai->driver->cops &&
+ dai->driver->cops->set_metadata)
+ ret = dai->driver->cops->set_metadata(cstream, metadata, dai);
+
+ return soc_dai_ret(dai, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_metadata);
+
+int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_metadata *metadata)
+{
+ int ret = 0;
+
+ if (dai->driver->cops &&
+ dai->driver->cops->get_metadata)
+ ret = dai->driver->cops->get_metadata(cstream, metadata, dai);
+
+ return soc_dai_ret(dai, ret);
}
+EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_metadata);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index e2632841b321..80658d13a855 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -4427,11 +4427,11 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
if (rtd->num_cpus == 1) {
for_each_rtd_codec_dais(rtd, i, codec_dai)
dapm_connect_dai_pair(card, rtd, codec_dai,
- rtd->cpu_dais[0]);
+ asoc_rtd_to_cpu(rtd, 0));
} else if (rtd->num_codecs == rtd->num_cpus) {
for_each_rtd_codec_dais(rtd, i, codec_dai)
dapm_connect_dai_pair(card, rtd, codec_dai,
- rtd->cpu_dais[i]);
+ asoc_rtd_to_cpu(rtd, i));
} else {
dev_err(card->dev,
"N cpus to M codecs link is not supported yet\n");
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index facf1922a714..f728309a0833 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -68,7 +68,7 @@ int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
return -EINVAL;
}
- dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
if (ret)
@@ -134,7 +134,7 @@ dmaengine_pcm_set_runtime_hwparams(struct snd_soc_component *component,
return snd_soc_set_runtime_hwparams(substream,
pcm->config->pcm_hardware);
- dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
memset(&hw, 0, sizeof(hw));
hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
@@ -203,7 +203,7 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel(
return NULL;
}
- dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) && pcm->chan[0])
return pcm->chan[0];
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 1f302de44052..440c7e87829a 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -136,7 +136,7 @@ static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
return -ENOMEM;
for_each_pcm_streams(stream)
- if (snd_soc_dai_stream_valid(fe->cpu_dai, stream))
+ if (snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream))
offset += dpcm_show_state(fe, stream,
buf + offset,
out_count - offset);
@@ -836,10 +836,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
soc_pcm_init_runtime_hw(substream);
if (rtd->num_codecs == 1)
- codec_dai_name = rtd->codec_dai->name;
+ codec_dai_name = asoc_rtd_to_codec(rtd, 0)->name;
if (rtd->num_cpus == 1)
- cpu_dai_name = rtd->cpu_dai->name;
+ cpu_dai_name = asoc_rtd_to_cpu(rtd, 0)->name;
if (soc_pcm_has_symmetry(substream))
runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
@@ -950,13 +950,10 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
}
}
- for_each_rtd_dais(rtd, i, dai) {
- ret = snd_soc_dai_prepare(dai, substream);
- if (ret < 0) {
- dev_err(dai->dev,
- "ASoC: DAI prepare error: %d\n", ret);
- goto out;
- }
+ ret = snd_soc_pcm_dai_prepare(substream);
+ if (ret < 0) {
+ dev_err(rtd->dev, "ASoC: DAI prepare error: %d\n", ret);
+ goto out;
}
/* cancel any delayed stream shutdown that is pending */
@@ -1195,7 +1192,6 @@ static int soc_pcm_trigger_start(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_component *component;
- struct snd_soc_dai *dai;
int i, ret;
ret = soc_rtd_trigger(rtd, substream, cmd);
@@ -1208,27 +1204,18 @@ static int soc_pcm_trigger_start(struct snd_pcm_substream *substream, int cmd)
return ret;
}
- for_each_rtd_dais(rtd, i, dai) {
- ret = snd_soc_dai_trigger(dai, substream, cmd);
- if (ret < 0)
- return ret;
- }
-
- return 0;
+ return snd_soc_pcm_dai_trigger(substream, cmd);
}
static int soc_pcm_trigger_stop(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_component *component;
- struct snd_soc_dai *dai;
int i, ret;
- for_each_rtd_dais(rtd, i, dai) {
- ret = snd_soc_dai_trigger(dai, substream, cmd);
- if (ret < 0)
- return ret;
- }
+ ret = snd_soc_pcm_dai_trigger(substream, cmd);
+ if (ret < 0)
+ return ret;
for_each_rtd_components(rtd, i, component) {
ret = snd_soc_component_trigger(component, substream, cmd);
@@ -1265,21 +1252,6 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return ret;
}
-static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
- int cmd)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *dai;
- int i, ret;
-
- for_each_rtd_dais(rtd, i, dai) {
- ret = snd_soc_dai_bespoke_trigger(dai, substream, cmd);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
/*
* soc level wrapper for pointer callback
* If cpu_dai, codec_dai, component driver has the delay callback, then
@@ -1483,7 +1455,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
int stream, struct snd_soc_dapm_widget_list **list)
{
- struct snd_soc_dai *cpu_dai = fe->cpu_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
int paths;
if (fe->num_cpus > 1) {
@@ -1842,7 +1814,7 @@ static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
* DAIs connected to a single CPU DAI, use CPU DAI's directly
*/
if (be->num_codecs == 1) {
- codec_stream = snd_soc_dai_get_pcm_stream(be->codec_dais[0], stream);
+ codec_stream = snd_soc_dai_get_pcm_stream(asoc_rtd_to_codec(be, 0), stream);
*channels_min = max(*channels_min,
codec_stream->channels_min);
@@ -2483,7 +2455,7 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
fe->dai_link->name, cmd);
- ret = soc_pcm_bespoke_trigger(substream, cmd);
+ ret = snd_soc_pcm_dai_bespoke_trigger(substream, cmd);
break;
default:
dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
@@ -2628,7 +2600,7 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
fe->dai_link->name);
- err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
+ err = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
if (err < 0)
dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
} else {
@@ -2706,7 +2678,7 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
fe->dai_link->name);
- ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
+ ret = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
if (ret < 0) {
dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
goto hw_free;
@@ -2759,7 +2731,7 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
return 0;
/* only check active links */
- if (!fe->cpu_dai->active)
+ if (!asoc_rtd_to_cpu(fe, 0)->active)
return 0;
/* DAPM sync will call this to update DSP paths */
@@ -2769,13 +2741,13 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
for_each_pcm_streams(stream) {
/* skip if FE doesn't have playback/capture capability */
- if (!snd_soc_dai_stream_valid(fe->cpu_dai, stream) ||
- !snd_soc_dai_stream_valid(fe->codec_dai, stream))
+ if (!snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream) ||
+ !snd_soc_dai_stream_valid(asoc_rtd_to_codec(fe, 0), stream))
continue;
/* skip if FE isn't currently playing/capturing */
- if (!fe->cpu_dai->stream_active[stream] ||
- !fe->codec_dai->stream_active[stream])
+ if (!asoc_rtd_to_cpu(fe, 0)->stream_active[stream] ||
+ !asoc_rtd_to_codec(fe, 0)->stream_active[stream])
continue;
paths = dpcm_path_get(fe, stream, &list);
@@ -2931,9 +2903,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
for_each_rtd_codec_dais(rtd, i, codec_dai) {
if (rtd->num_cpus == 1) {
- cpu_dai = rtd->cpu_dais[0];
+ cpu_dai = asoc_rtd_to_cpu(rtd, 0);
} else if (rtd->num_cpus == rtd->num_codecs) {
- cpu_dai = rtd->cpu_dais[i];
+ cpu_dai = asoc_rtd_to_cpu(rtd, i);
} else {
dev_err(rtd->card->dev,
"N cpus to M codecs link is not supported yet\n");
@@ -2980,7 +2952,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
snprintf(new_name, sizeof(new_name), "%s %s-%d",
rtd->dai_link->stream_name,
(rtd->num_codecs > 1) ?
- "multicodec" : rtd->codec_dai->name, num);
+ "multicodec" : asoc_rtd_to_codec(rtd, 0)->name, num);
ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
capture, &pcm);
@@ -3059,8 +3031,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
pcm->no_device_suspend = true;
out:
dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
- (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,
- (rtd->num_cpus > 1) ? "multicpu" : rtd->cpu_dai->name);
+ (rtd->num_codecs > 1) ? "multicodec" : asoc_rtd_to_codec(rtd, 0)->name,
+ (rtd->num_cpus > 1) ? "multicpu" : asoc_rtd_to_cpu(rtd, 0)->name);
return ret;
}
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 6df3b0d12d87..49875978a1ce 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -2390,7 +2390,7 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg,
tplg->pos += le32_to_cpu(hdr->size) +
le32_to_cpu(hdr->payload_size);
return 0;
- };
+ }
/* check the element size and count */
link = (struct snd_soc_tplg_link_config *)tplg->pos;
diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile
index 8eca2f85c90e..05718dfe6cd2 100644
--- a/sound/soc/sof/Makefile
+++ b/sound/soc/sof/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
control.o trace.o utils.o sof-audio.o
diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c
index 7354dc6a49cf..2d4969c705a4 100644
--- a/sound/soc/sof/compress.c
+++ b/sound/soc/sof/compress.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
@@ -13,7 +13,7 @@
#include "ops.h"
#include "probe.h"
-struct snd_compr_ops sof_probe_compressed_ops = {
+struct snd_compress_ops sof_probe_compressed_ops = {
.copy = sof_probe_compr_copy,
};
EXPORT_SYMBOL(sof_probe_compressed_ops);
@@ -117,8 +117,9 @@ int sof_probe_compr_pointer(struct snd_compr_stream *cstream,
}
EXPORT_SYMBOL(sof_probe_compr_pointer);
-int sof_probe_compr_copy(struct snd_compr_stream *cstream,
- char __user *buf, size_t count)
+int sof_probe_compr_copy(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
+ char __user *buf, size_t count)
{
struct snd_compr_runtime *rtd = cstream->runtime;
unsigned int offset, n;
diff --git a/sound/soc/sof/compress.h b/sound/soc/sof/compress.h
index 800f163603e1..ca8790bd4b13 100644
--- a/sound/soc/sof/compress.h
+++ b/sound/soc/sof/compress.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -13,7 +13,7 @@
#include <sound/compress_driver.h>
-extern struct snd_compr_ops sof_probe_compressed_ops;
+extern struct snd_compress_ops sof_probe_compressed_ops;
int sof_probe_compr_open(struct snd_compr_stream *cstream,
struct snd_soc_dai *dai);
@@ -25,7 +25,8 @@ int sof_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd,
struct snd_soc_dai *dai);
int sof_probe_compr_pointer(struct snd_compr_stream *cstream,
struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai);
-int sof_probe_compr_copy(struct snd_compr_stream *cstream,
- char __user *buf, size_t count);
+int sof_probe_compr_copy(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
+ char __user *buf, size_t count);
#endif
diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c
index 6d63768d42aa..186eea105bb1 100644
--- a/sound/soc/sof/control.c
+++ b/sound/soc/sof/control.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c
index 91acfae7935c..ef9be4f45e27 100644
--- a/sound/soc/sof/core.c
+++ b/sound/soc/sof/core.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
@@ -176,6 +176,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
/* init the IPC */
sdev->ipc = snd_sof_ipc_init(sdev);
if (!sdev->ipc) {
+ ret = -ENOMEM;
dev_err(sdev->dev, "error: failed to init DSP IPC %d\n", ret);
goto ipc_err;
}
diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c
index b5c0d6cf72cc..8e15f105d1d5 100644
--- a/sound/soc/sof/debug.c
+++ b/sound/soc/sof/debug.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig
index bae4f7bf5f75..8230285baa43 100644
--- a/sound/soc/sof/imx/Kconfig
+++ b/sound/soc/sof/imx/Kconfig
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
config SND_SOC_SOF_IMX_TOPLEVEL
bool "SOF support for NXP i.MX audio DSPs"
@@ -11,17 +11,41 @@ config SND_SOC_SOF_IMX_TOPLEVEL
if SND_SOC_SOF_IMX_TOPLEVEL
+config SND_SOC_SOF_IMX_OF
+ def_tristate SND_SOC_SOF_OF
+ select SND_SOC_SOF_IMX8 if SND_SOC_SOF_IMX8_SUPPORT
+ select SND_SOC_SOF_IMX8M if SND_SOC_SOF_IMX8M_SUPPORT
+ help
+ This option is not user-selectable but automagically handled by
+ 'select' statements at a higher level
+
config SND_SOC_SOF_IMX8_SUPPORT
bool "SOF support for i.MX8"
- depends on IMX_SCU
- depends on IMX_DSP
+ depends on IMX_SCU=y || IMX_SCU=SND_SOC_SOF_IMX_OF
+ depends on IMX_DSP=y || IMX_DSP=SND_SOC_SOF_IMX_OF
help
This adds support for Sound Open Firmware for NXP i.MX8 platforms
Say Y if you have such a device.
If unsure select "N".
config SND_SOC_SOF_IMX8
- def_tristate SND_SOC_SOF_OF
- depends on SND_SOC_SOF_IMX8_SUPPORT
+ tristate
+ help
+ This option is not user-selectable but automagically handled by
+ 'select' statements at a higher level
+
+config SND_SOC_SOF_IMX8M_SUPPORT
+ bool "SOF support for i.MX8M"
+ depends on IMX_DSP=y || IMX_DSP=SND_SOC_SOF_OF
+ help
+ This adds support for Sound Open Firmware for NXP i.MX8M platforms
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_SOF_IMX8M
+ tristate
+ help
+ This option is not user-selectable but automagically handled by
+ 'select' statements at a higher level
endif ## SND_SOC_SOF_IMX_IMX_TOPLEVEL
diff --git a/sound/soc/sof/imx/Makefile b/sound/soc/sof/imx/Makefile
index 6ef908e8c807..2b933b02bbac 100644
--- a/sound/soc/sof/imx/Makefile
+++ b/sound/soc/sof/imx/Makefile
@@ -1,4 +1,6 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
snd-sof-imx8-objs := imx8.o
+snd-sof-imx8m-objs := imx8m.o
obj-$(CONFIG_SND_SOC_SOF_IMX8) += snd-sof-imx8.o
+obj-$(CONFIG_SND_SOC_SOF_IMX8M) += snd-sof-imx8m.o
diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c
index b692752b2178..68b2edccd791 100644
--- a/sound/soc/sof/imx/imx8.c
+++ b/sound/soc/sof/imx/imx8.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// Copyright 2019 NXP
//
diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c
new file mode 100644
index 000000000000..3ac0444dca93
--- /dev/null
+++ b/sound/soc/sof/imx/imx8m.c
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// Copyright 2020 NXP
+//
+// Author: Daniel Baluta <[email protected]>
+//
+// Hardware interface for audio DSP on i.MX8M
+
+#include <linux/firmware.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <linux/module.h>
+#include <sound/sof.h>
+#include <sound/sof/xtensa.h>
+#include <linux/firmware/imx/dsp.h>
+
+#include "../ops.h"
+
+#define MBOX_OFFSET 0x800000
+#define MBOX_SIZE 0x1000
+
+struct imx8m_priv {
+ struct device *dev;
+ struct snd_sof_dev *sdev;
+
+ /* DSP IPC handler */
+ struct imx_dsp_ipc *dsp_ipc;
+ struct platform_device *ipc_dev;
+};
+
+static void imx8m_get_reply(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_ipc_msg *msg = sdev->msg;
+ struct sof_ipc_reply reply;
+ int ret = 0;
+
+ if (!msg) {
+ dev_warn(sdev->dev, "unexpected ipc interrupt\n");
+ return;
+ }
+
+ /* get reply */
+ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply));
+
+ if (reply.error < 0) {
+ memcpy(msg->reply_data, &reply, sizeof(reply));
+ ret = reply.error;
+ } else {
+ /* reply has correct size? */
+ if (reply.hdr.size != msg->reply_size) {
+ dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n",
+ msg->reply_size, reply.hdr.size);
+ ret = -EINVAL;
+ }
+
+ /* read the message */
+ if (msg->reply_size > 0)
+ sof_mailbox_read(sdev, sdev->host_box.offset,
+ msg->reply_data, msg->reply_size);
+ }
+
+ msg->reply_error = ret;
+}
+
+static int imx8m_get_mailbox_offset(struct snd_sof_dev *sdev)
+{
+ return MBOX_OFFSET;
+}
+
+static int imx8m_get_window_offset(struct snd_sof_dev *sdev, u32 id)
+{
+ return MBOX_OFFSET;
+}
+
+static void imx8m_dsp_handle_reply(struct imx_dsp_ipc *ipc)
+{
+ struct imx8m_priv *priv = imx_dsp_get_data(ipc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
+ imx8m_get_reply(priv->sdev);
+ snd_sof_ipc_reply(priv->sdev, 0);
+ spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
+}
+
+static void imx8m_dsp_handle_request(struct imx_dsp_ipc *ipc)
+{
+ struct imx8m_priv *priv = imx_dsp_get_data(ipc);
+
+ snd_sof_ipc_msgs_rx(priv->sdev);
+}
+
+struct imx_dsp_ops imx8m_dsp_ops = {
+ .handle_reply = imx8m_dsp_handle_reply,
+ .handle_request = imx8m_dsp_handle_request,
+};
+
+static int imx8m_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
+{
+ struct imx8m_priv *priv = (struct imx8m_priv *)sdev->private;
+
+ sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
+ msg->msg_size);
+ imx_dsp_ring_doorbell(priv->dsp_ipc, 0);
+
+ return 0;
+}
+
+/*
+ * DSP control.
+ */
+static int imx8m_run(struct snd_sof_dev *sdev)
+{
+ /* TODO: start DSP using Audio MIX bits */
+ return 0;
+}
+
+static int imx8m_probe(struct snd_sof_dev *sdev)
+{
+ struct platform_device *pdev =
+ container_of(sdev->dev, struct platform_device, dev);
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *res_node;
+ struct resource *mmio;
+ struct imx8m_priv *priv;
+ struct resource res;
+ u32 base, size;
+ int ret = 0;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ sdev->private = priv;
+ priv->dev = sdev->dev;
+ priv->sdev = sdev;
+
+ priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp",
+ PLATFORM_DEVID_NONE,
+ pdev, sizeof(*pdev));
+ if (IS_ERR(priv->ipc_dev))
+ return PTR_ERR(priv->ipc_dev);
+
+ priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev);
+ if (!priv->dsp_ipc) {
+ /* DSP IPC driver not probed yet, try later */
+ ret = -EPROBE_DEFER;
+ dev_err(sdev->dev, "Failed to get drvdata\n");
+ goto exit_pdev_unregister;
+ }
+
+ imx_dsp_set_data(priv->dsp_ipc, priv);
+ priv->dsp_ipc->ops = &imx8m_dsp_ops;
+
+ /* DSP base */
+ mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (mmio) {
+ base = mmio->start;
+ size = resource_size(mmio);
+ } else {
+ dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n");
+ ret = -EINVAL;
+ goto exit_pdev_unregister;
+ }
+
+ sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size);
+ if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) {
+ dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n",
+ base, size);
+ ret = -ENODEV;
+ goto exit_pdev_unregister;
+ }
+ sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM;
+
+ res_node = of_parse_phandle(np, "memory-region", 0);
+ if (!res_node) {
+ dev_err(&pdev->dev, "failed to get memory region node\n");
+ ret = -ENODEV;
+ goto exit_pdev_unregister;
+ }
+
+ ret = of_address_to_resource(res_node, 0, &res);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get reserved region address\n");
+ goto exit_pdev_unregister;
+ }
+
+ sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start,
+ res.end - res.start +
+ 1);
+ if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
+ dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n",
+ base, size);
+ ret = -ENOMEM;
+ goto exit_pdev_unregister;
+ }
+ sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
+
+ /* set default mailbox offset for FW ready message */
+ sdev->dsp_box.offset = MBOX_OFFSET;
+
+ return 0;
+
+exit_pdev_unregister:
+ platform_device_unregister(priv->ipc_dev);
+ return ret;
+}
+
+static int imx8m_remove(struct snd_sof_dev *sdev)
+{
+ struct imx8m_priv *priv = (struct imx8m_priv *)sdev->private;
+
+ platform_device_unregister(priv->ipc_dev);
+
+ return 0;
+}
+
+/* on i.MX8 there is 1 to 1 match between type and BAR idx */
+static int imx8m_get_bar_index(struct snd_sof_dev *sdev, u32 type)
+{
+ return type;
+}
+
+static void imx8m_ipc_msg_data(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream,
+ void *p, size_t sz)
+{
+ sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz);
+}
+
+static int imx8m_ipc_pcm_params(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream,
+ const struct sof_ipc_pcm_params_reply *reply)
+{
+ return 0;
+}
+
+static struct snd_soc_dai_driver imx8m_dai[] = {
+{
+ .name = "sai-port",
+},
+};
+
+/* i.MX8 ops */
+struct snd_sof_dsp_ops sof_imx8m_ops = {
+ /* probe and remove */
+ .probe = imx8m_probe,
+ .remove = imx8m_remove,
+ /* DSP core boot */
+ .run = imx8m_run,
+
+ /* Block IO */
+ .block_read = sof_block_read,
+ .block_write = sof_block_write,
+
+ /* ipc */
+ .send_msg = imx8m_send_msg,
+ .fw_ready = sof_fw_ready,
+ .get_mailbox_offset = imx8m_get_mailbox_offset,
+ .get_window_offset = imx8m_get_window_offset,
+
+ .ipc_msg_data = imx8m_ipc_msg_data,
+ .ipc_pcm_params = imx8m_ipc_pcm_params,
+
+ /* module loading */
+ .load_module = snd_sof_parse_module_memcpy,
+ .get_bar_index = imx8m_get_bar_index,
+ /* firmware loading */
+ .load_firmware = snd_sof_load_firmware_memcpy,
+
+ /* DAI drivers */
+ .drv = imx8m_dai,
+ .num_drv = 1, /* we have only 1 SAI interface on i.MX8M */
+};
+EXPORT_SYMBOL(sof_imx8m_ops);
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile
index cee02a2e00f4..f7e9358f1f06 100644
--- a/sound/soc/sof/intel/Makefile
+++ b/sound/soc/sof/intel/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
snd-sof-intel-byt-objs := byt.o
snd-sof-intel-bdw-objs := bdw.o
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c
index 02218d22e51f..9e29d4fd393a 100644
--- a/sound/soc/sof/intel/apl.c
+++ b/sound/soc/sof/intel/apl.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c
index a32a3ef78ec5..99fd0bd7276e 100644
--- a/sound/soc/sof/intel/bdw.c
+++ b/sound/soc/sof/intel/bdw.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c
index 29fd1d86156c..3747f2c2c28b 100644
--- a/sound/soc/sof/intel/byt.c
+++ b/sound/soc/sof/intel/byt.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
@@ -82,33 +82,6 @@ static const struct snd_sof_debugfs_map byt_debugfs[] = {
SOF_DEBUGFS_ACCESS_ALWAYS},
};
-static const struct snd_sof_debugfs_map cht_debugfs[] = {
- {"dmac0", BYT_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE,
- SOF_DEBUGFS_ACCESS_ALWAYS},
- {"dmac1", BYT_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE,
- SOF_DEBUGFS_ACCESS_ALWAYS},
- {"dmac2", BYT_DSP_BAR, DMAC2_OFFSET, DMAC_SIZE,
- SOF_DEBUGFS_ACCESS_ALWAYS},
- {"ssp0", BYT_DSP_BAR, SSP0_OFFSET, SSP_SIZE,
- SOF_DEBUGFS_ACCESS_ALWAYS},
- {"ssp1", BYT_DSP_BAR, SSP1_OFFSET, SSP_SIZE,
- SOF_DEBUGFS_ACCESS_ALWAYS},
- {"ssp2", BYT_DSP_BAR, SSP2_OFFSET, SSP_SIZE,
- SOF_DEBUGFS_ACCESS_ALWAYS},
- {"ssp3", BYT_DSP_BAR, SSP3_OFFSET, SSP_SIZE,
- SOF_DEBUGFS_ACCESS_ALWAYS},
- {"ssp4", BYT_DSP_BAR, SSP4_OFFSET, SSP_SIZE,
- SOF_DEBUGFS_ACCESS_ALWAYS},
- {"ssp5", BYT_DSP_BAR, SSP5_OFFSET, SSP_SIZE,
- SOF_DEBUGFS_ACCESS_ALWAYS},
- {"iram", BYT_DSP_BAR, IRAM_OFFSET, IRAM_SIZE,
- SOF_DEBUGFS_ACCESS_D0_ONLY},
- {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE,
- SOF_DEBUGFS_ACCESS_D0_ONLY},
- {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE_CHT,
- SOF_DEBUGFS_ACCESS_ALWAYS},
-};
-
static void byt_host_done(struct snd_sof_dev *sdev);
static void byt_dsp_done(struct snd_sof_dev *sdev);
static void byt_get_reply(struct snd_sof_dev *sdev);
@@ -681,6 +654,33 @@ EXPORT_SYMBOL_NS(tng_chip_info, SND_SOC_SOF_MERRIFIELD);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
+static const struct snd_sof_debugfs_map cht_debugfs[] = {
+ {"dmac0", BYT_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE,
+ SOF_DEBUGFS_ACCESS_ALWAYS},
+ {"dmac1", BYT_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE,
+ SOF_DEBUGFS_ACCESS_ALWAYS},
+ {"dmac2", BYT_DSP_BAR, DMAC2_OFFSET, DMAC_SIZE,
+ SOF_DEBUGFS_ACCESS_ALWAYS},
+ {"ssp0", BYT_DSP_BAR, SSP0_OFFSET, SSP_SIZE,
+ SOF_DEBUGFS_ACCESS_ALWAYS},
+ {"ssp1", BYT_DSP_BAR, SSP1_OFFSET, SSP_SIZE,
+ SOF_DEBUGFS_ACCESS_ALWAYS},
+ {"ssp2", BYT_DSP_BAR, SSP2_OFFSET, SSP_SIZE,
+ SOF_DEBUGFS_ACCESS_ALWAYS},
+ {"ssp3", BYT_DSP_BAR, SSP3_OFFSET, SSP_SIZE,
+ SOF_DEBUGFS_ACCESS_ALWAYS},
+ {"ssp4", BYT_DSP_BAR, SSP4_OFFSET, SSP_SIZE,
+ SOF_DEBUGFS_ACCESS_ALWAYS},
+ {"ssp5", BYT_DSP_BAR, SSP5_OFFSET, SSP_SIZE,
+ SOF_DEBUGFS_ACCESS_ALWAYS},
+ {"iram", BYT_DSP_BAR, IRAM_OFFSET, IRAM_SIZE,
+ SOF_DEBUGFS_ACCESS_D0_ONLY},
+ {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE,
+ SOF_DEBUGFS_ACCESS_D0_ONLY},
+ {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE_CHT,
+ SOF_DEBUGFS_ACCESS_ALWAYS},
+};
+
static int byt_acpi_probe(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *pdata = sdev->pdata;
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index e427d00eca71..16db0f50d139 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c
index 1d2babdda9dd..789148e5584b 100644
--- a/sound/soc/sof/intel/hda-bus.c
+++ b/sound/soc/sof/intel/hda-bus.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c
index 3041fbbb010a..c3299be119a1 100644
--- a/sound/soc/sof/intel/hda-codec.c
+++ b/sound/soc/sof/intel/hda-codec.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
@@ -207,7 +207,6 @@ EXPORT_SYMBOL_NS(hda_codec_i915_init, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
int hda_codec_i915_exit(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
- int ret;
if (!bus->audio_component)
return 0;
@@ -215,9 +214,7 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev)
/* power down unconditionally */
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
- ret = snd_hdac_i915_exit(bus);
-
- return ret;
+ return snd_hdac_i915_exit(bus);
}
EXPORT_SYMBOL_NS(hda_codec_i915_exit, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
diff --git a/sound/soc/sof/intel/hda-compress.c b/sound/soc/sof/intel/hda-compress.c
index 38a1ebec8478..53c08034fa22 100644
--- a/sound/soc/sof/intel/hda-compress.c
+++ b/sound/soc/sof/intel/hda-compress.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c
index 6288b2f99540..fa5f0a718901 100644
--- a/sound/soc/sof/intel/hda-ctrl.c
+++ b/sound/soc/sof/intel/hda-ctrl.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 833dc303b394..3934cd6bf87a 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index 99087b6afb67..9e5ff8c18f99 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
@@ -226,10 +226,10 @@ bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev,
val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS);
- is_enable = ((val & HDA_DSP_ADSPCS_CPA_MASK(core_mask)) &&
- (val & HDA_DSP_ADSPCS_SPA_MASK(core_mask)) &&
- !(val & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) &&
- !(val & HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)));
+ is_enable = (val & HDA_DSP_ADSPCS_CPA_MASK(core_mask)) &&
+ (val & HDA_DSP_ADSPCS_SPA_MASK(core_mask)) &&
+ !(val & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) &&
+ !(val & HDA_DSP_ADSPCS_CSTALL_MASK(core_mask));
dev_dbg(sdev->dev, "DSP core(s) enabled? %d : core_mask %x\n",
is_enable, core_mask);
diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c
index 6062bb6011fb..c91aa951df22 100644
--- a/sound/soc/sof/intel/hda-ipc.c
+++ b/sound/soc/sof/intel/hda-ipc.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/intel/hda-ipc.h b/sound/soc/sof/intel/hda-ipc.h
index aef0ceac9803..ade4c3191a39 100644
--- a/sound/soc/sof/intel/hda-ipc.h
+++ b/sound/soc/sof/intel/hda-ipc.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index e1550ccd0a49..d762b3e1ce4a 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
@@ -293,8 +293,13 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
chip_info = desc->chip_info;
- stripped_firmware.data = plat_data->fw->data;
- stripped_firmware.size = plat_data->fw->size;
+ if (plat_data->fw->size < plat_data->fw_offset) {
+ dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
+ return -EINVAL;
+ }
+
+ stripped_firmware.data = plat_data->fw->data + plat_data->fw_offset;
+ stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
/* init for booting wait */
init_waitqueue_head(&sdev->boot_wait);
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c
index a46a6baa1c3f..53a875ac52d6 100644
--- a/sound/soc/sof/intel/hda-pcm.c
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index 5d386956906f..7f65dcc95811 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c
index 33b23bd6a01e..1eb746d5adeb 100644
--- a/sound/soc/sof/intel/hda-trace.c
+++ b/sound/soc/sof/intel/hda-trace.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 211e91e79eae..578ac7b036b0 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
@@ -135,10 +135,8 @@ static int hda_sdw_acpi_scan(struct snd_sof_dev *sdev)
hdev = sdev->pdata->hw_pdata;
ret = sdw_intel_acpi_scan(handle, &hdev->info);
- if (ret < 0) {
- dev_err(sdev->dev, "%s failed\n", __func__);
+ if (ret < 0)
return -EINVAL;
- }
return 0;
}
@@ -282,6 +280,10 @@ module_param_named(use_msi, hda_use_msi, bool, 0444);
MODULE_PARM_DESC(use_msi, "SOF HDA use PCI MSI mode");
#endif
+static char *hda_model;
+module_param(hda_model, charp, 0444);
+MODULE_PARM_DESC(hda_model, "Use the given HDA board model.");
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
static int hda_dmic_num = -1;
module_param_named(dmic_num, hda_dmic_num, int, 0444);
@@ -503,7 +505,7 @@ static int hda_init(struct snd_sof_dev *sdev)
mutex_init(&hbus->prepare_mutex);
hbus->pci = pci;
hbus->mixer_assigned = -1;
- hbus->modelname = "sofbus";
+ hbus->modelname = hda_model;
/* initialise hdac bus */
bus->addr = pci_resource_start(pci, 0);
@@ -604,7 +606,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
/* scan SoundWire capabilities exposed by DSDT */
ret = hda_sdw_acpi_scan(sdev);
if (ret < 0) {
- dev_dbg(sdev->dev, "skipping SoundWire, ACPI scan error\n");
+ dev_dbg(sdev->dev, "skipping SoundWire, not detected with ACPI scan\n");
goto skip_soundwire;
}
@@ -1008,6 +1010,10 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev)
if (!tplg_filename)
return -EINVAL;
+ dev_info(bus->dev,
+ "DMICs detected in NHLT tables: %d\n",
+ dmic_num);
+
pdata->machine = hda_mach;
pdata->tplg_filename = tplg_filename;
}
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index e9825798de77..fe452f0d0ec7 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/intel/intel-ipc.c b/sound/soc/sof/intel/intel-ipc.c
index e935f70d611b..310f9168c124 100644
--- a/sound/soc/sof/intel/intel-ipc.c
+++ b/sound/soc/sof/intel/intel-ipc.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h
index daaf3364c177..6fe8b004b50e 100644
--- a/sound/soc/sof/intel/shim.h
+++ b/sound/soc/sof/intel/shim.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c
index 1c6794918cbb..f7a0353596fb 100644
--- a/sound/soc/sof/ipc.c
+++ b/sound/soc/sof/ipc.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c
index 64af08293daa..4a5b57ecf359 100644
--- a/sound/soc/sof/loader.c
+++ b/sound/soc/sof/loader.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
@@ -15,9 +15,9 @@
#include "ops.h"
static int get_ext_windows(struct snd_sof_dev *sdev,
- struct sof_ipc_ext_data_hdr *ext_hdr)
+ const struct sof_ipc_ext_data_hdr *ext_hdr)
{
- struct sof_ipc_window *w =
+ const struct sof_ipc_window *w =
container_of(ext_hdr, struct sof_ipc_window, ext_hdr);
if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS)
@@ -33,11 +33,11 @@ static int get_ext_windows(struct snd_sof_dev *sdev,
}
static int get_cc_info(struct snd_sof_dev *sdev,
- struct sof_ipc_ext_data_hdr *ext_hdr)
+ const struct sof_ipc_ext_data_hdr *ext_hdr)
{
int ret;
- struct sof_ipc_cc_version *cc =
+ const struct sof_ipc_cc_version *cc =
container_of(ext_hdr, struct sof_ipc_cc_version, ext_hdr);
dev_dbg(sdev->dev, "Firmware info: used compiler %s %d:%d:%d%s used optimization flags %s\n",
@@ -379,12 +379,19 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev,
}
EXPORT_SYMBOL(snd_sof_parse_module_memcpy);
-static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw)
+static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw,
+ size_t fw_offset)
{
struct snd_sof_fw_header *header;
+ size_t fw_size = fw->size - fw_offset;
+
+ if (fw->size < fw_offset) {
+ dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
+ return -EINVAL;
+ }
/* Read the header information from the data pointer */
- header = (struct snd_sof_fw_header *)fw->data;
+ header = (struct snd_sof_fw_header *)(fw->data + fw_offset);
/* verify FW sig */
if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) {
@@ -393,9 +400,9 @@ static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw)
}
/* check size is valid */
- if (fw->size != header->file_size + sizeof(*header)) {
+ if (fw_size != header->file_size + sizeof(*header)) {
dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n",
- fw->size, header->file_size + sizeof(*header));
+ fw_size, header->file_size + sizeof(*header));
return -EINVAL;
}
@@ -406,7 +413,8 @@ static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw)
return 0;
}
-static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw)
+static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw,
+ size_t fw_offset)
{
struct snd_sof_fw_header *header;
struct snd_sof_mod_hdr *module;
@@ -415,14 +423,15 @@ static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw)
int ret, count;
size_t remaining;
- header = (struct snd_sof_fw_header *)fw->data;
+ header = (struct snd_sof_fw_header *)(fw->data + fw_offset);
load_module = sof_ops(sdev)->load_module;
if (!load_module)
return -EINVAL;
/* parse each module */
- module = (struct snd_sof_mod_hdr *)((u8 *)(fw->data) + sizeof(*header));
- remaining = fw->size - sizeof(*header);
+ module = (struct snd_sof_mod_hdr *)(fw->data + fw_offset +
+ sizeof(*header));
+ remaining = fw->size - sizeof(*header) - fw_offset;
/* check for wrap */
if (remaining > fw->size) {
dev_err(sdev->dev, "error: fw size smaller than header size\n");
@@ -502,7 +511,7 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
return ret;
/* make sure the FW header and file is valid */
- ret = check_header(sdev, plat_data->fw);
+ ret = check_header(sdev, plat_data->fw, plat_data->fw_offset);
if (ret < 0) {
dev_err(sdev->dev, "error: invalid FW header\n");
goto error;
@@ -516,7 +525,7 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
}
/* parse and load firmware modules to DSP */
- ret = load_modules(sdev, plat_data->fw);
+ ret = load_modules(sdev, plat_data->fw, plat_data->fw_offset);
if (ret < 0) {
dev_err(sdev->dev, "error: invalid FW modules\n");
goto error;
diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c
index 2233146386cc..ce053ba8f2e8 100644
--- a/sound/soc/sof/nocodec.c
+++ b/sound/soc/sof/nocodec.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
@@ -66,7 +66,6 @@ int sof_nocodec_setup(struct device *dev,
const struct snd_sof_dsp_ops *ops)
{
struct snd_soc_dai_link *links;
- int ret;
/* create dummy BE dai_links */
links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
@@ -74,9 +73,8 @@ int sof_nocodec_setup(struct device *dev,
if (!links)
return -ENOMEM;
- ret = sof_nocodec_bes_setup(dev, ops, links, ops->num_drv,
- &sof_nocodec_card);
- return ret;
+ return sof_nocodec_bes_setup(dev, ops, links, ops->num_drv,
+ &sof_nocodec_card);
}
EXPORT_SYMBOL(sof_nocodec_setup);
diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c
index 7a27c3b719e7..1a394b4c6a2f 100644
--- a/sound/soc/sof/ops.c
+++ b/sound/soc/sof/ops.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h
index a771500ac442..b21632f5511a 100644
--- a/sound/soc/sof/ops.h
+++ b/sound/soc/sof/ops.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index 47cd741f2a8c..22fe9d5e932b 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
@@ -639,6 +639,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
struct snd_sof_dai *dai =
snd_sof_find_dai(component, (char *)rtd->dai_link->name);
+ struct snd_soc_dpcm *dpcm;
/* no topology exists for this BE, try a common configuration */
if (!dai) {
@@ -702,7 +703,16 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
}
break;
case SOF_DAI_INTEL_HDA:
- /* do nothing for HDA dai_link */
+ /*
+ * HDaudio does not follow the default trigger
+ * sequence due to firmware implementation
+ */
+ for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) {
+ struct snd_soc_pcm_runtime *fe = dpcm->fe;
+
+ fe->dai_link->trigger[SNDRV_PCM_STREAM_PLAYBACK] =
+ SND_SOC_DPCM_TRIGGER_POST;
+ }
break;
case SOF_DAI_INTEL_ALH:
/* do nothing for ALH dai_link */
@@ -785,11 +795,11 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
pd->pointer = sof_pcm_pointer;
#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS)
- pd->compr_ops = &sof_compressed_ops;
+ pd->compress_ops = &sof_compressed_ops;
#endif
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
/* override cops when probe support is enabled */
- pd->compr_ops = &sof_probe_compressed_ops;
+ pd->compress_ops = &sof_probe_compressed_ops;
#endif
pd->pcm_construct = sof_pcm_new;
pd->ignore_machine = drv_name;
diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c
index c410822d9920..1f8f7e33979d 100644
--- a/sound/soc/sof/pm.c
+++ b/sound/soc/sof/pm.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/probe.c b/sound/soc/sof/probe.c
index c38169fe00c5..14509f4d3f86 100644
--- a/sound/soc/sof/probe.c
+++ b/sound/soc/sof/probe.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/probe.h b/sound/soc/sof/probe.h
index 45daa5552834..b04b728c7224 100644
--- a/sound/soc/sof/probe.h
+++ b/sound/soc/sof/probe.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c
index 1278aa95effa..c5eaaa978054 100644
--- a/sound/soc/sof/sof-acpi-dev.c
+++ b/sound/soc/sof/sof-acpi-dev.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index fc4ed2a8a914..1c7698f8edd6 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 875a5fc13297..9629994fe463 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c
index 16e49f2ee629..f492c5dfa659 100644
--- a/sound/soc/sof/sof-of-dev.c
+++ b/sound/soc/sof/sof-of-dev.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// Copyright 2019 NXP
//
@@ -14,6 +14,7 @@
extern struct snd_sof_dsp_ops sof_imx8_ops;
extern struct snd_sof_dsp_ops sof_imx8x_ops;
+extern struct snd_sof_dsp_ops sof_imx8m_ops;
/* platform specific devices */
#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8)
@@ -34,6 +35,16 @@ static struct sof_dev_desc sof_of_imx8qm_desc = {
};
#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8M)
+static struct sof_dev_desc sof_of_imx8mp_desc = {
+ .default_fw_path = "imx/sof",
+ .default_tplg_path = "imx/sof-tplg",
+ .default_fw_filename = "sof-imx8m.ri",
+ .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
+ .ops = &sof_imx8m_ops,
+};
+#endif
+
static const struct dev_pm_ops sof_of_pm = {
SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
@@ -114,6 +125,9 @@ static const struct of_device_id sof_of_ids[] = {
{ .compatible = "fsl,imx8qxp-dsp", .data = &sof_of_imx8qxp_desc},
{ .compatible = "fsl,imx8qm-dsp", .data = &sof_of_imx8qm_desc},
#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8M)
+ { .compatible = "fsl,imx8mp-dsp", .data = &sof_of_imx8mp_desc},
+#endif
{ }
};
MODULE_DEVICE_TABLE(of, sof_of_ids);
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
index cec631a1389b..b13697dab7c0 100644
--- a/sound/soc/sof/sof-pci-dev.c
+++ b/sound/soc/sof/sof-pci-dev.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
@@ -435,6 +435,8 @@ static const struct pci_device_id sof_pci_ids[] = {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
{ PCI_DEVICE(0x8086, 0x4b55),
.driver_data = (unsigned long)&ehl_desc},
+ { PCI_DEVICE(0x8086, 0x4b58),
+ .driver_data = (unsigned long)&ehl_desc},
#endif
{ 0, }
};
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index a4b297c842df..a34dbae9f971 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -522,7 +522,7 @@ void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev);
/*
* Platform specific ops.
*/
-extern struct snd_compr_ops sof_compressed_ops;
+extern struct snd_compress_ops sof_compressed_ops;
/*
* DSP Architectures.
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index ab2b69de1d4d..0259537d3740 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
@@ -430,6 +430,7 @@ static const struct sof_process_types sof_process[] = {
{"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR, SOF_COMP_SELECTOR},
{"MUX", SOF_PROCESS_MUX, SOF_COMP_MUX},
{"DEMUX", SOF_PROCESS_DEMUX, SOF_COMP_DEMUX},
+ {"DCBLOCK", SOF_PROCESS_DCBLOCK, SOF_COMP_DCBLOCK},
};
static enum sof_ipc_process_type find_process(const char *name)
@@ -655,6 +656,16 @@ static const struct sof_topology_token ssp_tokens[] = {
};
+/* ALH */
+static const struct sof_topology_token alh_tokens[] = {
+ {SOF_TKN_INTEL_ALH_RATE,
+ SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_alh_params, rate), 0},
+ {SOF_TKN_INTEL_ALH_CH,
+ SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_alh_params, channels), 0},
+};
+
/* DMIC */
static const struct sof_topology_token dmic_tokens[] = {
{SOF_TKN_INTEL_DMIC_DRIVER_VERSION,
@@ -742,6 +753,12 @@ static const struct sof_topology_token dmic_pdm_tokens[] = {
/* HDA */
static const struct sof_topology_token hda_tokens[] = {
+ {SOF_TKN_INTEL_HDA_RATE,
+ SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_hda_params, rate), 0},
+ {SOF_TKN_INTEL_HDA_CH,
+ SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_hda_params, channels), 0},
};
/* Leds */
@@ -752,13 +769,15 @@ static const struct sof_topology_token led_tokens[] = {
get_token_u32, offsetof(struct snd_sof_led_control, direction), 0},
};
-static void sof_parse_uuid_tokens(struct snd_soc_component *scomp,
- void *object,
- const struct sof_topology_token *tokens,
- int count,
- struct snd_soc_tplg_vendor_array *array)
+static int sof_parse_uuid_tokens(struct snd_soc_component *scomp,
+ void *object,
+ const struct sof_topology_token *tokens,
+ int count,
+ struct snd_soc_tplg_vendor_array *array,
+ size_t offset)
{
struct snd_soc_tplg_vendor_uuid_elem *elem;
+ int found = 0;
int i, j;
/* parse element by element */
@@ -776,19 +795,26 @@ static void sof_parse_uuid_tokens(struct snd_soc_component *scomp,
continue;
/* matched - now load token */
- tokens[j].get_token(elem, object, tokens[j].offset,
+ tokens[j].get_token(elem, object,
+ offset + tokens[j].offset,
tokens[j].size);
+
+ found++;
}
}
+
+ return found;
}
-static void sof_parse_string_tokens(struct snd_soc_component *scomp,
- void *object,
- const struct sof_topology_token *tokens,
- int count,
- struct snd_soc_tplg_vendor_array *array)
+static int sof_parse_string_tokens(struct snd_soc_component *scomp,
+ void *object,
+ const struct sof_topology_token *tokens,
+ int count,
+ struct snd_soc_tplg_vendor_array *array,
+ size_t offset)
{
struct snd_soc_tplg_vendor_string_elem *elem;
+ int found = 0;
int i, j;
/* parse element by element */
@@ -806,24 +832,27 @@ static void sof_parse_string_tokens(struct snd_soc_component *scomp,
continue;
/* matched - now load token */
- tokens[j].get_token(elem, object, tokens[j].offset,
+ tokens[j].get_token(elem, object,
+ offset + tokens[j].offset,
tokens[j].size);
+
+ found++;
}
}
+
+ return found;
}
-static void sof_parse_word_tokens(struct snd_soc_component *scomp,
- void *object,
- const struct sof_topology_token *tokens,
- int count,
- struct snd_soc_tplg_vendor_array *array)
+static int sof_parse_word_tokens(struct snd_soc_component *scomp,
+ void *object,
+ const struct sof_topology_token *tokens,
+ int count,
+ struct snd_soc_tplg_vendor_array *array,
+ size_t offset)
{
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_soc_tplg_vendor_value_elem *elem;
- size_t size = sizeof(struct sof_ipc_dai_dmic_pdm_ctrl);
+ int found = 0;
int i, j;
- u32 offset;
- u32 *index = NULL;
/* parse element by element */
for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
@@ -842,58 +871,45 @@ static void sof_parse_word_tokens(struct snd_soc_component *scomp,
if (tokens[j].token != le32_to_cpu(elem->token))
continue;
- /* pdm config array index */
- if (sdev->private)
- index = sdev->private;
-
- /* matched - determine offset */
- switch (tokens[j].token) {
- case SOF_TKN_INTEL_DMIC_PDM_CTRL_ID:
-
- /* inc number of pdm array index */
- if (index)
- (*index)++;
- /* fallthrough */
- case SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable:
- case SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable:
- case SOF_TKN_INTEL_DMIC_PDM_POLARITY_A:
- case SOF_TKN_INTEL_DMIC_PDM_POLARITY_B:
- case SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE:
- case SOF_TKN_INTEL_DMIC_PDM_SKEW:
-
- /* check if array index is valid */
- if (!index || *index == 0) {
- dev_err(scomp->dev,
- "error: invalid array offset\n");
- continue;
- } else {
- /* offset within the pdm config array */
- offset = size * (*index - 1);
- }
- break;
- default:
- offset = 0;
- break;
- }
-
/* load token */
tokens[j].get_token(elem, object,
offset + tokens[j].offset,
tokens[j].size);
+
+ found++;
}
}
+
+ return found;
}
-static int sof_parse_tokens(struct snd_soc_component *scomp,
- void *object,
- const struct sof_topology_token *tokens,
- int count,
- struct snd_soc_tplg_vendor_array *array,
- int priv_size)
-{
+/**
+ * sof_parse_token_sets - Parse multiple sets of tokens
+ * @scomp: pointer to soc component
+ * @object: target ipc struct for parsed values
+ * @tokens: token definition array describing what tokens to parse
+ * @count: number of tokens in definition array
+ * @array: source pointer to consecutive vendor arrays to be parsed
+ * @priv_size: total size of the consecutive source arrays
+ * @sets: number of similar token sets to be parsed, 1 set has count elements
+ * @object_size: offset to next target ipc struct with multiple sets
+ *
+ * This function parses multiple sets of tokens in vendor arrays into
+ * consecutive ipc structs.
+ */
+static int sof_parse_token_sets(struct snd_soc_component *scomp,
+ void *object,
+ const struct sof_topology_token *tokens,
+ int count,
+ struct snd_soc_tplg_vendor_array *array,
+ int priv_size, int sets, size_t object_size)
+{
+ size_t offset = 0;
+ int found = 0;
+ int total = 0;
int asize;
- while (priv_size > 0) {
+ while (priv_size > 0 && total < count * sets) {
asize = le32_to_cpu(array->size);
/* validate asize */
@@ -914,19 +930,19 @@ static int sof_parse_tokens(struct snd_soc_component *scomp,
/* call correct parser depending on type */
switch (le32_to_cpu(array->type)) {
case SND_SOC_TPLG_TUPLE_TYPE_UUID:
- sof_parse_uuid_tokens(scomp, object, tokens, count,
- array);
+ found += sof_parse_uuid_tokens(scomp, object, tokens,
+ count, array, offset);
break;
case SND_SOC_TPLG_TUPLE_TYPE_STRING:
- sof_parse_string_tokens(scomp, object, tokens, count,
- array);
+ found += sof_parse_string_tokens(scomp, object, tokens,
+ count, array, offset);
break;
case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
case SND_SOC_TPLG_TUPLE_TYPE_WORD:
case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
- sof_parse_word_tokens(scomp, object, tokens, count,
- array);
+ found += sof_parse_word_tokens(scomp, object, tokens,
+ count, array, offset);
break;
default:
dev_err(scomp->dev, "error: unknown token type %d\n",
@@ -937,10 +953,35 @@ static int sof_parse_tokens(struct snd_soc_component *scomp,
/* next array */
array = (struct snd_soc_tplg_vendor_array *)((u8 *)array
+ asize);
+
+ /* move to next target struct */
+ if (found >= count) {
+ offset += object_size;
+ total += found;
+ found = 0;
+ }
}
+
return 0;
}
+static int sof_parse_tokens(struct snd_soc_component *scomp,
+ void *object,
+ const struct sof_topology_token *tokens,
+ int count,
+ struct snd_soc_tplg_vendor_array *array,
+ int priv_size)
+{
+ /*
+ * sof_parse_tokens is used when topology contains only a single set of
+ * identical tuples arrays. So additional parameters to
+ * sof_parse_token_sets are sets = 1 (only 1 set) and
+ * object_size = 0 (irrelevant).
+ */
+ return sof_parse_token_sets(scomp, object, tokens, count, array,
+ priv_size, 1, 0);
+}
+
static void sof_dbg_comp_config(struct snd_soc_component *scomp,
struct sof_ipc_comp_config *config)
{
@@ -1259,15 +1300,45 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp,
switch (w->id) {
case snd_soc_dapm_dai_out:
- for_each_rtd_cpu_dais(rtd, i, cpu_dai)
- cpu_dai->capture_widget = w;
+ for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
+ /*
+ * Please create DAI widget in the right order
+ * to ensure BE will connect to the right DAI
+ * widget.
+ */
+ if (!cpu_dai->capture_widget) {
+ cpu_dai->capture_widget = w;
+ break;
+ }
+ }
+ if (i == rtd->num_cpus) {
+ dev_err(scomp->dev, "error: can't find BE for DAI %s\n",
+ w->name);
+
+ return -EINVAL;
+ }
dai->name = rtd->dai_link->name;
dev_dbg(scomp->dev, "tplg: connected widget %s -> DAI link %s\n",
w->name, rtd->dai_link->name);
break;
case snd_soc_dapm_dai_in:
- for_each_rtd_cpu_dais(rtd, i, cpu_dai)
- cpu_dai->playback_widget = w;
+ for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
+ /*
+ * Please create DAI widget in the right order
+ * to ensure BE will connect to the right DAI
+ * widget.
+ */
+ if (!cpu_dai->playback_widget) {
+ cpu_dai->playback_widget = w;
+ break;
+ }
+ }
+ if (i == rtd->num_cpus) {
+ dev_err(scomp->dev, "error: can't find BE for DAI %s\n",
+ w->name);
+
+ return -EINVAL;
+ }
dai->name = rtd->dai_link->name;
dev_dbg(scomp->dev, "tplg: connected widget %s -> DAI link %s\n",
w->name, rtd->dai_link->name);
@@ -2604,7 +2675,11 @@ static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config,
}
}
-/* set config for all DAI's with name matching the link name */
+/*
+ * Send IPC and set the same config for all DAIs with name matching the link
+ * name. Note that the function can only be used for the case that all DAIs
+ * have a common DAI config for now.
+ */
static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size,
struct snd_soc_dai_link *link,
struct sof_ipc_dai_config *config)
@@ -2617,6 +2692,27 @@ static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size,
continue;
if (strcmp(link->name, dai->name) == 0) {
+ struct sof_ipc_reply reply;
+ int ret;
+
+ /*
+ * the same dai config will be applied to all DAIs in
+ * the same dai link. We have to ensure that the ipc
+ * dai config's dai_index match to the component's
+ * dai_index.
+ */
+ config->dai_index = dai->comp_dai.dai_index;
+
+ /* send message to DSP */
+ ret = sof_ipc_tx_message(sdev->ipc,
+ config->hdr.cmd, config, size,
+ &reply, sizeof(reply));
+
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: failed to set DAI config for %s index %d\n",
+ dai->name, config->dai_index);
+ return ret;
+ }
dai->dai_config = kmemdup(config, size, GFP_KERNEL);
if (!dai->dai_config)
return -ENOMEM;
@@ -2649,7 +2745,6 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index,
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_soc_tplg_private *private = &cfg->priv;
- struct sof_ipc_reply reply;
u32 size = sizeof(*config);
int ret;
@@ -2698,17 +2793,6 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index,
return -EINVAL;
}
- /* send message to DSP */
- ret = sof_ipc_tx_message(sdev->ipc,
- config->hdr.cmd, config, size, &reply,
- sizeof(reply));
-
- if (ret < 0) {
- dev_err(scomp->dev, "error: failed to set DAI config for SSP%d\n",
- config->dai_index);
- return ret;
- }
-
/* set config for all DAI's with name matching the link name */
ret = sof_set_dai_config(sdev, size, link, config);
if (ret < 0)
@@ -2726,7 +2810,6 @@ static int sof_link_sai_load(struct snd_soc_component *scomp, int index,
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_soc_tplg_private *private = &cfg->priv;
- struct sof_ipc_reply reply;
u32 size = sizeof(*config);
int ret;
@@ -2766,17 +2849,6 @@ static int sof_link_sai_load(struct snd_soc_component *scomp, int index,
return -EINVAL;
}
- /* send message to DSP */
- ret = sof_ipc_tx_message(sdev->ipc,
- config->hdr.cmd, config, size, &reply,
- sizeof(reply));
-
- if (ret < 0) {
- dev_err(scomp->dev, "error: failed to set DAI config for SAI%d\n",
- config->dai_index);
- return ret;
- }
-
/* set config for all DAI's with name matching the link name */
ret = sof_set_dai_config(sdev, size, link, config);
if (ret < 0)
@@ -2794,7 +2866,6 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index,
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_soc_tplg_private *private = &cfg->priv;
- struct sof_ipc_reply reply;
u32 size = sizeof(*config);
int ret;
@@ -2835,16 +2906,6 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index,
return -EINVAL;
}
- /* send message to DSP */
- ret = sof_ipc_tx_message(sdev->ipc,
- config->hdr.cmd, config, size, &reply,
- sizeof(reply));
- if (ret < 0) {
- dev_err(scomp->dev, "error: failed to set DAI config for ESAI%d\n",
- config->dai_index);
- return ret;
- }
-
/* set config for all DAI's with name matching the link name */
ret = sof_set_dai_config(sdev, size, link, config);
if (ret < 0)
@@ -2862,18 +2923,12 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_soc_tplg_private *private = &cfg->priv;
- struct sof_ipc_dai_config *ipc_config;
- struct sof_ipc_reply reply;
struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
struct sof_ipc_fw_version *v = &ready->version;
- u32 size;
+ size_t size = sizeof(*config);
int ret, j;
- /*
- * config is only used for the common params in dmic_params structure
- * that does not include the PDM controller config array
- * Set the common params to 0.
- */
+ /* Ensure the entire DMIC config struct is zeros */
memset(&config->dmic, 0, sizeof(struct sof_ipc_dai_dmic_params));
/* get DMIC tokens */
@@ -2887,34 +2942,20 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
}
/*
- * allocate memory for dmic dai config accounting for the
- * variable number of active pdm controllers
- * This will be the ipc payload for setting dai config
- */
- size = sizeof(*config) + sizeof(struct sof_ipc_dai_dmic_pdm_ctrl) *
- config->dmic.num_pdm_active;
-
- ipc_config = kzalloc(size, GFP_KERNEL);
- if (!ipc_config)
- return -ENOMEM;
-
- /* copy the common dai config and dmic params */
- memcpy(ipc_config, config, sizeof(*config));
-
- /*
* alloc memory for private member
* Used to track the pdm config array index currently being parsed
*/
sdev->private = kzalloc(sizeof(u32), GFP_KERNEL);
- if (!sdev->private) {
- kfree(ipc_config);
+ if (!sdev->private)
return -ENOMEM;
- }
/* get DMIC PDM tokens */
- ret = sof_parse_tokens(scomp, &ipc_config->dmic.pdm[0], dmic_pdm_tokens,
+ ret = sof_parse_token_sets(scomp, &config->dmic.pdm[0], dmic_pdm_tokens,
ARRAY_SIZE(dmic_pdm_tokens), private->array,
- le32_to_cpu(private->size));
+ le32_to_cpu(private->size),
+ config->dmic.num_pdm_active,
+ sizeof(struct sof_ipc_dai_dmic_pdm_ctrl));
+
if (ret != 0) {
dev_err(scomp->dev, "error: parse dmic pdm tokens failed %d\n",
le32_to_cpu(private->size));
@@ -2922,125 +2963,53 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
}
/* set IPC header size */
- ipc_config->hdr.size = size;
+ config->hdr.size = size;
/* debug messages */
dev_dbg(scomp->dev, "tplg: config DMIC%d driver version %d\n",
- ipc_config->dai_index, ipc_config->dmic.driver_ipc_version);
+ config->dai_index, config->dmic.driver_ipc_version);
dev_dbg(scomp->dev, "pdmclk_min %d pdm_clkmax %d duty_min %hd\n",
- ipc_config->dmic.pdmclk_min, ipc_config->dmic.pdmclk_max,
- ipc_config->dmic.duty_min);
+ config->dmic.pdmclk_min, config->dmic.pdmclk_max,
+ config->dmic.duty_min);
dev_dbg(scomp->dev, "duty_max %hd fifo_fs %d num_pdms active %d\n",
- ipc_config->dmic.duty_max, ipc_config->dmic.fifo_fs,
- ipc_config->dmic.num_pdm_active);
- dev_dbg(scomp->dev, "fifo word length %hd\n",
- ipc_config->dmic.fifo_bits);
+ config->dmic.duty_max, config->dmic.fifo_fs,
+ config->dmic.num_pdm_active);
+ dev_dbg(scomp->dev, "fifo word length %hd\n", config->dmic.fifo_bits);
- for (j = 0; j < ipc_config->dmic.num_pdm_active; j++) {
+ for (j = 0; j < config->dmic.num_pdm_active; j++) {
dev_dbg(scomp->dev, "pdm %hd mic a %hd mic b %hd\n",
- ipc_config->dmic.pdm[j].id,
- ipc_config->dmic.pdm[j].enable_mic_a,
- ipc_config->dmic.pdm[j].enable_mic_b);
+ config->dmic.pdm[j].id,
+ config->dmic.pdm[j].enable_mic_a,
+ config->dmic.pdm[j].enable_mic_b);
dev_dbg(scomp->dev, "pdm %hd polarity a %hd polarity b %hd\n",
- ipc_config->dmic.pdm[j].id,
- ipc_config->dmic.pdm[j].polarity_mic_a,
- ipc_config->dmic.pdm[j].polarity_mic_b);
+ config->dmic.pdm[j].id,
+ config->dmic.pdm[j].polarity_mic_a,
+ config->dmic.pdm[j].polarity_mic_b);
dev_dbg(scomp->dev, "pdm %hd clk_edge %hd skew %hd\n",
- ipc_config->dmic.pdm[j].id,
- ipc_config->dmic.pdm[j].clk_edge,
- ipc_config->dmic.pdm[j].skew);
+ config->dmic.pdm[j].id,
+ config->dmic.pdm[j].clk_edge,
+ config->dmic.pdm[j].skew);
}
- if (SOF_ABI_VER(v->major, v->minor, v->micro) < SOF_ABI_VER(3, 0, 1)) {
- /* this takes care of backwards compatible handling of fifo_bits_b */
- ipc_config->dmic.reserved_2 = ipc_config->dmic.fifo_bits;
- }
-
- /* send message to DSP */
- ret = sof_ipc_tx_message(sdev->ipc,
- ipc_config->hdr.cmd, ipc_config, size, &reply,
- sizeof(reply));
-
- if (ret < 0) {
- dev_err(scomp->dev,
- "error: failed to set DAI config for DMIC%d\n",
- config->dai_index);
- goto err;
- }
+ /*
+ * this takes care of backwards compatible handling of fifo_bits_b.
+ * It is deprecated since firmware ABI version 3.0.1.
+ */
+ if (SOF_ABI_VER(v->major, v->minor, v->micro) < SOF_ABI_VER(3, 0, 1))
+ config->dmic.fifo_bits_b = config->dmic.fifo_bits;
/* set config for all DAI's with name matching the link name */
- ret = sof_set_dai_config(sdev, size, link, ipc_config);
+ ret = sof_set_dai_config(sdev, size, link, config);
if (ret < 0)
dev_err(scomp->dev, "error: failed to save DAI config for DMIC%d\n",
config->dai_index);
err:
kfree(sdev->private);
- kfree(ipc_config);
return ret;
}
-/*
- * for hda link, playback and capture are supported by different dai
- * in FW. Here get the dai_index, set dma channel of each dai
- * and send config to FW. In FW, each dai sets config by dai_index
- */
-static int sof_link_hda_process(struct snd_sof_dev *sdev,
- struct snd_soc_dai_link *link,
- struct sof_ipc_dai_config *config)
-{
- struct sof_ipc_reply reply;
- u32 size = sizeof(*config);
- struct snd_sof_dai *sof_dai;
- int found = 0;
- int ret;
-
- list_for_each_entry(sof_dai, &sdev->dai_list, list) {
- if (!sof_dai->name)
- continue;
-
- if (strcmp(link->name, sof_dai->name) == 0) {
- config->dai_index = sof_dai->comp_dai.dai_index;
- found = 1;
-
- config->hda.link_dma_ch = DMA_CHAN_INVALID;
-
- /* save config in dai component */
- sof_dai->dai_config = kmemdup(config, size, GFP_KERNEL);
- if (!sof_dai->dai_config)
- return -ENOMEM;
-
- sof_dai->cpu_dai_name = link->cpus->dai_name;
-
- /* send message to DSP */
- ret = sof_ipc_tx_message(sdev->ipc,
- config->hdr.cmd, config, size,
- &reply, sizeof(reply));
-
- if (ret < 0) {
- dev_err(sdev->dev, "error: failed to set DAI config for direction:%d of HDA dai %d\n",
- sof_dai->comp_dai.direction,
- config->dai_index);
-
- return ret;
- }
- }
- }
-
- /*
- * machine driver may define a dai link with playback and capture
- * dai enabled, but the dai link in topology would support both, one
- * or none of them. Here print a warning message to notify user
- */
- if (!found) {
- dev_warn(sdev->dev, "warning: failed to find dai for dai link %s",
- link->name);
- }
-
- return 0;
-}
-
static int sof_link_hda_load(struct snd_soc_component *scomp, int index,
struct snd_soc_dai_link *link,
struct snd_soc_tplg_link_config *cfg,
@@ -3058,7 +3027,7 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index,
config->hdr.size = size;
/* get any bespoke DAI tokens */
- ret = sof_parse_tokens(scomp, config, hda_tokens,
+ ret = sof_parse_tokens(scomp, &config->hda, hda_tokens,
ARRAY_SIZE(hda_tokens), private->array,
le32_to_cpu(private->size));
if (ret != 0) {
@@ -3067,6 +3036,9 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index,
return ret;
}
+ dev_dbg(scomp->dev, "HDA config rate %d channels %d\n",
+ config->hda.rate, config->hda.channels);
+
dai = snd_soc_find_dai(link->cpus);
if (!dai) {
dev_err(scomp->dev, "error: failed to find dai %s in %s",
@@ -3074,7 +3046,9 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index,
return -EINVAL;
}
- ret = sof_link_hda_process(sdev, link, config);
+ config->hda.link_dma_ch = DMA_CHAN_INVALID;
+
+ ret = sof_set_dai_config(sdev, size, link, config);
if (ret < 0)
dev_err(scomp->dev, "error: failed to process hda dai link %s",
link->name);
@@ -3089,24 +3063,22 @@ static int sof_link_alh_load(struct snd_soc_component *scomp, int index,
struct sof_ipc_dai_config *config)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- struct sof_ipc_reply reply;
+ struct snd_soc_tplg_private *private = &cfg->priv;
u32 size = sizeof(*config);
int ret;
- /* init IPC */
- config->hdr.size = size;
-
- /* send message to DSP */
- ret = sof_ipc_tx_message(sdev->ipc,
- config->hdr.cmd, config, size, &reply,
- sizeof(reply));
-
- if (ret < 0) {
- dev_err(scomp->dev, "error: failed to set DAI config for ALH %d\n",
- config->dai_index);
+ ret = sof_parse_tokens(scomp, &config->alh, alh_tokens,
+ ARRAY_SIZE(alh_tokens), private->array,
+ le32_to_cpu(private->size));
+ if (ret != 0) {
+ dev_err(scomp->dev, "error: parse alh tokens failed %d\n",
+ le32_to_cpu(private->size));
return ret;
}
+ /* init IPC */
+ config->hdr.size = size;
+
/* set config for all DAI's with name matching the link name */
ret = sof_set_dai_config(sdev, size, link, config);
if (ret < 0)
@@ -3141,9 +3113,17 @@ static int sof_link_load(struct snd_soc_component *scomp, int index,
if (!link->no_pcm) {
link->nonatomic = true;
- /* set trigger order */
- link->trigger[0] = SND_SOC_DPCM_TRIGGER_POST;
- link->trigger[1] = SND_SOC_DPCM_TRIGGER_POST;
+ /*
+ * set default trigger order for all links. Exceptions to
+ * the rule will be handled in sof_pcm_dai_link_fixup()
+ * For playback, the sequence is the following: start FE,
+ * start BE, stop BE, stop FE; for Capture the sequence is
+ * inverted start BE, start FE, stop FE, stop BE
+ */
+ link->trigger[SNDRV_PCM_STREAM_PLAYBACK] =
+ SND_SOC_DPCM_TRIGGER_PRE;
+ link->trigger[SNDRV_PCM_STREAM_CAPTURE] =
+ SND_SOC_DPCM_TRIGGER_POST;
/* nothing more to do for FE dai links */
return 0;
diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c
index d815090252f8..69889241a092 100644
--- a/sound/soc/sof/trace.c
+++ b/sound/soc/sof/trace.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c
index 9831eb57df6c..5539d3afbe8f 100644
--- a/sound/soc/sof/utils.c
+++ b/sound/soc/sof/utils.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sof/xtensa/Makefile b/sound/soc/sof/xtensa/Makefile
index cc89c7472a38..b8376ea04bcf 100644
--- a/sound/soc/sof/xtensa/Makefile
+++ b/sound/soc/sof/xtensa/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
snd-sof-xtensa-dsp-objs := core.o
diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c
index ea08651f0bb3..bbb9a2282ed9 100644
--- a/sound/soc/sof/xtensa/core.c
+++ b/sound/soc/sof/xtensa/core.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
diff --git a/sound/soc/sprd/sprd-pcm-compress.c b/sound/soc/sprd/sprd-pcm-compress.c
index 74d48340cade..749dcb7b993b 100644
--- a/sound/soc/sprd/sprd-pcm-compress.c
+++ b/sound/soc/sprd/sprd-pcm-compress.c
@@ -96,7 +96,8 @@ struct sprd_compr_stream {
int stage1_pointer;
};
-static int sprd_platform_compr_trigger(struct snd_compr_stream *cstream,
+static int sprd_platform_compr_trigger(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
int cmd);
static void sprd_platform_compr_drain_notify(void *arg)
@@ -125,15 +126,14 @@ static void sprd_platform_compr_dma_complete(void *data)
snd_compr_fragment_elapsed(cstream);
}
-static int sprd_platform_compr_dma_config(struct snd_compr_stream *cstream,
+static int sprd_platform_compr_dma_config(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
struct snd_compr_params *params,
int channel)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct sprd_compr_stream *stream = runtime->private_data;
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_component *component =
- snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct device *dev = component->dev;
struct sprd_compr_data *data = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
struct sprd_pcm_dma_params *dma_params = data->dma_params;
@@ -261,14 +261,12 @@ sg_err:
return ret;
}
-static int sprd_platform_compr_set_params(struct snd_compr_stream *cstream,
+static int sprd_platform_compr_set_params(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
struct snd_compr_params *params)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct sprd_compr_stream *stream = runtime->private_data;
- struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_component *component =
- snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct device *dev = component->dev;
struct sprd_compr_params compr_params = { };
int ret;
@@ -279,13 +277,13 @@ static int sprd_platform_compr_set_params(struct snd_compr_stream *cstream,
* means once the source channel's transaction is done, it will trigger
* the destination channel's transaction automatically.
*/
- ret = sprd_platform_compr_dma_config(cstream, params, 1);
+ ret = sprd_platform_compr_dma_config(component, cstream, params, 1);
if (ret) {
dev_err(dev, "failed to config stage 1 DMA: %d\n", ret);
return ret;
}
- ret = sprd_platform_compr_dma_config(cstream, params, 0);
+ ret = sprd_platform_compr_dma_config(component, cstream, params, 0);
if (ret) {
dev_err(dev, "failed to config stage 0 DMA: %d\n", ret);
goto config_err;
@@ -314,12 +312,11 @@ config_err:
return ret;
}
-static int sprd_platform_compr_open(struct snd_compr_stream *cstream)
+static int sprd_platform_compr_open(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_component *component =
- snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct device *dev = component->dev;
struct sprd_compr_data *data = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
struct sprd_compr_stream *stream;
@@ -392,13 +389,11 @@ err_iram:
return ret;
}
-static int sprd_platform_compr_free(struct snd_compr_stream *cstream)
+static int sprd_platform_compr_free(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct sprd_compr_stream *stream = runtime->private_data;
- struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_component *component =
- snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct device *dev = component->dev;
int stream_id = cstream->direction, i;
@@ -420,14 +415,12 @@ static int sprd_platform_compr_free(struct snd_compr_stream *cstream)
return 0;
}
-static int sprd_platform_compr_trigger(struct snd_compr_stream *cstream,
+static int sprd_platform_compr_trigger(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
int cmd)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct sprd_compr_stream *stream = runtime->private_data;
- struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_component *component =
- snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct device *dev = component->dev;
int channels = stream->num_channels, ret = 0, i;
int stream_id = cstream->direction;
@@ -518,7 +511,8 @@ static int sprd_platform_compr_trigger(struct snd_compr_stream *cstream,
return ret;
}
-static int sprd_platform_compr_pointer(struct snd_compr_stream *cstream,
+static int sprd_platform_compr_pointer(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
struct snd_compr_tstamp *tstamp)
{
struct snd_compr_runtime *runtime = cstream->runtime;
@@ -532,7 +526,8 @@ static int sprd_platform_compr_pointer(struct snd_compr_stream *cstream,
return 0;
}
-static int sprd_platform_compr_copy(struct snd_compr_stream *cstream,
+static int sprd_platform_compr_copy(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
char __user *buf, size_t count)
{
struct snd_compr_runtime *runtime = cstream->runtime;
@@ -609,7 +604,8 @@ copy_done:
return count;
}
-static int sprd_platform_compr_get_caps(struct snd_compr_stream *cstream,
+static int sprd_platform_compr_get_caps(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
struct snd_compr_caps *caps)
{
caps->direction = cstream->direction;
@@ -625,7 +621,8 @@ static int sprd_platform_compr_get_caps(struct snd_compr_stream *cstream,
}
static int
-sprd_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
+sprd_platform_compr_get_codec_caps(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
struct snd_compr_codec_caps *codec)
{
switch (codec->codec) {
@@ -658,7 +655,7 @@ sprd_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
return 0;
}
-const struct snd_compr_ops sprd_platform_compr_ops = {
+const struct snd_compress_ops sprd_platform_compress_ops = {
.open = sprd_platform_compr_open,
.free = sprd_platform_compr_free,
.set_params = sprd_platform_compr_set_params,
diff --git a/sound/soc/sprd/sprd-pcm-dma.c b/sound/soc/sprd/sprd-pcm-dma.c
index d12d3cad8cbd..5074123f8855 100644
--- a/sound/soc/sprd/sprd-pcm-dma.c
+++ b/sound/soc/sprd/sprd-pcm-dma.c
@@ -515,7 +515,7 @@ static const struct snd_soc_component_driver sprd_soc_component = {
.mmap = sprd_pcm_mmap,
.pcm_construct = sprd_pcm_new,
.pcm_destruct = sprd_pcm_free,
- .compr_ops = &sprd_platform_compr_ops,
+ .compress_ops = &sprd_platform_compress_ops,
};
static int sprd_soc_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/sprd/sprd-pcm-dma.h b/sound/soc/sprd/sprd-pcm-dma.h
index 08e9fdba82f1..be5e385f5e42 100644
--- a/sound/soc/sprd/sprd-pcm-dma.h
+++ b/sound/soc/sprd/sprd-pcm-dma.h
@@ -6,7 +6,7 @@
#define DRV_NAME "sprd_pcm_dma"
#define SPRD_PCM_CHANNEL_MAX 2
-extern const struct snd_compr_ops sprd_platform_compr_ops;
+extern const struct snd_compress_ops sprd_platform_compress_ops;
struct sprd_pcm_dma_params {
dma_addr_t dev_phys[SPRD_PCM_CHANNEL_MAX];
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 6525b93cb75c..d3ead0213cef 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -177,6 +177,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_component *component = codec_dai->component;
struct snd_soc_card *card = rtd->card;
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+ int shrt = 0;
if (gpio_is_valid(machine->gpio_hp_det)) {
tegra_wm8903_hp_jack_gpio.gpio = machine->gpio_hp_det;
@@ -189,12 +190,15 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
&tegra_wm8903_hp_jack_gpio);
}
+ if (of_property_read_bool(card->dev->of_node, "nvidia,headset"))
+ shrt = SND_JACK_MICROPHONE;
+
snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE,
&tegra_wm8903_mic_jack,
tegra_wm8903_mic_jack_pins,
ARRAY_SIZE(tegra_wm8903_mic_jack_pins));
wm8903_mic_detect(component, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE,
- 0);
+ shrt);
snd_soc_dapm_force_enable_pin(&card->dapm, "MICBIAS");
@@ -347,9 +351,9 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = snd_soc_register_card(card);
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ dev_err(&pdev->dev, "devm_snd_soc_register_card failed (%d)\n",
ret);
return ret;
}
@@ -357,15 +361,6 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
return 0;
}
-static int tegra_wm8903_driver_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
-
- snd_soc_unregister_card(card);
-
- return 0;
-}
-
static const struct of_device_id tegra_wm8903_of_match[] = {
{ .compatible = "nvidia,tegra-audio-wm8903", },
{},
@@ -378,7 +373,6 @@ static struct platform_driver tegra_wm8903_driver = {
.of_match_table = tegra_wm8903_of_match,
},
.probe = tegra_wm8903_driver_probe,
- .remove = tegra_wm8903_driver_remove,
};
module_platform_driver(tegra_wm8903_driver);
diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c
index 3d41ca2238d4..6c83b9888467 100644
--- a/sound/soc/ti/omap-mcbsp.c
+++ b/sound/soc/ti/omap-mcbsp.c
@@ -686,7 +686,7 @@ static int omap_mcbsp_init(struct platform_device *pdev)
mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp,
SNDRV_PCM_STREAM_CAPTURE);
- mcbsp->fclk = clk_get(&pdev->dev, "fck");
+ mcbsp->fclk = devm_clk_get(&pdev->dev, "fck");
if (IS_ERR(mcbsp->fclk)) {
ret = PTR_ERR(mcbsp->fclk);
dev_err(mcbsp->dev, "unable to get fck: %d\n", ret);
@@ -711,7 +711,7 @@ static int omap_mcbsp_init(struct platform_device *pdev)
if (ret) {
dev_err(mcbsp->dev,
"Unable to create additional controls\n");
- goto err_thres;
+ return ret;
}
}
@@ -724,8 +724,6 @@ static int omap_mcbsp_init(struct platform_device *pdev)
err_st:
if (mcbsp->pdata->buffer_size)
sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-err_thres:
- clk_put(mcbsp->fclk);
return ret;
}
@@ -1185,7 +1183,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
default:
return -EINVAL;
}
- if (inv_fs == true)
+ if (inv_fs)
regs->pcr0 ^= FSXP | FSRP;
return 0;
@@ -1442,8 +1440,6 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
omap_mcbsp_st_cleanup(pdev);
- clk_put(mcbsp->fclk);
-
return 0;
}
diff --git a/sound/soc/uniphier/aio-compress.c b/sound/soc/uniphier/aio-compress.c
index 232d3cc5bce0..0f76bc601ca9 100644
--- a/sound/soc/uniphier/aio-compress.c
+++ b/sound/soc/uniphier/aio-compress.c
@@ -16,8 +16,10 @@
#include "aio.h"
-static int uniphier_aio_compr_prepare(struct snd_compr_stream *cstream);
-static int uniphier_aio_compr_hw_free(struct snd_compr_stream *cstream);
+static int uniphier_aio_compr_prepare(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream);
+static int uniphier_aio_compr_hw_free(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream);
static int uniphier_aio_comprdma_new(struct snd_soc_pcm_runtime *rtd)
{
@@ -70,7 +72,8 @@ static int uniphier_aio_comprdma_free(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static int uniphier_aio_compr_open(struct snd_compr_stream *cstream)
+static int uniphier_aio_compr_open(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
@@ -95,14 +98,15 @@ static int uniphier_aio_compr_open(struct snd_compr_stream *cstream)
return 0;
}
-static int uniphier_aio_compr_free(struct snd_compr_stream *cstream)
+static int uniphier_aio_compr_free(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
int ret;
- ret = uniphier_aio_compr_hw_free(cstream);
+ ret = uniphier_aio_compr_hw_free(component, cstream);
if (ret)
return ret;
ret = uniphier_aio_comprdma_free(rtd);
@@ -114,7 +118,8 @@ static int uniphier_aio_compr_free(struct snd_compr_stream *cstream)
return 0;
}
-static int uniphier_aio_compr_get_params(struct snd_compr_stream *cstream,
+static int uniphier_aio_compr_get_params(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
struct snd_codec *params)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -126,7 +131,8 @@ static int uniphier_aio_compr_get_params(struct snd_compr_stream *cstream,
return 0;
}
-static int uniphier_aio_compr_set_params(struct snd_compr_stream *cstream,
+static int uniphier_aio_compr_set_params(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
struct snd_compr_params *params)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -155,14 +161,15 @@ static int uniphier_aio_compr_set_params(struct snd_compr_stream *cstream,
aio_port_reset(sub);
aio_src_reset(sub);
- ret = uniphier_aio_compr_prepare(cstream);
+ ret = uniphier_aio_compr_prepare(component, cstream);
if (ret)
return ret;
return 0;
}
-static int uniphier_aio_compr_hw_free(struct snd_compr_stream *cstream)
+static int uniphier_aio_compr_hw_free(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
@@ -173,7 +180,8 @@ static int uniphier_aio_compr_hw_free(struct snd_compr_stream *cstream)
return 0;
}
-static int uniphier_aio_compr_prepare(struct snd_compr_stream *cstream)
+static int uniphier_aio_compr_prepare(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_compr_runtime *runtime = cstream->runtime;
@@ -210,7 +218,8 @@ static int uniphier_aio_compr_prepare(struct snd_compr_stream *cstream)
return 0;
}
-static int uniphier_aio_compr_trigger(struct snd_compr_stream *cstream,
+static int uniphier_aio_compr_trigger(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
int cmd)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -243,7 +252,8 @@ static int uniphier_aio_compr_trigger(struct snd_compr_stream *cstream,
return ret;
}
-static int uniphier_aio_compr_pointer(struct snd_compr_stream *cstream,
+static int uniphier_aio_compr_pointer(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
struct snd_compr_tstamp *tstamp)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -316,7 +326,8 @@ static int aio_compr_send_to_hw(struct uniphier_aio_sub *sub,
return 0;
}
-static int uniphier_aio_compr_copy(struct snd_compr_stream *cstream,
+static int uniphier_aio_compr_copy(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
char __user *buf, size_t count)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -375,7 +386,8 @@ static int uniphier_aio_compr_copy(struct snd_compr_stream *cstream,
return cnt;
}
-static int uniphier_aio_compr_get_caps(struct snd_compr_stream *cstream,
+static int uniphier_aio_compr_get_caps(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
struct snd_compr_caps *caps)
{
caps->num_codecs = 1;
@@ -401,7 +413,8 @@ static const struct snd_compr_codec_caps caps_iec = {
.descriptor[0].formats = 0,
};
-static int uniphier_aio_compr_get_codec_caps(struct snd_compr_stream *stream,
+static int uniphier_aio_compr_get_codec_caps(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
struct snd_compr_codec_caps *codec)
{
if (codec->codec == SND_AUDIOCODEC_IEC61937)
@@ -412,7 +425,7 @@ static int uniphier_aio_compr_get_codec_caps(struct snd_compr_stream *stream,
return 0;
}
-const struct snd_compr_ops uniphier_aio_compr_ops = {
+const struct snd_compress_ops uniphier_aio_compress_ops = {
.open = uniphier_aio_compr_open,
.free = uniphier_aio_compr_free,
.get_params = uniphier_aio_compr_get_params,
diff --git a/sound/soc/uniphier/aio-dma.c b/sound/soc/uniphier/aio-dma.c
index 4bbcb007df41..d6bcd476df12 100644
--- a/sound/soc/uniphier/aio-dma.c
+++ b/sound/soc/uniphier/aio-dma.c
@@ -227,7 +227,7 @@ static const struct snd_soc_component_driver uniphier_soc_platform = {
.pointer = uniphier_aiodma_pointer,
.mmap = uniphier_aiodma_mmap,
.pcm_construct = uniphier_aiodma_new,
- .compr_ops = &uniphier_aio_compr_ops,
+ .compress_ops = &uniphier_aio_compress_ops,
};
static const struct regmap_config aiodma_regmap_config = {
diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h
index 694ac030950e..0b03571aa9f0 100644
--- a/sound/soc/uniphier/aio.h
+++ b/sound/soc/uniphier/aio.h
@@ -304,7 +304,7 @@ static inline struct uniphier_aio *uniphier_priv(struct snd_soc_dai *dai)
}
int uniphier_aiodma_soc_register_platform(struct platform_device *pdev);
-extern const struct snd_compr_ops uniphier_aio_compr_ops;
+extern const struct snd_compress_ops uniphier_aio_compress_ops;
int uniphier_aio_dai_probe(struct snd_soc_dai *dai);
int uniphier_aio_dai_remove(struct snd_soc_dai *dai);
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
index 2873e8e6f02b..cdae1190b930 100644
--- a/sound/soc/ux500/mop500.c
+++ b/sound/soc/ux500/mop500.c
@@ -63,10 +63,11 @@ static void mop500_of_node_put(void)
{
int i;
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < 2; i++)
of_node_put(mop500_dai_links[i].cpus->of_node);
- of_node_put(mop500_dai_links[i].codecs->of_node);
- }
+
+ /* Both links use the same codec, which is refcounted only once */
+ of_node_put(mop500_dai_links[0].codecs->of_node);
}
static int mop500_of_probe(struct platform_device *pdev,
@@ -81,7 +82,9 @@ static int mop500_of_probe(struct platform_device *pdev,
if (!(msp_np[0] && msp_np[1] && codec_np)) {
dev_err(&pdev->dev, "Phandle missing or invalid\n");
- mop500_of_node_put();
+ for (i = 0; i < 2; i++)
+ of_node_put(msp_np[i]);
+ of_node_put(codec_np);
return -EINVAL;
}